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