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