OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libobjc/] [thr.c] - Blame information for rev 739

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.