xref: /netbsd-src/external/gpl3/gcc.old/dist/libobjc/thr.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
136ac495dSmrg /* GNU Objective C Runtime Thread Interface
2*8feb0f0bSmrg    Copyright (C) 1996-2020 Free Software Foundation, Inc.
336ac495dSmrg    Contributed by Galen C. Hunt (gchunt@cs.rochester.edu)
436ac495dSmrg 
536ac495dSmrg This file is part of GCC.
636ac495dSmrg 
736ac495dSmrg GCC is free software; you can redistribute it and/or modify it under the
836ac495dSmrg terms of the GNU General Public License as published by the Free Software
936ac495dSmrg Foundation; either version 3, or (at your option) any later version.
1036ac495dSmrg 
1136ac495dSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1236ac495dSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1336ac495dSmrg FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
1436ac495dSmrg details.
1536ac495dSmrg 
1636ac495dSmrg Under Section 7 of GPL version 3, you are granted additional
1736ac495dSmrg permissions described in the GCC Runtime Library Exception, version
1836ac495dSmrg 3.1, as published by the Free Software Foundation.
1936ac495dSmrg 
2036ac495dSmrg You should have received a copy of the GNU General Public License and
2136ac495dSmrg a copy of the GCC Runtime Library Exception along with this program;
2236ac495dSmrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
2336ac495dSmrg <http://www.gnu.org/licenses/>.  */
2436ac495dSmrg 
2536ac495dSmrg #include "objc-private/common.h"
2636ac495dSmrg #include "objc-private/error.h"
2736ac495dSmrg #define _LIBOBJC
2836ac495dSmrg #include "config.h"
2936ac495dSmrg #include "tconfig.h"
3036ac495dSmrg #include "coretypes.h"
3136ac495dSmrg #include "tm.h"
3236ac495dSmrg #include "defaults.h"
3336ac495dSmrg #include "objc/thr.h"
3436ac495dSmrg #include "objc/message.h" /* For objc_msg_lookup().  */
3536ac495dSmrg #include "objc/runtime.h"
3636ac495dSmrg #include "objc-private/module-abi-8.h"
3736ac495dSmrg #include "objc-private/runtime.h"
3836ac495dSmrg #include <gthr.h>
3936ac495dSmrg 
4036ac495dSmrg #include <stdlib.h>
4136ac495dSmrg 
4236ac495dSmrg /* Global exit status. */
4336ac495dSmrg int __objc_thread_exit_status = 0;
4436ac495dSmrg 
4536ac495dSmrg /* Flag which lets us know if we ever became multi threaded.  */
4636ac495dSmrg int __objc_is_multi_threaded = 0;
4736ac495dSmrg 
4836ac495dSmrg /* The hook function called when the runtime becomes multi
4936ac495dSmrg    threaded.  */
5036ac495dSmrg objc_thread_callback _objc_became_multi_threaded = NULL;
5136ac495dSmrg 
5236ac495dSmrg /* Use this to set the hook function that will be called when the
5336ac495dSmrg    runtime initially becomes multi threaded.  The hook function is
5436ac495dSmrg    only called once, meaning only when the 2nd thread is spawned, not
5536ac495dSmrg    for each and every thread.
5636ac495dSmrg 
5736ac495dSmrg    It returns the previous hook function or NULL if there is none.
5836ac495dSmrg 
5936ac495dSmrg    A program outside of the runtime could set this to some function so
6036ac495dSmrg    it can be informed; for example, the GNUstep Base Library sets it
6136ac495dSmrg    so it can implement the NSBecomingMultiThreaded notification.  */
objc_set_thread_callback(objc_thread_callback func)6236ac495dSmrg objc_thread_callback objc_set_thread_callback (objc_thread_callback func)
6336ac495dSmrg {
6436ac495dSmrg   objc_thread_callback temp = _objc_became_multi_threaded;
6536ac495dSmrg   _objc_became_multi_threaded = func;
6636ac495dSmrg   return temp;
6736ac495dSmrg }
6836ac495dSmrg 
6936ac495dSmrg /* Private functions.
7036ac495dSmrg 
7136ac495dSmrg    These functions are utilized by the runtime, but they are not
7236ac495dSmrg    considered part of the public interface.  */
7336ac495dSmrg 
7436ac495dSmrg /* Initialize the threads subsystem.  */
7536ac495dSmrg int
__objc_init_thread_system(void)7636ac495dSmrg __objc_init_thread_system(void)
7736ac495dSmrg {
7836ac495dSmrg   return __gthread_objc_init_thread_system ();
7936ac495dSmrg }
8036ac495dSmrg 
8136ac495dSmrg /* First function called in a thread, starts everything else.
8236ac495dSmrg 
8336ac495dSmrg    This function is passed to the backend by objc_thread_detach as the
8436ac495dSmrg    starting function for a new thread.  */
8536ac495dSmrg struct __objc_thread_start_state
8636ac495dSmrg {
8736ac495dSmrg   SEL selector;
8836ac495dSmrg   id object;
8936ac495dSmrg   id argument;
9036ac495dSmrg };
9136ac495dSmrg 
9236ac495dSmrg static void __attribute__((noreturn))
__objc_thread_detach_function(struct __objc_thread_start_state * istate)9336ac495dSmrg __objc_thread_detach_function (struct __objc_thread_start_state *istate)
9436ac495dSmrg {
9536ac495dSmrg   /* Valid state? */
9636ac495dSmrg   if (istate)
9736ac495dSmrg     {
9836ac495dSmrg       id (*imp) (id, SEL, id);
9936ac495dSmrg       SEL selector = istate->selector;
10036ac495dSmrg       id object   = istate->object;
10136ac495dSmrg       id argument = istate->argument;
10236ac495dSmrg 
10336ac495dSmrg       /* Don't need anymore so free it.  */
10436ac495dSmrg       objc_free (istate);
10536ac495dSmrg 
10636ac495dSmrg       /* Clear out the thread local storage.  */
10736ac495dSmrg       objc_thread_set_data (NULL);
10836ac495dSmrg 
10936ac495dSmrg       /* Check to see if we just became multi threaded. */
11036ac495dSmrg       if (! __objc_is_multi_threaded)
11136ac495dSmrg 	{
11236ac495dSmrg 	  __objc_is_multi_threaded = 1;
11336ac495dSmrg 
11436ac495dSmrg 	  /* Call the hook function.  */
11536ac495dSmrg 	  if (_objc_became_multi_threaded != NULL)
11636ac495dSmrg 	    (*_objc_became_multi_threaded) ();
11736ac495dSmrg 	}
11836ac495dSmrg 
11936ac495dSmrg       /* Call the method.  */
12036ac495dSmrg       if ((imp = (id (*) (id, SEL, id))objc_msg_lookup (object, selector)))
12136ac495dSmrg 	(*imp) (object, selector, argument);
12236ac495dSmrg       else
12336ac495dSmrg 	{
12436ac495dSmrg 	  /* FIXME: Should we abort here ? */
12536ac495dSmrg 	  _objc_abort ("objc_thread_detach called with bad selector.\n");
12636ac495dSmrg 	}
12736ac495dSmrg     }
12836ac495dSmrg   else
12936ac495dSmrg     {
13036ac495dSmrg       /* FIXME: Should we abort here ? */
13136ac495dSmrg       _objc_abort ("objc_thread_detach called with NULL state.\n");
13236ac495dSmrg     }
13336ac495dSmrg 
13436ac495dSmrg   /* Exit the thread.  */
13536ac495dSmrg   objc_thread_exit ();
13636ac495dSmrg 
13736ac495dSmrg   /* Make sure compiler detects no return.  */
13836ac495dSmrg   __builtin_trap ();
13936ac495dSmrg }
14036ac495dSmrg 
14136ac495dSmrg /* Public functions.
14236ac495dSmrg 
14336ac495dSmrg    These functions constitute the public interface to the Objective-C
14436ac495dSmrg    thread and mutex functionality.  */
14536ac495dSmrg 
14636ac495dSmrg /* Detach a new thread of execution and return its id.  Returns NULL
14736ac495dSmrg    if fails.  Thread is started by sending message with selector to
14836ac495dSmrg    object.  Message takes a single argument.  */
14936ac495dSmrg objc_thread_t
objc_thread_detach(SEL selector,id object,id argument)15036ac495dSmrg objc_thread_detach (SEL selector, id object, id argument)
15136ac495dSmrg {
15236ac495dSmrg   struct __objc_thread_start_state *istate;
15336ac495dSmrg   objc_thread_t        thread_id = NULL;
15436ac495dSmrg 
15536ac495dSmrg   /* Allocate the state structure.  */
15636ac495dSmrg   if (!(istate = (struct __objc_thread_start_state *)objc_malloc
15736ac495dSmrg 	(sizeof (*istate))))
15836ac495dSmrg     return NULL;
15936ac495dSmrg 
16036ac495dSmrg   /* Initialize the state structure.  */
16136ac495dSmrg   istate->selector = selector;
16236ac495dSmrg   istate->object = object;
16336ac495dSmrg   istate->argument = argument;
16436ac495dSmrg 
16536ac495dSmrg   /* Lock access.  */
16636ac495dSmrg   objc_mutex_lock (__objc_runtime_mutex);
16736ac495dSmrg 
16836ac495dSmrg   /* Call the backend to spawn the thread.  */
16936ac495dSmrg   if ((thread_id = __gthread_objc_thread_detach ((void *)__objc_thread_detach_function,
17036ac495dSmrg 						 istate)) == NULL)
17136ac495dSmrg     {
17236ac495dSmrg       /* Failed!  */
17336ac495dSmrg       objc_mutex_unlock (__objc_runtime_mutex);
17436ac495dSmrg       objc_free (istate);
17536ac495dSmrg       return NULL;
17636ac495dSmrg     }
17736ac495dSmrg 
17836ac495dSmrg   /* Increment our thread counter.  */
17936ac495dSmrg   __objc_runtime_threads_alive++;
18036ac495dSmrg   objc_mutex_unlock (__objc_runtime_mutex);
18136ac495dSmrg 
18236ac495dSmrg   return thread_id;
18336ac495dSmrg }
18436ac495dSmrg 
18536ac495dSmrg /* Set the current thread's priority.  */
18636ac495dSmrg int
objc_thread_set_priority(int priority)18736ac495dSmrg objc_thread_set_priority (int priority)
18836ac495dSmrg {
18936ac495dSmrg   return __gthread_objc_thread_set_priority (priority);
19036ac495dSmrg }
19136ac495dSmrg 
19236ac495dSmrg /* Return the current thread's priority.  */
19336ac495dSmrg int
objc_thread_get_priority(void)19436ac495dSmrg objc_thread_get_priority (void)
19536ac495dSmrg {
19636ac495dSmrg   return __gthread_objc_thread_get_priority ();
19736ac495dSmrg }
19836ac495dSmrg 
19936ac495dSmrg /* Yield our process time to another thread.  Any BUSY waiting that is
20036ac495dSmrg    done by a thread should use this function to make sure that other
20136ac495dSmrg    threads can make progress even on a lazy uniprocessor system.  */
20236ac495dSmrg void
objc_thread_yield(void)20336ac495dSmrg objc_thread_yield (void)
20436ac495dSmrg {
20536ac495dSmrg   __gthread_objc_thread_yield ();
20636ac495dSmrg }
20736ac495dSmrg 
20836ac495dSmrg /* Terminate the current tread.  Doesn't return.  Actually, if it
20936ac495dSmrg    failed returns -1.  */
21036ac495dSmrg int
objc_thread_exit(void)21136ac495dSmrg objc_thread_exit (void)
21236ac495dSmrg {
21336ac495dSmrg   /* Decrement our counter of the number of threads alive.  */
21436ac495dSmrg   objc_mutex_lock (__objc_runtime_mutex);
21536ac495dSmrg   __objc_runtime_threads_alive--;
21636ac495dSmrg   objc_mutex_unlock (__objc_runtime_mutex);
21736ac495dSmrg 
21836ac495dSmrg   /* Call the backend to terminate the thread.  */
21936ac495dSmrg   return __gthread_objc_thread_exit ();
22036ac495dSmrg }
22136ac495dSmrg 
22236ac495dSmrg /* Returns an integer value which uniquely describes a thread.  Must
22336ac495dSmrg    not be NULL which is reserved as a marker for "no thread".  */
22436ac495dSmrg objc_thread_t
objc_thread_id(void)22536ac495dSmrg objc_thread_id (void)
22636ac495dSmrg {
22736ac495dSmrg   return __gthread_objc_thread_id ();
22836ac495dSmrg }
22936ac495dSmrg 
23036ac495dSmrg /* Sets the thread's local storage pointer.  Returns 0 if successful
23136ac495dSmrg    or -1 if failed.  */
23236ac495dSmrg int
objc_thread_set_data(void * value)23336ac495dSmrg objc_thread_set_data (void *value)
23436ac495dSmrg {
23536ac495dSmrg   return __gthread_objc_thread_set_data (value);
23636ac495dSmrg }
23736ac495dSmrg 
23836ac495dSmrg /* Returns the thread's local storage pointer.  Returns NULL on
23936ac495dSmrg    failure.  */
24036ac495dSmrg void *
objc_thread_get_data(void)24136ac495dSmrg objc_thread_get_data (void)
24236ac495dSmrg {
24336ac495dSmrg   return __gthread_objc_thread_get_data ();
24436ac495dSmrg }
24536ac495dSmrg 
24636ac495dSmrg /* Public mutex functions */
24736ac495dSmrg 
24836ac495dSmrg /* Allocate a mutex.  Return the mutex pointer if successful or NULL
24936ac495dSmrg    if the allocation failed for any reason.  */
25036ac495dSmrg objc_mutex_t
objc_mutex_allocate(void)25136ac495dSmrg objc_mutex_allocate (void)
25236ac495dSmrg {
25336ac495dSmrg   objc_mutex_t mutex;
25436ac495dSmrg 
25536ac495dSmrg   /* Allocate the mutex structure.  */
25636ac495dSmrg   if (! (mutex = (objc_mutex_t)objc_malloc (sizeof (struct objc_mutex))))
25736ac495dSmrg     return NULL;
25836ac495dSmrg 
25936ac495dSmrg   /* Call backend to create the mutex.  */
26036ac495dSmrg   if (__gthread_objc_mutex_allocate (mutex))
26136ac495dSmrg     {
26236ac495dSmrg       /* Failed!  */
26336ac495dSmrg       objc_free (mutex);
26436ac495dSmrg       return NULL;
26536ac495dSmrg     }
26636ac495dSmrg 
26736ac495dSmrg   /* Initialize mutex.  */
26836ac495dSmrg   mutex->owner = NULL;
26936ac495dSmrg   mutex->depth = 0;
27036ac495dSmrg   return mutex;
27136ac495dSmrg }
27236ac495dSmrg 
27336ac495dSmrg /* Deallocate a mutex.  Note that this includes an implicit mutex_lock
27436ac495dSmrg    to insure that no one else is using the lock.  It is legal to
27536ac495dSmrg    deallocate a lock if we have a lock on it, but illegal to
27636ac495dSmrg    deallocate a lock held by anyone else.  Returns the number of locks
27736ac495dSmrg    on the thread.  (1 for deallocate).  */
27836ac495dSmrg int
objc_mutex_deallocate(objc_mutex_t mutex)27936ac495dSmrg objc_mutex_deallocate (objc_mutex_t mutex)
28036ac495dSmrg {
28136ac495dSmrg   int depth;
28236ac495dSmrg 
28336ac495dSmrg   /* Valid mutex?  */
28436ac495dSmrg   if (! mutex)
28536ac495dSmrg     return -1;
28636ac495dSmrg 
28736ac495dSmrg   /* Acquire lock on mutex.  */
28836ac495dSmrg   depth = objc_mutex_lock (mutex);
28936ac495dSmrg 
29036ac495dSmrg   /* Call backend to destroy mutex.  */
29136ac495dSmrg   if (__gthread_objc_mutex_deallocate (mutex))
29236ac495dSmrg     return -1;
29336ac495dSmrg 
29436ac495dSmrg   /* Free the mutex structure.  */
29536ac495dSmrg   objc_free (mutex);
29636ac495dSmrg 
29736ac495dSmrg   /* Return last depth.  */
29836ac495dSmrg   return depth;
29936ac495dSmrg }
30036ac495dSmrg 
30136ac495dSmrg /* Grab a lock on a mutex.  If this thread already has a lock on this
30236ac495dSmrg    mutex then we increment the lock count.  If another thread has a
30336ac495dSmrg    lock on the mutex we block and wait for the thread to release the
30436ac495dSmrg    lock.  Returns the lock count on the mutex held by this thread.  */
30536ac495dSmrg int
objc_mutex_lock(objc_mutex_t mutex)30636ac495dSmrg objc_mutex_lock (objc_mutex_t mutex)
30736ac495dSmrg {
30836ac495dSmrg   objc_thread_t thread_id;
30936ac495dSmrg   int status;
31036ac495dSmrg 
31136ac495dSmrg   /* Valid mutex?  */
31236ac495dSmrg   if (! mutex)
31336ac495dSmrg     return -1;
31436ac495dSmrg 
31536ac495dSmrg   /* If we already own the lock then increment depth.  */
31636ac495dSmrg   thread_id = __gthread_objc_thread_id ();
31736ac495dSmrg   if (mutex->owner == thread_id)
31836ac495dSmrg     return ++mutex->depth;
31936ac495dSmrg 
32036ac495dSmrg   /* Call the backend to lock the mutex.  */
32136ac495dSmrg   status = __gthread_objc_mutex_lock (mutex);
32236ac495dSmrg 
32336ac495dSmrg   /* Failed?  */
32436ac495dSmrg   if (status)
32536ac495dSmrg     return status;
32636ac495dSmrg 
32736ac495dSmrg   /* Successfully locked the thread.  */
32836ac495dSmrg   mutex->owner = thread_id;
32936ac495dSmrg   return mutex->depth = 1;
33036ac495dSmrg }
33136ac495dSmrg 
33236ac495dSmrg /* Try to grab a lock on a mutex.  If this thread already has a lock
33336ac495dSmrg    on this mutex then we increment the lock count and return it.  If
33436ac495dSmrg    another thread has a lock on the mutex returns -1.  */
33536ac495dSmrg int
objc_mutex_trylock(objc_mutex_t mutex)33636ac495dSmrg objc_mutex_trylock (objc_mutex_t mutex)
33736ac495dSmrg {
33836ac495dSmrg   objc_thread_t thread_id;
33936ac495dSmrg   int status;
34036ac495dSmrg 
34136ac495dSmrg   /* Valid mutex?  */
34236ac495dSmrg   if (! mutex)
34336ac495dSmrg     return -1;
34436ac495dSmrg 
34536ac495dSmrg   /* If we already own the lock then increment depth.  */
34636ac495dSmrg   thread_id = __gthread_objc_thread_id ();
34736ac495dSmrg   if (mutex->owner == thread_id)
34836ac495dSmrg     return ++mutex->depth;
34936ac495dSmrg 
35036ac495dSmrg   /* Call the backend to try to lock the mutex.  */
35136ac495dSmrg   status = __gthread_objc_mutex_trylock (mutex);
35236ac495dSmrg 
35336ac495dSmrg   /* Failed?  */
35436ac495dSmrg   if (status)
35536ac495dSmrg     return status;
35636ac495dSmrg 
35736ac495dSmrg   /* Successfully locked the thread.  */
35836ac495dSmrg   mutex->owner = thread_id;
35936ac495dSmrg   return mutex->depth = 1;
36036ac495dSmrg }
36136ac495dSmrg 
36236ac495dSmrg /* Unlocks the mutex by one level.  Decrements the lock count on this
36336ac495dSmrg    mutex by one.  If the lock count reaches zero, release the lock on
36436ac495dSmrg    the mutex.  Returns the lock count on the mutex.  It is an error to
36536ac495dSmrg    attempt to unlock a mutex which this thread doesn't hold in which
36636ac495dSmrg    case return -1 and the mutex is unaffected.  */
36736ac495dSmrg int
objc_mutex_unlock(objc_mutex_t mutex)36836ac495dSmrg objc_mutex_unlock (objc_mutex_t mutex)
36936ac495dSmrg {
37036ac495dSmrg   objc_thread_t thread_id;
37136ac495dSmrg   int status;
37236ac495dSmrg 
37336ac495dSmrg   /* Valid mutex?  */
37436ac495dSmrg   if (! mutex)
37536ac495dSmrg     return -1;
37636ac495dSmrg 
37736ac495dSmrg   /* If another thread owns the lock then abort.  */
37836ac495dSmrg   thread_id = __gthread_objc_thread_id ();
37936ac495dSmrg   if (mutex->owner != thread_id)
38036ac495dSmrg     return -1;
38136ac495dSmrg 
38236ac495dSmrg   /* Decrement depth and return.  */
38336ac495dSmrg   if (mutex->depth > 1)
38436ac495dSmrg     return --mutex->depth;
38536ac495dSmrg 
38636ac495dSmrg   /* Depth down to zero so we are no longer the owner.  */
38736ac495dSmrg   mutex->depth = 0;
38836ac495dSmrg   mutex->owner = NULL;
38936ac495dSmrg 
39036ac495dSmrg   /* Have the backend unlock the mutex.  */
39136ac495dSmrg   status = __gthread_objc_mutex_unlock (mutex);
39236ac495dSmrg 
39336ac495dSmrg   /* Failed?  */
39436ac495dSmrg   if (status)
39536ac495dSmrg     return status;
39636ac495dSmrg 
39736ac495dSmrg   return 0;
39836ac495dSmrg }
39936ac495dSmrg 
40036ac495dSmrg /* Public condition mutex functions */
40136ac495dSmrg 
40236ac495dSmrg /* Allocate a condition.  Return the condition pointer if successful
40336ac495dSmrg    or NULL if the allocation failed for any reason.  */
40436ac495dSmrg objc_condition_t
objc_condition_allocate(void)40536ac495dSmrg objc_condition_allocate (void)
40636ac495dSmrg {
40736ac495dSmrg   objc_condition_t condition;
40836ac495dSmrg 
40936ac495dSmrg   /* Allocate the condition mutex structure.  */
41036ac495dSmrg   if (! (condition =
41136ac495dSmrg 	 (objc_condition_t) objc_malloc (sizeof (struct objc_condition))))
41236ac495dSmrg     return NULL;
41336ac495dSmrg 
41436ac495dSmrg   /* Call the backend to create the condition mutex.  */
41536ac495dSmrg   if (__gthread_objc_condition_allocate (condition))
41636ac495dSmrg     {
41736ac495dSmrg       /* Failed!  */
41836ac495dSmrg       objc_free (condition);
41936ac495dSmrg       return NULL;
42036ac495dSmrg     }
42136ac495dSmrg 
42236ac495dSmrg   /* Success!  */
42336ac495dSmrg   return condition;
42436ac495dSmrg }
42536ac495dSmrg 
42636ac495dSmrg /* Deallocate a condition. Note that this includes an implicit
42736ac495dSmrg    condition_broadcast to insure that waiting threads have the
42836ac495dSmrg    opportunity to wake.  It is legal to dealloc a condition only if no
42936ac495dSmrg    other thread is/will be using it. Here we do NOT check for other
43036ac495dSmrg    threads waiting but just wake them up.  */
43136ac495dSmrg int
objc_condition_deallocate(objc_condition_t condition)43236ac495dSmrg objc_condition_deallocate (objc_condition_t condition)
43336ac495dSmrg {
43436ac495dSmrg   /* Broadcast the condition.  */
43536ac495dSmrg   if (objc_condition_broadcast (condition))
43636ac495dSmrg     return -1;
43736ac495dSmrg 
43836ac495dSmrg   /* Call the backend to destroy.  */
43936ac495dSmrg   if (__gthread_objc_condition_deallocate (condition))
44036ac495dSmrg     return -1;
44136ac495dSmrg 
44236ac495dSmrg   /* Free the condition mutex structure.  */
44336ac495dSmrg   objc_free (condition);
44436ac495dSmrg 
44536ac495dSmrg   return 0;
44636ac495dSmrg }
44736ac495dSmrg 
44836ac495dSmrg /* Wait on the condition unlocking the mutex until
44936ac495dSmrg    objc_condition_signal () or objc_condition_broadcast () are called
45036ac495dSmrg    for the same condition. The given mutex *must* have the depth set
45136ac495dSmrg    to 1 so that it can be unlocked here, so that someone else can lock
45236ac495dSmrg    it and signal/broadcast the condition.  The mutex is used to lock
45336ac495dSmrg    access to the shared data that make up the "condition"
45436ac495dSmrg    predicate.  */
45536ac495dSmrg int
objc_condition_wait(objc_condition_t condition,objc_mutex_t mutex)45636ac495dSmrg objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex)
45736ac495dSmrg {
45836ac495dSmrg   objc_thread_t thread_id;
45936ac495dSmrg 
46036ac495dSmrg   /* Valid arguments?  */
46136ac495dSmrg   if (! mutex || ! condition)
46236ac495dSmrg     return -1;
46336ac495dSmrg 
46436ac495dSmrg   /* Make sure we are owner of mutex.  */
46536ac495dSmrg   thread_id = __gthread_objc_thread_id ();
46636ac495dSmrg   if (mutex->owner != thread_id)
46736ac495dSmrg     return -1;
46836ac495dSmrg 
46936ac495dSmrg   /* Cannot be locked more than once.  */
47036ac495dSmrg   if (mutex->depth > 1)
47136ac495dSmrg     return -1;
47236ac495dSmrg 
47336ac495dSmrg   /* Virtually unlock the mutex.  */
47436ac495dSmrg   mutex->depth = 0;
47536ac495dSmrg   mutex->owner = (objc_thread_t)NULL;
47636ac495dSmrg 
47736ac495dSmrg   /* Call the backend to wait.  */
47836ac495dSmrg   __gthread_objc_condition_wait (condition, mutex);
47936ac495dSmrg 
48036ac495dSmrg   /* Make ourselves owner of the mutex.  */
48136ac495dSmrg   mutex->owner = thread_id;
48236ac495dSmrg   mutex->depth = 1;
48336ac495dSmrg 
48436ac495dSmrg   return 0;
48536ac495dSmrg }
48636ac495dSmrg 
48736ac495dSmrg /* Wake up all threads waiting on this condition. It is recommended
48836ac495dSmrg    that the called would lock the same mutex as the threads in
48936ac495dSmrg    objc_condition_wait before changing the "condition predicate" and
49036ac495dSmrg    make this call and unlock it right away after this call.  */
49136ac495dSmrg int
objc_condition_broadcast(objc_condition_t condition)49236ac495dSmrg objc_condition_broadcast (objc_condition_t condition)
49336ac495dSmrg {
49436ac495dSmrg   /* Valid condition mutex?  */
49536ac495dSmrg   if (! condition)
49636ac495dSmrg     return -1;
49736ac495dSmrg 
49836ac495dSmrg   return __gthread_objc_condition_broadcast (condition);
49936ac495dSmrg }
50036ac495dSmrg 
50136ac495dSmrg /* Wake up one thread waiting on this condition. It is recommended
50236ac495dSmrg    that the called would lock the same mutex as the threads in
50336ac495dSmrg    objc_condition_wait before changing the "condition predicate" and
50436ac495dSmrg    make this call and unlock it right away after this call.  */
50536ac495dSmrg int
objc_condition_signal(objc_condition_t condition)50636ac495dSmrg objc_condition_signal (objc_condition_t condition)
50736ac495dSmrg {
50836ac495dSmrg   /* Valid condition mutex?  */
50936ac495dSmrg   if (! condition)
51036ac495dSmrg     return -1;
51136ac495dSmrg 
51236ac495dSmrg   return __gthread_objc_condition_signal (condition);
51336ac495dSmrg }
51436ac495dSmrg 
51536ac495dSmrg /* Make the objc thread system aware that a thread which is managed
51636ac495dSmrg    (started, stopped) by external code could access objc facilities
51736ac495dSmrg    from now on.  This is used when you are interfacing with some
51836ac495dSmrg    external non-objc-based environment/system - you must call
51936ac495dSmrg    objc_thread_add () before an alien thread makes any calls to
52036ac495dSmrg    Objective-C.  Do not cause the _objc_became_multi_threaded hook to
52136ac495dSmrg    be executed. */
52236ac495dSmrg void
objc_thread_add(void)52336ac495dSmrg objc_thread_add (void)
52436ac495dSmrg {
52536ac495dSmrg   objc_mutex_lock (__objc_runtime_mutex);
52636ac495dSmrg   __objc_is_multi_threaded = 1;
52736ac495dSmrg   __objc_runtime_threads_alive++;
52836ac495dSmrg   objc_mutex_unlock (__objc_runtime_mutex);
52936ac495dSmrg }
53036ac495dSmrg 
53136ac495dSmrg /* Make the objc thread system aware that a thread managed (started,
53236ac495dSmrg    stopped) by some external code will no longer access objc and thus
53336ac495dSmrg    can be forgotten by the objc thread system.  Call
53436ac495dSmrg    objc_thread_remove () when your alien thread is done with making
53536ac495dSmrg    calls to Objective-C. */
53636ac495dSmrg void
objc_thread_remove(void)53736ac495dSmrg objc_thread_remove (void)
53836ac495dSmrg {
53936ac495dSmrg   objc_mutex_lock (__objc_runtime_mutex);
54036ac495dSmrg   __objc_runtime_threads_alive--;
54136ac495dSmrg   objc_mutex_unlock (__objc_runtime_mutex);
54236ac495dSmrg }
54336ac495dSmrg 
544