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