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