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

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [libobjc/] [thr.c] - Blame information for rev 19

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 jlechner
/* 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
 
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 2, 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
You should have received a copy of the GNU General Public License along with
17
GCC; see the file COPYING.  If not, write to the Free Software
18
Foundation, 51 Franklin Street, Fifth Floor,
19
Boston, MA 02110-1301, USA.  */
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>
28
#include "objc/runtime.h"
29
 
30
/* Global exit status. */
31
int __objc_thread_exit_status = 0;
32
 
33
/* Flag which lets us know if we ever became multi threaded */
34
int __objc_is_multi_threaded = 0;
35
 
36
/* The hook function called when the runtime becomes multi threaded */
37
objc_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
  */
51
objc_thread_callback objc_set_thread_callback (objc_thread_callback func)
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
 */
71
struct __objc_thread_start_state
72
{
73
  SEL selector;
74
  id object;
75
  id argument;
76
};
77
 
78
static void __attribute__((noreturn))
79
__objc_thread_detach_function (struct __objc_thread_start_state *istate)
80
{
81
  /* Valid state? */
82
  if (istate) {
83
    id (*imp) (id, SEL, id);
84
    SEL selector = istate->selector;
85
    id object   = istate->object;
86
    id argument = istate->argument;
87
 
88
    /* Don't need anymore so free it */
89
    objc_free (istate);
90
 
91
    /* Clear out the thread local storage */
92
    objc_thread_set_data (NULL);
93
 
94
    /* Check to see if we just became multi threaded */
95
    if (! __objc_is_multi_threaded)
96
      {
97
        __objc_is_multi_threaded = 1;
98
 
99
        /* Call the hook function */
100
        if (_objc_became_multi_threaded != NULL)
101
          (*_objc_became_multi_threaded) ();
102
      }
103
 
104
    /* Call the method */
105
    if ((imp = (id (*) (id, SEL, id))objc_msg_lookup (object, selector)))
106
        (*imp) (object, selector, argument);
107
    else
108
      objc_error (object, OBJC_ERR_UNIMPLEMENTED,
109
                  "objc_thread_detach called with bad selector.\n");
110
  }
111
  else
112
    objc_error (nil, OBJC_ERR_BAD_STATE,
113
                "objc_thread_detach called with NULL state.\n");
114
 
115
  /* Exit the thread */
116
  objc_thread_exit ();
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
  */
133
objc_thread_t
134
objc_thread_detach (SEL selector, id object, id argument)
135
{
136
  struct __objc_thread_start_state *istate;
137
  objc_thread_t        thread_id = NULL;
138
 
139
  /* Allocate the state structure */
140
  if (! (istate = (struct __objc_thread_start_state *)
141
         objc_malloc (sizeof (*istate))))
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 */
150
  objc_mutex_lock (__objc_runtime_mutex);
151
 
152
  /* Call the backend to spawn the thread */
153
  if ((thread_id = __objc_thread_detach ((void *)__objc_thread_detach_function,
154
                                         istate)) == NULL)
155
    {
156
      /* failed! */
157
      objc_mutex_unlock (__objc_runtime_mutex);
158
      objc_free (istate);
159
      return NULL;
160
    }
161
 
162
  /* Increment our thread counter */
163
  __objc_runtime_threads_alive++;
164
  objc_mutex_unlock (__objc_runtime_mutex);
165
 
166
  return thread_id;
167
}
168
 
169
/* Set the current thread's priority. */
170
int
171
objc_thread_set_priority (int priority)
172
{
173
  /* Call the backend */
174
  return __objc_thread_set_priority (priority);
175
}
176
 
177
/* Return the current thread's priority. */
178
int
179
objc_thread_get_priority (void)
180
{
181
  /* Call the backend */
182
  return __objc_thread_get_priority ();
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
  */
190
void
191
objc_thread_yield (void)
192
{
193
  /* Call the backend */
194
  __objc_thread_yield ();
195
}
196
 
197
/*
198
  Terminate the current tread.  Doesn't return.
199
  Actually, if it failed returns -1.
200
  */
201
int
202
objc_thread_exit (void)
203
{
204
  /* Decrement our counter of the number of threads alive */
205
  objc_mutex_lock (__objc_runtime_mutex);
206
  __objc_runtime_threads_alive--;
207
  objc_mutex_unlock (__objc_runtime_mutex);
208
 
209
  /* Call the backend to terminate the thread */
210
  return __objc_thread_exit ();
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
  */
217
objc_thread_t
218
objc_thread_id (void)
219
{
220
  /* Call the backend */
221
  return __objc_thread_id ();
222
}
223
 
224
/*
225
  Sets the thread's local storage pointer.
226
  Returns 0 if successful or -1 if failed.
227
  */
228
int
229
objc_thread_set_data (void *value)
230
{
231
  /* Call the backend */
232
  return __objc_thread_set_data (value);
233
}
234
 
235
/*
236
  Returns the thread's local storage pointer.  Returns NULL on failure.
237
  */
238
void *
239
objc_thread_get_data (void)
240
{
241
  /* Call the backend */
242
  return __objc_thread_get_data ();
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
  */
251
objc_mutex_t
252
objc_mutex_allocate (void)
253
{
254
  objc_mutex_t mutex;
255
 
256
  /* Allocate the mutex structure */
257
  if (! (mutex = (objc_mutex_t)objc_malloc (sizeof (struct objc_mutex))))
258
    return NULL;
259
 
260
  /* Call backend to create the mutex */
261
  if (__objc_mutex_allocate (mutex))
262
    {
263
      /* failed! */
264
      objc_free (mutex);
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
  */
281
int
282
objc_mutex_deallocate (objc_mutex_t mutex)
283
{
284
  int depth;
285
 
286
  /* Valid mutex? */
287
  if (! mutex)
288
    return -1;
289
 
290
  /* Acquire lock on mutex */
291
  depth = objc_mutex_lock (mutex);
292
 
293
  /* Call backend to destroy mutex */
294
  if (__objc_mutex_deallocate (mutex))
295
    return -1;
296
 
297
  /* Free the mutex structure */
298
  objc_free (mutex);
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
  */
310
int
311
objc_mutex_lock (objc_mutex_t mutex)
312
{
313
  objc_thread_t thread_id;
314
  int status;
315
 
316
  /* Valid mutex? */
317
  if (! mutex)
318
    return -1;
319
 
320
  /* If we already own the lock then increment depth */
321
  thread_id = __objc_thread_id ();
322
  if (mutex->owner == thread_id)
323
    return ++mutex->depth;
324
 
325
  /* Call the backend to lock the mutex */
326
  status = __objc_mutex_lock (mutex);
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
  */
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 = __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 = __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
/*
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
  */
377
int
378
objc_mutex_unlock (objc_mutex_t mutex)
379
{
380
  objc_thread_t thread_id;
381
  int status;
382
 
383
  /* Valid mutex? */
384
  if (! mutex)
385
    return -1;
386
 
387
  /* If another thread owns the lock then abort */
388
  thread_id = __objc_thread_id ();
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 */
401
  status = __objc_mutex_unlock (mutex);
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
  */
416
objc_condition_t
417
objc_condition_allocate (void)
418
{
419
  objc_condition_t condition;
420
 
421
  /* Allocate the condition mutex structure */
422
  if (! (condition =
423
         (objc_condition_t) objc_malloc (sizeof (struct objc_condition))))
424
    return NULL;
425
 
426
  /* Call the backend to create the condition mutex */
427
  if (__objc_condition_allocate (condition))
428
    {
429
      /* failed! */
430
      objc_free (condition);
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
  */
445
int
446
objc_condition_deallocate (objc_condition_t condition)
447
{
448
  /* Broadcast the condition */
449
  if (objc_condition_broadcast (condition))
450
    return -1;
451
 
452
  /* Call the backend to destroy */
453
  if (__objc_condition_deallocate (condition))
454
    return -1;
455
 
456
  /* Free the condition mutex structure */
457
  objc_free (condition);
458
 
459
  return 0;
460
}
461
 
462
/*
463
  Wait on the condition unlocking the mutex until objc_condition_signal ()
464
  or objc_condition_broadcast () are called for the same condition. The
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
  */
470
int
471
objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex)
472
{
473
  objc_thread_t thread_id;
474
 
475
  /* Valid arguments? */
476
  if (! mutex || ! condition)
477
    return -1;
478
 
479
  /* Make sure we are owner of mutex */
480
  thread_id = __objc_thread_id ();
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 */
493
  __objc_condition_wait (condition, mutex);
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
  */
508
int
509
objc_condition_broadcast (objc_condition_t condition)
510
{
511
  /* Valid condition mutex? */
512
  if (! condition)
513
    return -1;
514
 
515
  return __objc_condition_broadcast (condition);
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
  */
524
int
525
objc_condition_signal (objc_condition_t condition)
526
{
527
  /* Valid condition mutex? */
528
  if (! condition)
529
    return -1;
530
 
531
  return __objc_condition_signal (condition);
532
}
533
 
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
538
   objc_thread_add () before an alien thread makes any calls to
539
   Objective-C.  Do not cause the _objc_became_multi_threaded hook to
540
   be executed. */
541
void
542
objc_thread_add (void)
543
{
544
  objc_mutex_lock (__objc_runtime_mutex);
545
  __objc_is_multi_threaded = 1;
546
  __objc_runtime_threads_alive++;
547
  objc_mutex_unlock (__objc_runtime_mutex);
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
553
   objc_thread_remove () when your alien thread is done with making
554
   calls to Objective-C. */
555
void
556
objc_thread_remove (void)
557
{
558
  objc_mutex_lock (__objc_runtime_mutex);
559
  __objc_runtime_threads_alive--;
560
  objc_mutex_unlock (__objc_runtime_mutex);
561
}
562
 
563
/* End of File */

powered by: WebSVN 2.1.0

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