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