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