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