annotate libobjc/thr.c @ 158:494b0b89df80 default tip

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