xref: /netbsd-src/external/gpl3/gcc/dist/libobjc/thr.c (revision b1e838363e3c6fc78a55519254d99869742dd33c)
14fee23f9Smrg /* GNU Objective C Runtime Thread Interface
2*b1e83836Smrg    Copyright (C) 1996-2022 Free Software Foundation, Inc.
34fee23f9Smrg    Contributed by Galen C. Hunt (gchunt@cs.rochester.edu)
44fee23f9Smrg 
54fee23f9Smrg This file is part of GCC.
64fee23f9Smrg 
74fee23f9Smrg GCC is free software; you can redistribute it and/or modify it under the
84fee23f9Smrg terms of the GNU General Public License as published by the Free Software
94fee23f9Smrg Foundation; either version 3, or (at your option) any later version.
104fee23f9Smrg 
114fee23f9Smrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
124fee23f9Smrg WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
134fee23f9Smrg FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
144fee23f9Smrg details.
154fee23f9Smrg 
164fee23f9Smrg Under Section 7 of GPL version 3, you are granted additional
174fee23f9Smrg permissions described in the GCC Runtime Library Exception, version
184fee23f9Smrg 3.1, as published by the Free Software Foundation.
194fee23f9Smrg 
204fee23f9Smrg You should have received a copy of the GNU General Public License and
214fee23f9Smrg a copy of the GCC Runtime Library Exception along with this program;
224fee23f9Smrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
234fee23f9Smrg <http://www.gnu.org/licenses/>.  */
244fee23f9Smrg 
2548fb7bfaSmrg #include "objc-private/common.h"
2648fb7bfaSmrg #include "objc-private/error.h"
2748fb7bfaSmrg #define _LIBOBJC
2848fb7bfaSmrg #include "config.h"
2948fb7bfaSmrg #include "tconfig.h"
3048fb7bfaSmrg #include "coretypes.h"
3148fb7bfaSmrg #include "tm.h"
3248fb7bfaSmrg #include "defaults.h"
3348fb7bfaSmrg #include "objc/thr.h"
3448fb7bfaSmrg #include "objc/message.h" /* For objc_msg_lookup().  */
3548fb7bfaSmrg #include "objc/runtime.h"
3648fb7bfaSmrg #include "objc-private/module-abi-8.h"
3748fb7bfaSmrg #include "objc-private/runtime.h"
3848fb7bfaSmrg #include <gthr.h>
394fee23f9Smrg 
404fee23f9Smrg #include <stdlib.h>
414fee23f9Smrg 
424fee23f9Smrg /* Global exit status. */
434fee23f9Smrg int __objc_thread_exit_status = 0;
444fee23f9Smrg 
4548fb7bfaSmrg /* Flag which lets us know if we ever became multi threaded.  */
464fee23f9Smrg int __objc_is_multi_threaded = 0;
474fee23f9Smrg 
4848fb7bfaSmrg /* The hook function called when the runtime becomes multi
4948fb7bfaSmrg    threaded.  */
504fee23f9Smrg objc_thread_callback _objc_became_multi_threaded = NULL;
514fee23f9Smrg 
5248fb7bfaSmrg /* Use this to set the hook function that will be called when the
5348fb7bfaSmrg    runtime initially becomes multi threaded.  The hook function is
5448fb7bfaSmrg    only called once, meaning only when the 2nd thread is spawned, not
5548fb7bfaSmrg    for each and every thread.
564fee23f9Smrg 
574fee23f9Smrg    It returns the previous hook function or NULL if there is none.
584fee23f9Smrg 
594fee23f9Smrg    A program outside of the runtime could set this to some function so
604fee23f9Smrg    it can be informed; for example, the GNUstep Base Library sets it
6148fb7bfaSmrg    so it can implement the NSBecomingMultiThreaded notification.  */
objc_set_thread_callback(objc_thread_callback func)624fee23f9Smrg objc_thread_callback objc_set_thread_callback (objc_thread_callback func)
634fee23f9Smrg {
644fee23f9Smrg   objc_thread_callback temp = _objc_became_multi_threaded;
654fee23f9Smrg   _objc_became_multi_threaded = func;
664fee23f9Smrg   return temp;
674fee23f9Smrg }
684fee23f9Smrg 
6948fb7bfaSmrg /* Private functions.
704fee23f9Smrg 
7148fb7bfaSmrg    These functions are utilized by the runtime, but they are not
7248fb7bfaSmrg    considered part of the public interface.  */
734fee23f9Smrg 
7448fb7bfaSmrg /* Initialize the threads subsystem.  */
7548fb7bfaSmrg int
__objc_init_thread_system(void)7648fb7bfaSmrg __objc_init_thread_system(void)
7748fb7bfaSmrg {
7848fb7bfaSmrg   return __gthread_objc_init_thread_system ();
7948fb7bfaSmrg }
804fee23f9Smrg 
8148fb7bfaSmrg /* First function called in a thread, starts everything else.
8248fb7bfaSmrg 
8348fb7bfaSmrg    This function is passed to the backend by objc_thread_detach as the
8448fb7bfaSmrg    starting function for a new thread.  */
854fee23f9Smrg struct __objc_thread_start_state
864fee23f9Smrg {
874fee23f9Smrg   SEL selector;
884fee23f9Smrg   id object;
894fee23f9Smrg   id argument;
904fee23f9Smrg };
914fee23f9Smrg 
924fee23f9Smrg static void __attribute__((noreturn))
__objc_thread_detach_function(struct __objc_thread_start_state * istate)934fee23f9Smrg __objc_thread_detach_function (struct __objc_thread_start_state *istate)
944fee23f9Smrg {
954fee23f9Smrg   /* Valid state? */
9648fb7bfaSmrg   if (istate)
9748fb7bfaSmrg     {
984fee23f9Smrg       id (*imp) (id, SEL, id);
994fee23f9Smrg       SEL selector = istate->selector;
1004fee23f9Smrg       id object   = istate->object;
1014fee23f9Smrg       id argument = istate->argument;
1024fee23f9Smrg 
10348fb7bfaSmrg       /* Don't need anymore so free it.  */
1044fee23f9Smrg       objc_free (istate);
1054fee23f9Smrg 
10648fb7bfaSmrg       /* Clear out the thread local storage.  */
1074fee23f9Smrg       objc_thread_set_data (NULL);
1084fee23f9Smrg 
10948fb7bfaSmrg       /* Check to see if we just became multi threaded. */
1104fee23f9Smrg       if (! __objc_is_multi_threaded)
1114fee23f9Smrg 	{
1124fee23f9Smrg 	  __objc_is_multi_threaded = 1;
1134fee23f9Smrg 
11448fb7bfaSmrg 	  /* Call the hook function.  */
1154fee23f9Smrg 	  if (_objc_became_multi_threaded != NULL)
1164fee23f9Smrg 	    (*_objc_became_multi_threaded) ();
1174fee23f9Smrg 	}
1184fee23f9Smrg 
11948fb7bfaSmrg       /* Call the method.  */
1204fee23f9Smrg       if ((imp = (id (*) (id, SEL, id))objc_msg_lookup (object, selector)))
1214fee23f9Smrg 	(*imp) (object, selector, argument);
1224fee23f9Smrg       else
12348fb7bfaSmrg 	{
12448fb7bfaSmrg 	  /* FIXME: Should we abort here ? */
12548fb7bfaSmrg 	  _objc_abort ("objc_thread_detach called with bad selector.\n");
12648fb7bfaSmrg 	}
1274fee23f9Smrg     }
1284fee23f9Smrg   else
12948fb7bfaSmrg     {
13048fb7bfaSmrg       /* FIXME: Should we abort here ? */
13148fb7bfaSmrg       _objc_abort ("objc_thread_detach called with NULL state.\n");
13248fb7bfaSmrg     }
1334fee23f9Smrg 
13448fb7bfaSmrg   /* Exit the thread.  */
1354fee23f9Smrg   objc_thread_exit ();
1364fee23f9Smrg 
1374fee23f9Smrg   /* Make sure compiler detects no return.  */
1384fee23f9Smrg   __builtin_trap ();
1394fee23f9Smrg }
1404fee23f9Smrg 
14148fb7bfaSmrg /* Public functions.
1424fee23f9Smrg 
14348fb7bfaSmrg    These functions constitute the public interface to the Objective-C
14448fb7bfaSmrg    thread and mutex functionality.  */
1454fee23f9Smrg 
14648fb7bfaSmrg /* Detach a new thread of execution and return its id.  Returns NULL
14748fb7bfaSmrg    if fails.  Thread is started by sending message with selector to
14848fb7bfaSmrg    object.  Message takes a single argument.  */
1494fee23f9Smrg objc_thread_t
objc_thread_detach(SEL selector,id object,id argument)1504fee23f9Smrg objc_thread_detach (SEL selector, id object, id argument)
1514fee23f9Smrg {
1524fee23f9Smrg   struct __objc_thread_start_state *istate;
1534fee23f9Smrg   objc_thread_t        thread_id = NULL;
1544fee23f9Smrg 
15548fb7bfaSmrg   /* Allocate the state structure.  */
15648fb7bfaSmrg   if (!(istate = (struct __objc_thread_start_state *)objc_malloc
15748fb7bfaSmrg 	(sizeof (*istate))))
1584fee23f9Smrg     return NULL;
1594fee23f9Smrg 
16048fb7bfaSmrg   /* Initialize the state structure.  */
1614fee23f9Smrg   istate->selector = selector;
1624fee23f9Smrg   istate->object = object;
1634fee23f9Smrg   istate->argument = argument;
1644fee23f9Smrg 
16548fb7bfaSmrg   /* Lock access.  */
1664fee23f9Smrg   objc_mutex_lock (__objc_runtime_mutex);
1674fee23f9Smrg 
16848fb7bfaSmrg   /* Call the backend to spawn the thread.  */
16948fb7bfaSmrg   if ((thread_id = __gthread_objc_thread_detach ((void *)__objc_thread_detach_function,
1704fee23f9Smrg 						 istate)) == NULL)
1714fee23f9Smrg     {
17248fb7bfaSmrg       /* Failed!  */
1734fee23f9Smrg       objc_mutex_unlock (__objc_runtime_mutex);
1744fee23f9Smrg       objc_free (istate);
1754fee23f9Smrg       return NULL;
1764fee23f9Smrg     }
1774fee23f9Smrg 
17848fb7bfaSmrg   /* Increment our thread counter.  */
1794fee23f9Smrg   __objc_runtime_threads_alive++;
1804fee23f9Smrg   objc_mutex_unlock (__objc_runtime_mutex);
1814fee23f9Smrg 
1824fee23f9Smrg   return thread_id;
1834fee23f9Smrg }
1844fee23f9Smrg 
1854fee23f9Smrg /* Set the current thread's priority.  */
1864fee23f9Smrg int
objc_thread_set_priority(int priority)1874fee23f9Smrg objc_thread_set_priority (int priority)
1884fee23f9Smrg {
18948fb7bfaSmrg   return __gthread_objc_thread_set_priority (priority);
1904fee23f9Smrg }
1914fee23f9Smrg 
1924fee23f9Smrg /* Return the current thread's priority.  */
1934fee23f9Smrg int
objc_thread_get_priority(void)1944fee23f9Smrg objc_thread_get_priority (void)
1954fee23f9Smrg {
19648fb7bfaSmrg   return __gthread_objc_thread_get_priority ();
1974fee23f9Smrg }
1984fee23f9Smrg 
19948fb7bfaSmrg /* Yield our process time to another thread.  Any BUSY waiting that is
20048fb7bfaSmrg    done by a thread should use this function to make sure that other
20148fb7bfaSmrg    threads can make progress even on a lazy uniprocessor system.  */
2024fee23f9Smrg void
objc_thread_yield(void)2034fee23f9Smrg objc_thread_yield (void)
2044fee23f9Smrg {
20548fb7bfaSmrg   __gthread_objc_thread_yield ();
2064fee23f9Smrg }
2074fee23f9Smrg 
20848fb7bfaSmrg /* Terminate the current tread.  Doesn't return.  Actually, if it
20948fb7bfaSmrg    failed returns -1.  */
2104fee23f9Smrg int
objc_thread_exit(void)2114fee23f9Smrg objc_thread_exit (void)
2124fee23f9Smrg {
21348fb7bfaSmrg   /* Decrement our counter of the number of threads alive.  */
2144fee23f9Smrg   objc_mutex_lock (__objc_runtime_mutex);
2154fee23f9Smrg   __objc_runtime_threads_alive--;
2164fee23f9Smrg   objc_mutex_unlock (__objc_runtime_mutex);
2174fee23f9Smrg 
21848fb7bfaSmrg   /* Call the backend to terminate the thread.  */
21948fb7bfaSmrg   return __gthread_objc_thread_exit ();
2204fee23f9Smrg }
2214fee23f9Smrg 
22248fb7bfaSmrg /* Returns an integer value which uniquely describes a thread.  Must
22348fb7bfaSmrg    not be NULL which is reserved as a marker for "no thread".  */
2244fee23f9Smrg objc_thread_t
objc_thread_id(void)2254fee23f9Smrg objc_thread_id (void)
2264fee23f9Smrg {
22748fb7bfaSmrg   return __gthread_objc_thread_id ();
2284fee23f9Smrg }
2294fee23f9Smrg 
23048fb7bfaSmrg /* Sets the thread's local storage pointer.  Returns 0 if successful
23148fb7bfaSmrg    or -1 if failed.  */
2324fee23f9Smrg int
objc_thread_set_data(void * value)2334fee23f9Smrg objc_thread_set_data (void *value)
2344fee23f9Smrg {
23548fb7bfaSmrg   return __gthread_objc_thread_set_data (value);
2364fee23f9Smrg }
2374fee23f9Smrg 
23848fb7bfaSmrg /* Returns the thread's local storage pointer.  Returns NULL on
23948fb7bfaSmrg    failure.  */
2404fee23f9Smrg void *
objc_thread_get_data(void)2414fee23f9Smrg objc_thread_get_data (void)
2424fee23f9Smrg {
24348fb7bfaSmrg   return __gthread_objc_thread_get_data ();
2444fee23f9Smrg }
2454fee23f9Smrg 
24648fb7bfaSmrg /* Public mutex functions */
2474fee23f9Smrg 
24848fb7bfaSmrg /* Allocate a mutex.  Return the mutex pointer if successful or NULL
24948fb7bfaSmrg    if the allocation failed for any reason.  */
2504fee23f9Smrg objc_mutex_t
objc_mutex_allocate(void)2514fee23f9Smrg objc_mutex_allocate (void)
2524fee23f9Smrg {
2534fee23f9Smrg   objc_mutex_t mutex;
2544fee23f9Smrg 
25548fb7bfaSmrg   /* Allocate the mutex structure.  */
2564fee23f9Smrg   if (! (mutex = (objc_mutex_t)objc_malloc (sizeof (struct objc_mutex))))
2574fee23f9Smrg     return NULL;
2584fee23f9Smrg 
25948fb7bfaSmrg   /* Call backend to create the mutex.  */
26048fb7bfaSmrg   if (__gthread_objc_mutex_allocate (mutex))
2614fee23f9Smrg     {
26248fb7bfaSmrg       /* Failed!  */
2634fee23f9Smrg       objc_free (mutex);
2644fee23f9Smrg       return NULL;
2654fee23f9Smrg     }
2664fee23f9Smrg 
26748fb7bfaSmrg   /* Initialize mutex.  */
2684fee23f9Smrg   mutex->owner = NULL;
2694fee23f9Smrg   mutex->depth = 0;
2704fee23f9Smrg   return mutex;
2714fee23f9Smrg }
2724fee23f9Smrg 
27348fb7bfaSmrg /* Deallocate a mutex.  Note that this includes an implicit mutex_lock
27448fb7bfaSmrg    to insure that no one else is using the lock.  It is legal to
27548fb7bfaSmrg    deallocate a lock if we have a lock on it, but illegal to
27648fb7bfaSmrg    deallocate a lock held by anyone else.  Returns the number of locks
27748fb7bfaSmrg    on the thread.  (1 for deallocate).  */
2784fee23f9Smrg int
objc_mutex_deallocate(objc_mutex_t mutex)2794fee23f9Smrg objc_mutex_deallocate (objc_mutex_t mutex)
2804fee23f9Smrg {
2814fee23f9Smrg   int depth;
2824fee23f9Smrg 
2834fee23f9Smrg   /* Valid mutex?  */
2844fee23f9Smrg   if (! mutex)
2854fee23f9Smrg     return -1;
2864fee23f9Smrg 
28748fb7bfaSmrg   /* Acquire lock on mutex.  */
2884fee23f9Smrg   depth = objc_mutex_lock (mutex);
2894fee23f9Smrg 
29048fb7bfaSmrg   /* Call backend to destroy mutex.  */
29148fb7bfaSmrg   if (__gthread_objc_mutex_deallocate (mutex))
2924fee23f9Smrg     return -1;
2934fee23f9Smrg 
29448fb7bfaSmrg   /* Free the mutex structure.  */
2954fee23f9Smrg   objc_free (mutex);
2964fee23f9Smrg 
29748fb7bfaSmrg   /* Return last depth.  */
2984fee23f9Smrg   return depth;
2994fee23f9Smrg }
3004fee23f9Smrg 
30148fb7bfaSmrg /* Grab a lock on a mutex.  If this thread already has a lock on this
30248fb7bfaSmrg    mutex then we increment the lock count.  If another thread has a
30348fb7bfaSmrg    lock on the mutex we block and wait for the thread to release the
30448fb7bfaSmrg    lock.  Returns the lock count on the mutex held by this thread.  */
3054fee23f9Smrg int
objc_mutex_lock(objc_mutex_t mutex)3064fee23f9Smrg objc_mutex_lock (objc_mutex_t mutex)
3074fee23f9Smrg {
3084fee23f9Smrg   objc_thread_t thread_id;
3094fee23f9Smrg   int status;
3104fee23f9Smrg 
3114fee23f9Smrg   /* Valid mutex?  */
3124fee23f9Smrg   if (! mutex)
3134fee23f9Smrg     return -1;
3144fee23f9Smrg 
31548fb7bfaSmrg   /* If we already own the lock then increment depth.  */
31648fb7bfaSmrg   thread_id = __gthread_objc_thread_id ();
3174fee23f9Smrg   if (mutex->owner == thread_id)
3184fee23f9Smrg     return ++mutex->depth;
3194fee23f9Smrg 
32048fb7bfaSmrg   /* Call the backend to lock the mutex.  */
32148fb7bfaSmrg   status = __gthread_objc_mutex_lock (mutex);
3224fee23f9Smrg 
3234fee23f9Smrg   /* Failed?  */
3244fee23f9Smrg   if (status)
3254fee23f9Smrg     return status;
3264fee23f9Smrg 
32748fb7bfaSmrg   /* Successfully locked the thread.  */
3284fee23f9Smrg   mutex->owner = thread_id;
3294fee23f9Smrg   return mutex->depth = 1;
3304fee23f9Smrg }
3314fee23f9Smrg 
33248fb7bfaSmrg /* Try to grab a lock on a mutex.  If this thread already has a lock
33348fb7bfaSmrg    on this mutex then we increment the lock count and return it.  If
33448fb7bfaSmrg    another thread has a lock on the mutex returns -1.  */
3354fee23f9Smrg int
objc_mutex_trylock(objc_mutex_t mutex)3364fee23f9Smrg objc_mutex_trylock (objc_mutex_t mutex)
3374fee23f9Smrg {
3384fee23f9Smrg   objc_thread_t thread_id;
3394fee23f9Smrg   int status;
3404fee23f9Smrg 
3414fee23f9Smrg   /* Valid mutex?  */
3424fee23f9Smrg   if (! mutex)
3434fee23f9Smrg     return -1;
3444fee23f9Smrg 
34548fb7bfaSmrg   /* If we already own the lock then increment depth.  */
34648fb7bfaSmrg   thread_id = __gthread_objc_thread_id ();
3474fee23f9Smrg   if (mutex->owner == thread_id)
3484fee23f9Smrg     return ++mutex->depth;
3494fee23f9Smrg 
35048fb7bfaSmrg   /* Call the backend to try to lock the mutex.  */
35148fb7bfaSmrg   status = __gthread_objc_mutex_trylock (mutex);
3524fee23f9Smrg 
3534fee23f9Smrg   /* Failed?  */
3544fee23f9Smrg   if (status)
3554fee23f9Smrg     return status;
3564fee23f9Smrg 
35748fb7bfaSmrg   /* Successfully locked the thread.  */
3584fee23f9Smrg   mutex->owner = thread_id;
3594fee23f9Smrg   return mutex->depth = 1;
3604fee23f9Smrg }
3614fee23f9Smrg 
36248fb7bfaSmrg /* Unlocks the mutex by one level.  Decrements the lock count on this
36348fb7bfaSmrg    mutex by one.  If the lock count reaches zero, release the lock on
36448fb7bfaSmrg    the mutex.  Returns the lock count on the mutex.  It is an error to
36548fb7bfaSmrg    attempt to unlock a mutex which this thread doesn't hold in which
36648fb7bfaSmrg    case return -1 and the mutex is unaffected.  */
3674fee23f9Smrg int
objc_mutex_unlock(objc_mutex_t mutex)3684fee23f9Smrg objc_mutex_unlock (objc_mutex_t mutex)
3694fee23f9Smrg {
3704fee23f9Smrg   objc_thread_t thread_id;
3714fee23f9Smrg   int status;
3724fee23f9Smrg 
3734fee23f9Smrg   /* Valid mutex?  */
3744fee23f9Smrg   if (! mutex)
3754fee23f9Smrg     return -1;
3764fee23f9Smrg 
37748fb7bfaSmrg   /* If another thread owns the lock then abort.  */
37848fb7bfaSmrg   thread_id = __gthread_objc_thread_id ();
3794fee23f9Smrg   if (mutex->owner != thread_id)
3804fee23f9Smrg     return -1;
3814fee23f9Smrg 
38248fb7bfaSmrg   /* Decrement depth and return.  */
3834fee23f9Smrg   if (mutex->depth > 1)
3844fee23f9Smrg     return --mutex->depth;
3854fee23f9Smrg 
38648fb7bfaSmrg   /* Depth down to zero so we are no longer the owner.  */
3874fee23f9Smrg   mutex->depth = 0;
3884fee23f9Smrg   mutex->owner = NULL;
3894fee23f9Smrg 
39048fb7bfaSmrg   /* Have the backend unlock the mutex.  */
39148fb7bfaSmrg   status = __gthread_objc_mutex_unlock (mutex);
3924fee23f9Smrg 
3934fee23f9Smrg   /* Failed?  */
3944fee23f9Smrg   if (status)
3954fee23f9Smrg     return status;
3964fee23f9Smrg 
3974fee23f9Smrg   return 0;
3984fee23f9Smrg }
3994fee23f9Smrg 
40048fb7bfaSmrg /* Public condition mutex functions */
4014fee23f9Smrg 
40248fb7bfaSmrg /* Allocate a condition.  Return the condition pointer if successful
40348fb7bfaSmrg    or NULL if the allocation failed for any reason.  */
4044fee23f9Smrg objc_condition_t
objc_condition_allocate(void)4054fee23f9Smrg objc_condition_allocate (void)
4064fee23f9Smrg {
4074fee23f9Smrg   objc_condition_t condition;
4084fee23f9Smrg 
40948fb7bfaSmrg   /* Allocate the condition mutex structure.  */
4104fee23f9Smrg   if (! (condition =
4114fee23f9Smrg 	 (objc_condition_t) objc_malloc (sizeof (struct objc_condition))))
4124fee23f9Smrg     return NULL;
4134fee23f9Smrg 
41448fb7bfaSmrg   /* Call the backend to create the condition mutex.  */
41548fb7bfaSmrg   if (__gthread_objc_condition_allocate (condition))
4164fee23f9Smrg     {
41748fb7bfaSmrg       /* Failed!  */
4184fee23f9Smrg       objc_free (condition);
4194fee23f9Smrg       return NULL;
4204fee23f9Smrg     }
4214fee23f9Smrg 
4224fee23f9Smrg   /* Success!  */
4234fee23f9Smrg   return condition;
4244fee23f9Smrg }
4254fee23f9Smrg 
42648fb7bfaSmrg /* Deallocate a condition. Note that this includes an implicit
42748fb7bfaSmrg    condition_broadcast to insure that waiting threads have the
42848fb7bfaSmrg    opportunity to wake.  It is legal to dealloc a condition only if no
42948fb7bfaSmrg    other thread is/will be using it. Here we do NOT check for other
43048fb7bfaSmrg    threads waiting but just wake them up.  */
4314fee23f9Smrg int
objc_condition_deallocate(objc_condition_t condition)4324fee23f9Smrg objc_condition_deallocate (objc_condition_t condition)
4334fee23f9Smrg {
43448fb7bfaSmrg   /* Broadcast the condition.  */
4354fee23f9Smrg   if (objc_condition_broadcast (condition))
4364fee23f9Smrg     return -1;
4374fee23f9Smrg 
43848fb7bfaSmrg   /* Call the backend to destroy.  */
43948fb7bfaSmrg   if (__gthread_objc_condition_deallocate (condition))
4404fee23f9Smrg     return -1;
4414fee23f9Smrg 
44248fb7bfaSmrg   /* Free the condition mutex structure.  */
4434fee23f9Smrg   objc_free (condition);
4444fee23f9Smrg 
4454fee23f9Smrg   return 0;
4464fee23f9Smrg }
4474fee23f9Smrg 
44848fb7bfaSmrg /* Wait on the condition unlocking the mutex until
44948fb7bfaSmrg    objc_condition_signal () or objc_condition_broadcast () are called
45048fb7bfaSmrg    for the same condition. The given mutex *must* have the depth set
45148fb7bfaSmrg    to 1 so that it can be unlocked here, so that someone else can lock
45248fb7bfaSmrg    it and signal/broadcast the condition.  The mutex is used to lock
45348fb7bfaSmrg    access to the shared data that make up the "condition"
45448fb7bfaSmrg    predicate.  */
4554fee23f9Smrg int
objc_condition_wait(objc_condition_t condition,objc_mutex_t mutex)4564fee23f9Smrg objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex)
4574fee23f9Smrg {
4584fee23f9Smrg   objc_thread_t thread_id;
4594fee23f9Smrg 
4604fee23f9Smrg   /* Valid arguments?  */
4614fee23f9Smrg   if (! mutex || ! condition)
4624fee23f9Smrg     return -1;
4634fee23f9Smrg 
46448fb7bfaSmrg   /* Make sure we are owner of mutex.  */
46548fb7bfaSmrg   thread_id = __gthread_objc_thread_id ();
4664fee23f9Smrg   if (mutex->owner != thread_id)
4674fee23f9Smrg     return -1;
4684fee23f9Smrg 
46948fb7bfaSmrg   /* Cannot be locked more than once.  */
4704fee23f9Smrg   if (mutex->depth > 1)
4714fee23f9Smrg     return -1;
4724fee23f9Smrg 
47348fb7bfaSmrg   /* Virtually unlock the mutex.  */
4744fee23f9Smrg   mutex->depth = 0;
4754fee23f9Smrg   mutex->owner = (objc_thread_t)NULL;
4764fee23f9Smrg 
47748fb7bfaSmrg   /* Call the backend to wait.  */
47848fb7bfaSmrg   __gthread_objc_condition_wait (condition, mutex);
4794fee23f9Smrg 
48048fb7bfaSmrg   /* Make ourselves owner of the mutex.  */
4814fee23f9Smrg   mutex->owner = thread_id;
4824fee23f9Smrg   mutex->depth = 1;
4834fee23f9Smrg 
4844fee23f9Smrg   return 0;
4854fee23f9Smrg }
4864fee23f9Smrg 
48748fb7bfaSmrg /* Wake up all threads waiting on this condition. It is recommended
48848fb7bfaSmrg    that the called would lock the same mutex as the threads in
48948fb7bfaSmrg    objc_condition_wait before changing the "condition predicate" and
49048fb7bfaSmrg    make this call and unlock it right away after this call.  */
4914fee23f9Smrg int
objc_condition_broadcast(objc_condition_t condition)4924fee23f9Smrg objc_condition_broadcast (objc_condition_t condition)
4934fee23f9Smrg {
4944fee23f9Smrg   /* Valid condition mutex?  */
4954fee23f9Smrg   if (! condition)
4964fee23f9Smrg     return -1;
4974fee23f9Smrg 
49848fb7bfaSmrg   return __gthread_objc_condition_broadcast (condition);
4994fee23f9Smrg }
5004fee23f9Smrg 
50148fb7bfaSmrg /* Wake up one thread waiting on this condition. It is recommended
50248fb7bfaSmrg    that the called would lock the same mutex as the threads in
50348fb7bfaSmrg    objc_condition_wait before changing the "condition predicate" and
50448fb7bfaSmrg    make this call and unlock it right away after this call.  */
5054fee23f9Smrg int
objc_condition_signal(objc_condition_t condition)5064fee23f9Smrg objc_condition_signal (objc_condition_t condition)
5074fee23f9Smrg {
5084fee23f9Smrg   /* Valid condition mutex?  */
5094fee23f9Smrg   if (! condition)
5104fee23f9Smrg     return -1;
5114fee23f9Smrg 
51248fb7bfaSmrg   return __gthread_objc_condition_signal (condition);
5134fee23f9Smrg }
5144fee23f9Smrg 
5154fee23f9Smrg /* Make the objc thread system aware that a thread which is managed
5164fee23f9Smrg    (started, stopped) by external code could access objc facilities
5174fee23f9Smrg    from now on.  This is used when you are interfacing with some
5184fee23f9Smrg    external non-objc-based environment/system - you must call
5194fee23f9Smrg    objc_thread_add () before an alien thread makes any calls to
5204fee23f9Smrg    Objective-C.  Do not cause the _objc_became_multi_threaded hook to
5214fee23f9Smrg    be executed. */
5224fee23f9Smrg void
objc_thread_add(void)5234fee23f9Smrg objc_thread_add (void)
5244fee23f9Smrg {
5254fee23f9Smrg   objc_mutex_lock (__objc_runtime_mutex);
5264fee23f9Smrg   __objc_is_multi_threaded = 1;
5274fee23f9Smrg   __objc_runtime_threads_alive++;
5284fee23f9Smrg   objc_mutex_unlock (__objc_runtime_mutex);
5294fee23f9Smrg }
5304fee23f9Smrg 
5314fee23f9Smrg /* Make the objc thread system aware that a thread managed (started,
5324fee23f9Smrg    stopped) by some external code will no longer access objc and thus
5334fee23f9Smrg    can be forgotten by the objc thread system.  Call
5344fee23f9Smrg    objc_thread_remove () when your alien thread is done with making
5354fee23f9Smrg    calls to Objective-C. */
5364fee23f9Smrg void
objc_thread_remove(void)5374fee23f9Smrg objc_thread_remove (void)
5384fee23f9Smrg {
5394fee23f9Smrg   objc_mutex_lock (__objc_runtime_mutex);
5404fee23f9Smrg   __objc_runtime_threads_alive--;
5414fee23f9Smrg   objc_mutex_unlock (__objc_runtime_mutex);
5424fee23f9Smrg }
5434fee23f9Smrg 
544