OSDN Git Service

In libobjc/:
[pf3gnuchains/gcc-fork.git] / libobjc / thr.c
1 /* GNU Objective C Runtime Thread Interface
2    Copyright (C) 1996, 1997, 2009, 2010 Free Software Foundation, Inc.
3    Contributed by Galen C. Hunt (gchunt@cs.rochester.edu)
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it under the
8 terms of the GNU General Public License as published by the Free Software
9 Foundation; either version 3, or (at your option) any later version.
10
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
14 details.
15
16 Under Section 7 of GPL version 3, you are granted additional
17 permissions described in the GCC Runtime Library Exception, version
18 3.1, as published by the Free Software Foundation.
19
20 You should have received a copy of the GNU General Public License and
21 a copy of the GCC Runtime Library Exception along with this program;
22 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23 <http://www.gnu.org/licenses/>.  */
24
25 #include "objc-private/common.h"
26 #include "objc-private/error.h"
27 #define _LIBOBJC
28 /* The line below is needed for declarations of functions such as
29    pthread_mutexattr_settype, without which gthr-posix.h may fail to
30    compile within libobjc.  Unfortunately, this breaks compilation on
31    Tru64 UNIX V4.0F, so disable it there.  */
32 #ifndef __osf__
33 #define _XOPEN_SOURCE 500
34 #endif
35 #include "config.h"
36 #include "tconfig.h"
37 #include "coretypes.h"
38 #include "tm.h"
39 #include "defaults.h"
40 #include "objc/thr.h"
41 #include "objc/objc.h"
42 #include "objc/objc-api.h"
43 #include "objc-private/runtime.h"
44 #include <gthr.h>
45
46 #include <stdlib.h>
47
48 /* Global exit status. */
49 int __objc_thread_exit_status = 0;
50
51 /* Flag which lets us know if we ever became multi threaded */
52 int __objc_is_multi_threaded = 0;
53
54 /* The hook function called when the runtime becomes multi threaded */
55 objc_thread_callback _objc_became_multi_threaded = NULL;
56
57 /*
58   Use this to set the hook function that will be called when the 
59   runtime initially becomes multi threaded.
60   The hook function is only called once, meaning only when the 
61   2nd thread is spawned, not for each and every thread.
62
63   It returns the previous hook function or NULL if there is none.
64
65   A program outside of the runtime could set this to some function so
66   it can be informed; for example, the GNUstep Base Library sets it 
67   so it can implement the NSBecomingMultiThreaded notification.
68   */
69 objc_thread_callback objc_set_thread_callback (objc_thread_callback func)
70 {
71   objc_thread_callback temp = _objc_became_multi_threaded;
72   _objc_became_multi_threaded = func;
73   return temp;
74 }
75
76 /*
77   Private functions
78
79   These functions are utilized by the frontend, but they are not
80   considered part of the public interface.
81   */
82
83 /* Initialize the threads subsystem. */
84 int
85 __objc_init_thread_system(void)
86 {
87   return __gthread_objc_init_thread_system ();
88 }
89
90 /*
91   First function called in a thread, starts everything else.
92
93   This function is passed to the backend by objc_thread_detach
94   as the starting function for a new thread.
95  */
96 struct __objc_thread_start_state
97 {
98   SEL selector;
99   id object;
100   id argument;
101 };
102
103 static void __attribute__((noreturn))
104 __objc_thread_detach_function (struct __objc_thread_start_state *istate) 
105 {
106   /* Valid state? */
107   if (istate) {
108     id (*imp) (id, SEL, id);
109     SEL selector = istate->selector;
110     id object   = istate->object;
111     id argument = istate->argument;
112
113     /* Don't need anymore so free it */
114     objc_free (istate);
115
116     /* Clear out the thread local storage */
117     objc_thread_set_data (NULL);
118
119     /* Check to see if we just became multi threaded */
120     if (! __objc_is_multi_threaded)
121       {
122         __objc_is_multi_threaded = 1;
123
124         /* Call the hook function */
125         if (_objc_became_multi_threaded != NULL)
126           (*_objc_became_multi_threaded) ();
127       }
128
129     /* Call the method */
130     if ((imp = (id (*) (id, SEL, id))objc_msg_lookup (object, selector)))
131         (*imp) (object, selector, argument);
132     else
133       {
134         /* FIXME: Should we abort here ? */
135         _objc_abort ("objc_thread_detach called with bad selector.\n");
136       }
137   }
138   else
139     {
140       /* FIXME: Should we abort here ? */
141       _objc_abort ("objc_thread_detach called with NULL state.\n");
142     }
143
144   /* Exit the thread */
145   objc_thread_exit ();
146   
147   /* Make sure compiler detects no return.  */
148   __builtin_trap ();
149 }
150
151 /*
152   Frontend functions
153
154   These functions constitute the public interface to the Objective-C thread
155   and mutex functionality.
156   */
157
158 /* Frontend thread functions */
159
160 /*
161   Detach a new thread of execution and return its id.  Returns NULL if fails.
162   Thread is started by sending message with selector to object.  Message
163   takes a single argument.
164   */
165 objc_thread_t
166 objc_thread_detach (SEL selector, id object, id argument)
167 {
168   struct __objc_thread_start_state *istate;
169   objc_thread_t        thread_id = NULL;
170
171   /* Allocate the state structure */
172   if (! (istate = (struct __objc_thread_start_state *)
173          objc_malloc (sizeof (*istate))))
174     return NULL;
175
176   /* Initialize the state structure */
177   istate->selector = selector;
178   istate->object = object;
179   istate->argument = argument;
180
181   /* lock access */
182   objc_mutex_lock (__objc_runtime_mutex);
183
184   /* Call the backend to spawn the thread */
185   if ((thread_id = __gthread_objc_thread_detach ((void *)__objc_thread_detach_function,
186                                                  istate)) == NULL)
187     {
188       /* failed! */
189       objc_mutex_unlock (__objc_runtime_mutex);
190       objc_free (istate);
191       return NULL;
192     }
193
194   /* Increment our thread counter */
195   __objc_runtime_threads_alive++;
196   objc_mutex_unlock (__objc_runtime_mutex);
197
198   return thread_id;
199 }
200
201 /* Set the current thread's priority. */
202 int
203 objc_thread_set_priority (int priority)
204 {
205   /* Call the backend */
206   return __gthread_objc_thread_set_priority (priority);
207 }
208
209 /* Return the current thread's priority. */
210 int
211 objc_thread_get_priority (void)
212 {
213   /* Call the backend */
214   return __gthread_objc_thread_get_priority ();
215 }
216
217 /*
218   Yield our process time to another thread.  Any BUSY waiting that is done
219   by a thread should use this function to make sure that other threads can
220   make progress even on a lazy uniprocessor system.
221   */
222 void
223 objc_thread_yield (void)
224 {
225   /* Call the backend */
226   __gthread_objc_thread_yield ();
227 }
228
229 /*
230   Terminate the current tread.  Doesn't return.
231   Actually, if it failed returns -1.
232   */
233 int
234 objc_thread_exit (void)
235 {
236   /* Decrement our counter of the number of threads alive */
237   objc_mutex_lock (__objc_runtime_mutex);
238   __objc_runtime_threads_alive--;
239   objc_mutex_unlock (__objc_runtime_mutex);
240
241   /* Call the backend to terminate the thread */
242   return __gthread_objc_thread_exit ();
243 }
244
245 /*
246   Returns an integer value which uniquely describes a thread.  Must not be
247   NULL which is reserved as a marker for "no thread".
248   */
249 objc_thread_t
250 objc_thread_id (void)
251 {
252   /* Call the backend */
253   return __gthread_objc_thread_id ();
254 }
255
256 /*
257   Sets the thread's local storage pointer. 
258   Returns 0 if successful or -1 if failed.
259   */
260 int
261 objc_thread_set_data (void *value)
262 {
263   /* Call the backend */
264   return __gthread_objc_thread_set_data (value);
265 }
266
267 /*
268   Returns the thread's local storage pointer.  Returns NULL on failure.
269   */
270 void *
271 objc_thread_get_data (void)
272 {
273   /* Call the backend */
274   return __gthread_objc_thread_get_data ();
275 }
276
277 /* Frontend mutex functions */
278
279 /*
280   Allocate a mutex.  Return the mutex pointer if successful or NULL if the
281   allocation failed for any reason.
282   */
283 objc_mutex_t
284 objc_mutex_allocate (void)
285 {
286   objc_mutex_t mutex;
287
288   /* Allocate the mutex structure */
289   if (! (mutex = (objc_mutex_t)objc_malloc (sizeof (struct objc_mutex))))
290     return NULL;
291
292   /* Call backend to create the mutex */
293   if (__gthread_objc_mutex_allocate (mutex))
294     {
295       /* failed! */
296       objc_free (mutex);
297       return NULL;
298     }
299
300   /* Initialize mutex */
301   mutex->owner = NULL;
302   mutex->depth = 0;
303   return mutex;
304 }
305
306 /*
307   Deallocate a mutex.  Note that this includes an implicit mutex_lock to
308   insure that no one else is using the lock.  It is legal to deallocate
309   a lock if we have a lock on it, but illegal to deallocate a lock held
310   by anyone else.
311   Returns the number of locks on the thread.  (1 for deallocate).
312   */
313 int
314 objc_mutex_deallocate (objc_mutex_t mutex)
315 {
316   int depth;
317
318   /* Valid mutex? */
319   if (! mutex)
320     return -1;
321
322   /* Acquire lock on mutex */
323   depth = objc_mutex_lock (mutex);
324
325   /* Call backend to destroy mutex */
326   if (__gthread_objc_mutex_deallocate (mutex))
327     return -1;
328
329   /* Free the mutex structure */
330   objc_free (mutex);
331
332   /* Return last depth */
333   return depth;
334 }
335
336 /*
337   Grab a lock on a mutex.  If this thread already has a lock on this mutex
338   then we increment the lock count.  If another thread has a lock on the 
339   mutex we block and wait for the thread to release the lock.
340   Returns the lock count on the mutex held by this thread.
341   */
342 int
343 objc_mutex_lock (objc_mutex_t mutex)
344 {
345   objc_thread_t thread_id;
346   int status;
347
348   /* Valid mutex? */
349   if (! mutex)
350     return -1;
351
352   /* If we already own the lock then increment depth */
353   thread_id = __gthread_objc_thread_id ();
354   if (mutex->owner == thread_id)
355     return ++mutex->depth;
356
357   /* Call the backend to lock the mutex */
358   status = __gthread_objc_mutex_lock (mutex);
359
360   /* Failed? */
361   if (status)
362     return status;
363
364   /* Successfully locked the thread */
365   mutex->owner = thread_id;
366   return mutex->depth = 1;
367 }
368
369 /*
370   Try to grab a lock on a mutex.  If this thread already has a lock on
371   this mutex then we increment the lock count and return it.  If another
372   thread has a lock on the mutex returns -1.
373   */
374 int
375 objc_mutex_trylock (objc_mutex_t mutex)
376 {
377   objc_thread_t thread_id;
378   int status;
379
380   /* Valid mutex? */
381   if (! mutex)
382     return -1;
383
384   /* If we already own the lock then increment depth */ 
385   thread_id = __gthread_objc_thread_id ();
386   if (mutex->owner == thread_id)
387     return ++mutex->depth;
388     
389   /* Call the backend to try to lock the mutex */
390   status = __gthread_objc_mutex_trylock (mutex);
391
392   /* Failed? */
393   if (status)
394     return status;
395
396   /* Successfully locked the thread */
397   mutex->owner = thread_id;
398   return mutex->depth = 1;
399 }
400
401 /* 
402   Unlocks the mutex by one level.
403   Decrements the lock count on this mutex by one.
404   If the lock count reaches zero, release the lock on the mutex.
405   Returns the lock count on the mutex.
406   It is an error to attempt to unlock a mutex which this thread 
407   doesn't hold in which case return -1 and the mutex is unaffected.
408   */
409 int
410 objc_mutex_unlock (objc_mutex_t mutex)
411 {
412   objc_thread_t thread_id;
413   int status;
414
415   /* Valid mutex? */
416   if (! mutex)
417     return -1;
418
419   /* If another thread owns the lock then abort */
420   thread_id = __gthread_objc_thread_id ();
421   if (mutex->owner != thread_id)
422     return -1;
423
424   /* Decrement depth and return */
425   if (mutex->depth > 1)
426     return --mutex->depth;
427
428   /* Depth down to zero so we are no longer the owner */
429   mutex->depth = 0;
430   mutex->owner = NULL;
431
432   /* Have the backend unlock the mutex */
433   status = __gthread_objc_mutex_unlock (mutex);
434
435   /* Failed? */
436   if (status)
437     return status;
438
439   return 0;
440 }
441
442 /* Frontend condition mutex functions */
443
444 /*
445   Allocate a condition.  Return the condition pointer if successful or NULL
446   if the allocation failed for any reason.
447   */
448 objc_condition_t 
449 objc_condition_allocate (void)
450 {
451   objc_condition_t condition;
452     
453   /* Allocate the condition mutex structure */
454   if (! (condition = 
455          (objc_condition_t) objc_malloc (sizeof (struct objc_condition))))
456     return NULL;
457
458   /* Call the backend to create the condition mutex */
459   if (__gthread_objc_condition_allocate (condition))
460     {
461       /* failed! */
462       objc_free (condition);
463       return NULL;
464     }
465
466   /* Success! */
467   return condition;
468 }
469
470 /*
471   Deallocate a condition. Note that this includes an implicit 
472   condition_broadcast to insure that waiting threads have the opportunity
473   to wake.  It is legal to dealloc a condition only if no other
474   thread is/will be using it. Here we do NOT check for other threads
475   waiting but just wake them up.
476   */
477 int
478 objc_condition_deallocate (objc_condition_t condition)
479 {
480   /* Broadcast the condition */
481   if (objc_condition_broadcast (condition))
482     return -1;
483
484   /* Call the backend to destroy */
485   if (__gthread_objc_condition_deallocate (condition))
486     return -1;
487
488   /* Free the condition mutex structure */
489   objc_free (condition);
490
491   return 0;
492 }
493
494 /*
495   Wait on the condition unlocking the mutex until objc_condition_signal ()
496   or objc_condition_broadcast () are called for the same condition. The
497   given mutex *must* have the depth set to 1 so that it can be unlocked
498   here, so that someone else can lock it and signal/broadcast the condition.
499   The mutex is used to lock access to the shared data that make up the
500   "condition" predicate.
501   */
502 int
503 objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex)
504 {
505   objc_thread_t thread_id;
506
507   /* Valid arguments? */
508   if (! mutex || ! condition)
509     return -1;
510
511   /* Make sure we are owner of mutex */
512   thread_id = __gthread_objc_thread_id ();
513   if (mutex->owner != thread_id)
514     return -1;
515
516   /* Cannot be locked more than once */
517   if (mutex->depth > 1)
518     return -1;
519
520   /* Virtually unlock the mutex */
521   mutex->depth = 0;
522   mutex->owner = (objc_thread_t)NULL;
523
524   /* Call the backend to wait */
525   __gthread_objc_condition_wait (condition, mutex);
526
527   /* Make ourselves owner of the mutex */
528   mutex->owner = thread_id;
529   mutex->depth = 1;
530
531   return 0;
532 }
533
534 /*
535   Wake up all threads waiting on this condition. It is recommended that 
536   the called would lock the same mutex as the threads in objc_condition_wait
537   before changing the "condition predicate" and make this call and unlock it
538   right away after this call.
539   */
540 int
541 objc_condition_broadcast (objc_condition_t condition)
542 {
543   /* Valid condition mutex? */
544   if (! condition)
545     return -1;
546
547   return __gthread_objc_condition_broadcast (condition);
548 }
549
550 /*
551   Wake up one thread waiting on this condition. It is recommended that 
552   the called would lock the same mutex as the threads in objc_condition_wait
553   before changing the "condition predicate" and make this call and unlock it
554   right away after this call.
555   */
556 int
557 objc_condition_signal (objc_condition_t condition)
558 {
559   /* Valid condition mutex? */
560   if (! condition)
561     return -1;
562
563   return __gthread_objc_condition_signal (condition);
564 }
565
566 /* Make the objc thread system aware that a thread which is managed
567    (started, stopped) by external code could access objc facilities
568    from now on.  This is used when you are interfacing with some
569    external non-objc-based environment/system - you must call
570    objc_thread_add () before an alien thread makes any calls to
571    Objective-C.  Do not cause the _objc_became_multi_threaded hook to
572    be executed. */
573 void 
574 objc_thread_add (void)
575 {
576   objc_mutex_lock (__objc_runtime_mutex);
577   __objc_is_multi_threaded = 1;
578   __objc_runtime_threads_alive++;
579   objc_mutex_unlock (__objc_runtime_mutex);  
580 }
581
582 /* Make the objc thread system aware that a thread managed (started,
583    stopped) by some external code will no longer access objc and thus
584    can be forgotten by the objc thread system.  Call
585    objc_thread_remove () when your alien thread is done with making
586    calls to Objective-C. */
587 void
588 objc_thread_remove (void)
589 {
590   objc_mutex_lock (__objc_runtime_mutex);
591   __objc_runtime_threads_alive--;
592   objc_mutex_unlock (__objc_runtime_mutex);  
593 }
594
595 /* End of File */