OSDN Git Service

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