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