2010-09-09 Gerald Pfeifer <gerald@pfeifer.com>
[official-gcc.git] / libobjc / thr.c
blob4bdbb5d1a2760380523af9154368e2a8658c0bff
1 /* GNU Objective C Runtime Thread Interface
2 Copyright (C) 1996, 1997, 2009, 2010 Free Software Foundation, Inc.
3 Contributed by Galen C. Hunt (gchunt@cs.rochester.edu)
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under the
8 terms of the GNU General Public License as published by the Free Software
9 Foundation; either version 3, or (at your option) any later version.
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14 details.
16 Under Section 7 of GPL version 3, you are granted additional
17 permissions described in the GCC Runtime Library Exception, version
18 3.1, as published by the Free Software Foundation.
20 You should have received a copy of the GNU General Public License and
21 a copy of the GCC Runtime Library Exception along with this program;
22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 <http://www.gnu.org/licenses/>. */
25 #define _LIBOBJC
26 /* The line below is needed for declarations of functions such as
27 pthread_mutexattr_settype, without which gthr-posix.h may fail to
28 compile within libobjc. Unfortunately, this breaks compilation on
29 Tru64 UNIX V4.0F, so disable it there. */
30 #ifndef __osf__
31 #define _XOPEN_SOURCE 500
32 #endif
33 #include "config.h"
34 #include "tconfig.h"
35 #include "coretypes.h"
36 #include "tm.h"
37 #include "defaults.h"
38 #include "objc/thr.h"
39 #include "objc/runtime.h"
40 #include <gthr.h>
42 #include <stdlib.h>
44 /* Global exit status. */
45 int __objc_thread_exit_status = 0;
47 /* Flag which lets us know if we ever became multi threaded */
48 int __objc_is_multi_threaded = 0;
50 /* The hook function called when the runtime becomes multi threaded */
51 objc_thread_callback _objc_became_multi_threaded = NULL;
54 Use this to set the hook function that will be called when the
55 runtime initially becomes multi threaded.
56 The hook function is only called once, meaning only when the
57 2nd thread is spawned, not for each and every thread.
59 It returns the previous hook function or NULL if there is none.
61 A program outside of the runtime could set this to some function so
62 it can be informed; for example, the GNUstep Base Library sets it
63 so it can implement the NSBecomingMultiThreaded notification.
65 objc_thread_callback objc_set_thread_callback (objc_thread_callback func)
67 objc_thread_callback temp = _objc_became_multi_threaded;
68 _objc_became_multi_threaded = func;
69 return temp;
73 Private functions
75 These functions are utilized by the frontend, but they are not
76 considered part of the public interface.
79 /* Initialize the threads subsystem. */
80 int
81 __objc_init_thread_system(void)
83 return __gthread_objc_init_thread_system ();
87 First function called in a thread, starts everything else.
89 This function is passed to the backend by objc_thread_detach
90 as the starting function for a new thread.
92 struct __objc_thread_start_state
94 SEL selector;
95 id object;
96 id argument;
99 static void __attribute__((noreturn))
100 __objc_thread_detach_function (struct __objc_thread_start_state *istate)
102 /* Valid state? */
103 if (istate) {
104 id (*imp) (id, SEL, id);
105 SEL selector = istate->selector;
106 id object = istate->object;
107 id argument = istate->argument;
109 /* Don't need anymore so free it */
110 objc_free (istate);
112 /* Clear out the thread local storage */
113 objc_thread_set_data (NULL);
115 /* Check to see if we just became multi threaded */
116 if (! __objc_is_multi_threaded)
118 __objc_is_multi_threaded = 1;
120 /* Call the hook function */
121 if (_objc_became_multi_threaded != NULL)
122 (*_objc_became_multi_threaded) ();
125 /* Call the method */
126 if ((imp = (id (*) (id, SEL, id))objc_msg_lookup (object, selector)))
127 (*imp) (object, selector, argument);
128 else
129 objc_error (object, OBJC_ERR_UNIMPLEMENTED,
130 "objc_thread_detach called with bad selector.\n");
132 else
133 objc_error (nil, OBJC_ERR_BAD_STATE,
134 "objc_thread_detach called with NULL state.\n");
136 /* Exit the thread */
137 objc_thread_exit ();
139 /* Make sure compiler detects no return. */
140 __builtin_trap ();
144 Frontend functions
146 These functions constitute the public interface to the Objective-C thread
147 and mutex functionality.
150 /* Frontend thread functions */
153 Detach a new thread of execution and return its id. Returns NULL if fails.
154 Thread is started by sending message with selector to object. Message
155 takes a single argument.
157 objc_thread_t
158 objc_thread_detach (SEL selector, id object, id argument)
160 struct __objc_thread_start_state *istate;
161 objc_thread_t thread_id = NULL;
163 /* Allocate the state structure */
164 if (! (istate = (struct __objc_thread_start_state *)
165 objc_malloc (sizeof (*istate))))
166 return NULL;
168 /* Initialize the state structure */
169 istate->selector = selector;
170 istate->object = object;
171 istate->argument = argument;
173 /* lock access */
174 objc_mutex_lock (__objc_runtime_mutex);
176 /* Call the backend to spawn the thread */
177 if ((thread_id = __gthread_objc_thread_detach ((void *)__objc_thread_detach_function,
178 istate)) == NULL)
180 /* failed! */
181 objc_mutex_unlock (__objc_runtime_mutex);
182 objc_free (istate);
183 return NULL;
186 /* Increment our thread counter */
187 __objc_runtime_threads_alive++;
188 objc_mutex_unlock (__objc_runtime_mutex);
190 return thread_id;
193 /* Set the current thread's priority. */
195 objc_thread_set_priority (int priority)
197 /* Call the backend */
198 return __gthread_objc_thread_set_priority (priority);
201 /* Return the current thread's priority. */
203 objc_thread_get_priority (void)
205 /* Call the backend */
206 return __gthread_objc_thread_get_priority ();
210 Yield our process time to another thread. Any BUSY waiting that is done
211 by a thread should use this function to make sure that other threads can
212 make progress even on a lazy uniprocessor system.
214 void
215 objc_thread_yield (void)
217 /* Call the backend */
218 __gthread_objc_thread_yield ();
222 Terminate the current tread. Doesn't return.
223 Actually, if it failed returns -1.
226 objc_thread_exit (void)
228 /* Decrement our counter of the number of threads alive */
229 objc_mutex_lock (__objc_runtime_mutex);
230 __objc_runtime_threads_alive--;
231 objc_mutex_unlock (__objc_runtime_mutex);
233 /* Call the backend to terminate the thread */
234 return __gthread_objc_thread_exit ();
238 Returns an integer value which uniquely describes a thread. Must not be
239 NULL which is reserved as a marker for "no thread".
241 objc_thread_t
242 objc_thread_id (void)
244 /* Call the backend */
245 return __gthread_objc_thread_id ();
249 Sets the thread's local storage pointer.
250 Returns 0 if successful or -1 if failed.
253 objc_thread_set_data (void *value)
255 /* Call the backend */
256 return __gthread_objc_thread_set_data (value);
260 Returns the thread's local storage pointer. Returns NULL on failure.
262 void *
263 objc_thread_get_data (void)
265 /* Call the backend */
266 return __gthread_objc_thread_get_data ();
269 /* Frontend mutex functions */
272 Allocate a mutex. Return the mutex pointer if successful or NULL if the
273 allocation failed for any reason.
275 objc_mutex_t
276 objc_mutex_allocate (void)
278 objc_mutex_t mutex;
280 /* Allocate the mutex structure */
281 if (! (mutex = (objc_mutex_t)objc_malloc (sizeof (struct objc_mutex))))
282 return NULL;
284 /* Call backend to create the mutex */
285 if (__gthread_objc_mutex_allocate (mutex))
287 /* failed! */
288 objc_free (mutex);
289 return NULL;
292 /* Initialize mutex */
293 mutex->owner = NULL;
294 mutex->depth = 0;
295 return mutex;
299 Deallocate a mutex. Note that this includes an implicit mutex_lock to
300 insure that no one else is using the lock. It is legal to deallocate
301 a lock if we have a lock on it, but illegal to deallocate a lock held
302 by anyone else.
303 Returns the number of locks on the thread. (1 for deallocate).
306 objc_mutex_deallocate (objc_mutex_t mutex)
308 int depth;
310 /* Valid mutex? */
311 if (! mutex)
312 return -1;
314 /* Acquire lock on mutex */
315 depth = objc_mutex_lock (mutex);
317 /* Call backend to destroy mutex */
318 if (__gthread_objc_mutex_deallocate (mutex))
319 return -1;
321 /* Free the mutex structure */
322 objc_free (mutex);
324 /* Return last depth */
325 return depth;
329 Grab a lock on a mutex. If this thread already has a lock on this mutex
330 then we increment the lock count. If another thread has a lock on the
331 mutex we block and wait for the thread to release the lock.
332 Returns the lock count on the mutex held by this thread.
335 objc_mutex_lock (objc_mutex_t mutex)
337 objc_thread_t thread_id;
338 int status;
340 /* Valid mutex? */
341 if (! mutex)
342 return -1;
344 /* If we already own the lock then increment depth */
345 thread_id = __gthread_objc_thread_id ();
346 if (mutex->owner == thread_id)
347 return ++mutex->depth;
349 /* Call the backend to lock the mutex */
350 status = __gthread_objc_mutex_lock (mutex);
352 /* Failed? */
353 if (status)
354 return status;
356 /* Successfully locked the thread */
357 mutex->owner = thread_id;
358 return mutex->depth = 1;
362 Try to grab a lock on a mutex. If this thread already has a lock on
363 this mutex then we increment the lock count and return it. If another
364 thread has a lock on the mutex returns -1.
367 objc_mutex_trylock (objc_mutex_t mutex)
369 objc_thread_t thread_id;
370 int status;
372 /* Valid mutex? */
373 if (! mutex)
374 return -1;
376 /* If we already own the lock then increment depth */
377 thread_id = __gthread_objc_thread_id ();
378 if (mutex->owner == thread_id)
379 return ++mutex->depth;
381 /* Call the backend to try to lock the mutex */
382 status = __gthread_objc_mutex_trylock (mutex);
384 /* Failed? */
385 if (status)
386 return status;
388 /* Successfully locked the thread */
389 mutex->owner = thread_id;
390 return mutex->depth = 1;
394 Unlocks the mutex by one level.
395 Decrements the lock count on this mutex by one.
396 If the lock count reaches zero, release the lock on the mutex.
397 Returns the lock count on the mutex.
398 It is an error to attempt to unlock a mutex which this thread
399 doesn't hold in which case return -1 and the mutex is unaffected.
402 objc_mutex_unlock (objc_mutex_t mutex)
404 objc_thread_t thread_id;
405 int status;
407 /* Valid mutex? */
408 if (! mutex)
409 return -1;
411 /* If another thread owns the lock then abort */
412 thread_id = __gthread_objc_thread_id ();
413 if (mutex->owner != thread_id)
414 return -1;
416 /* Decrement depth and return */
417 if (mutex->depth > 1)
418 return --mutex->depth;
420 /* Depth down to zero so we are no longer the owner */
421 mutex->depth = 0;
422 mutex->owner = NULL;
424 /* Have the backend unlock the mutex */
425 status = __gthread_objc_mutex_unlock (mutex);
427 /* Failed? */
428 if (status)
429 return status;
431 return 0;
434 /* Frontend condition mutex functions */
437 Allocate a condition. Return the condition pointer if successful or NULL
438 if the allocation failed for any reason.
440 objc_condition_t
441 objc_condition_allocate (void)
443 objc_condition_t condition;
445 /* Allocate the condition mutex structure */
446 if (! (condition =
447 (objc_condition_t) objc_malloc (sizeof (struct objc_condition))))
448 return NULL;
450 /* Call the backend to create the condition mutex */
451 if (__gthread_objc_condition_allocate (condition))
453 /* failed! */
454 objc_free (condition);
455 return NULL;
458 /* Success! */
459 return condition;
463 Deallocate a condition. Note that this includes an implicit
464 condition_broadcast to insure that waiting threads have the opportunity
465 to wake. It is legal to dealloc a condition only if no other
466 thread is/will be using it. Here we do NOT check for other threads
467 waiting but just wake them up.
470 objc_condition_deallocate (objc_condition_t condition)
472 /* Broadcast the condition */
473 if (objc_condition_broadcast (condition))
474 return -1;
476 /* Call the backend to destroy */
477 if (__gthread_objc_condition_deallocate (condition))
478 return -1;
480 /* Free the condition mutex structure */
481 objc_free (condition);
483 return 0;
487 Wait on the condition unlocking the mutex until objc_condition_signal ()
488 or objc_condition_broadcast () are called for the same condition. The
489 given mutex *must* have the depth set to 1 so that it can be unlocked
490 here, so that someone else can lock it and signal/broadcast the condition.
491 The mutex is used to lock access to the shared data that make up the
492 "condition" predicate.
495 objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex)
497 objc_thread_t thread_id;
499 /* Valid arguments? */
500 if (! mutex || ! condition)
501 return -1;
503 /* Make sure we are owner of mutex */
504 thread_id = __gthread_objc_thread_id ();
505 if (mutex->owner != thread_id)
506 return -1;
508 /* Cannot be locked more than once */
509 if (mutex->depth > 1)
510 return -1;
512 /* Virtually unlock the mutex */
513 mutex->depth = 0;
514 mutex->owner = (objc_thread_t)NULL;
516 /* Call the backend to wait */
517 __gthread_objc_condition_wait (condition, mutex);
519 /* Make ourselves owner of the mutex */
520 mutex->owner = thread_id;
521 mutex->depth = 1;
523 return 0;
527 Wake up all threads waiting on this condition. It is recommended that
528 the called would lock the same mutex as the threads in objc_condition_wait
529 before changing the "condition predicate" and make this call and unlock it
530 right away after this call.
533 objc_condition_broadcast (objc_condition_t condition)
535 /* Valid condition mutex? */
536 if (! condition)
537 return -1;
539 return __gthread_objc_condition_broadcast (condition);
543 Wake up one thread waiting on this condition. It is recommended that
544 the called would lock the same mutex as the threads in objc_condition_wait
545 before changing the "condition predicate" and make this call and unlock it
546 right away after this call.
549 objc_condition_signal (objc_condition_t condition)
551 /* Valid condition mutex? */
552 if (! condition)
553 return -1;
555 return __gthread_objc_condition_signal (condition);
558 /* Make the objc thread system aware that a thread which is managed
559 (started, stopped) by external code could access objc facilities
560 from now on. This is used when you are interfacing with some
561 external non-objc-based environment/system - you must call
562 objc_thread_add () before an alien thread makes any calls to
563 Objective-C. Do not cause the _objc_became_multi_threaded hook to
564 be executed. */
565 void
566 objc_thread_add (void)
568 objc_mutex_lock (__objc_runtime_mutex);
569 __objc_is_multi_threaded = 1;
570 __objc_runtime_threads_alive++;
571 objc_mutex_unlock (__objc_runtime_mutex);
574 /* Make the objc thread system aware that a thread managed (started,
575 stopped) by some external code will no longer access objc and thus
576 can be forgotten by the objc thread system. Call
577 objc_thread_remove () when your alien thread is done with making
578 calls to Objective-C. */
579 void
580 objc_thread_remove (void)
582 objc_mutex_lock (__objc_runtime_mutex);
583 __objc_runtime_threads_alive--;
584 objc_mutex_unlock (__objc_runtime_mutex);
587 /* End of File */