OSDN Git Service

* jump.c (jump_optimize, follow_jumps, mark_jump_label): Disable some
[pf3gnuchains/gcc-fork.git] / gcc / objc / thr-pthreads.c
1 /* GNU Objective C Runtime Thread Implementation for PCThreads under Linux.
2    Copyright (C) 1996, 1997 Free Software Foundation, Inc.
3    Contributed by Scott Christley <scottc@net-community.com>
4
5 This file is part of GNU CC.
6
7 GNU CC 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 GNU CC 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
17 along with GNU CC; see the file COPYING.  If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, 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 <pthread.h>
28 #include <objc/thr.h>
29 #include "runtime.h"
30
31 /* Key structure for maintiain thread specific storage */
32 static pthread_key_t _objc_thread_storage;
33
34 /********
35  *  This structure represents a single mutual exclusion lock.  Lock semantics
36  *  are detailed with the subsequent functions.  We use whatever lock is
37  *  provided by the system.  We augment it with depth and current owner id
38  *  fields to implement and re-entrant lock.
39  */
40 struct objc_mutex 
41 {
42   volatile objc_thread_t     owner;          /* Id of thread that owns.  */
43   volatile int                depth;          /* # of acquires.           */
44   pthread_mutex_t             mutex;          /* PCThread mutex           */
45 };
46
47 struct objc_condition 
48 {
49   pthread_cond_t              condition;      /* cthread condition        */
50 };
51
52 /********
53  *  Initialize the threads subsystem.  Returns 0 if successful, or -1 if no
54  *  thread support is available.
55  */
56 int
57 __objc_init_thread_system(void)
58 {
59   /* Initialize the thread storage key */
60   return pthread_key_create(&_objc_thread_storage, NULL);
61 }
62
63 /********
64  *  Finalize the threads subsystem.  Returns 0 if successful, or -1 if not
65  */
66 int
67 __objc_fini_thread_system(void)
68 {
69   /* Destroy the thread storage key */
70   /* Not implemented yet */
71   /* return pthread_key_delete(&_objc_thread_storage); */
72   return 0;
73 }
74
75 /********
76  *  Create a new thread of execution and return its id.  Return NULL if fails.
77  *  The new thread starts in "func" with the given argument.
78  */
79 objc_thread_t
80 objc_thread_create(void (*func)(void *arg), void *arg)
81 {
82   objc_thread_t thread_id;
83   pthread_t new_thread_handle;
84
85   objc_mutex_lock(__objc_runtime_mutex);
86   
87   if ( !(pthread_create(&new_thread_handle, NULL, (void *)func, arg)) )
88     {
89       thread_id = *(objc_thread_t *)&new_thread_handle;
90       __objc_runtime_threads_alive++;
91     }
92   else
93     thread_id = NULL;
94   
95   objc_mutex_unlock(__objc_runtime_mutex);
96   
97   return thread_id;
98 }
99
100 /********
101  *  Set the current thread's priority.
102  */
103 int
104 objc_thread_set_priority(int priority)
105 {
106   /* Not implemented yet */
107   return -1;                                    /* Failed.                  */
108 }
109
110 /********
111  *  Return the current thread's priority.
112  */
113 int
114 objc_thread_get_priority(void)
115 {
116   /* Not implemented yet */
117   return OBJC_THREAD_INTERACTIVE_PRIORITY;      /* Highest priority.        */
118 }
119
120 /********
121  *  Yield our process time to another thread.  Any BUSY waiting that is done
122  *  by a thread should use this function to make sure that other threads can
123  *  make progress even on a lazy uniprocessor system.
124  */
125 void
126 objc_thread_yield(void)
127 {
128   pthread_yield(NULL);
129 }
130
131 /********
132  *  Terminate the current tread.  Doesn't return anything.  Doesn't return.
133  *  Actually, if it failed returns -1.
134  */
135 int
136 objc_thread_exit(void)
137 {
138   objc_mutex_lock(__objc_runtime_mutex);
139   __objc_runtime_threads_alive--;
140   objc_mutex_unlock(__objc_runtime_mutex);
141       
142   pthread_exit(&__objc_thread_exit_status);     /* Terminate thread.        */
143   return -1;
144 }
145
146 /********
147  *  Returns an integer value which uniquely describes a thread.  Must not be
148  *  NULL which is reserved as a marker for "no thread".
149  */
150 objc_thread_t
151 objc_thread_id(void)
152 {
153   pthread_t self = pthread_self();
154
155   return *(objc_thread_t *)&self;            /* Return thread handle.    */
156 }
157
158 /********
159  *  Sets the thread's local storage pointer.  Returns 0 if successful or -1
160  *  if failed.
161  */
162 int
163 objc_thread_set_data(void *value)
164 {
165   return pthread_setspecific(_objc_thread_storage, value);
166 }
167
168 /********
169  *  Returns the thread's local storage pointer.  Returns NULL on failure.
170  */
171 void *
172 objc_thread_get_data(void)
173 {
174   void *value = NULL;
175
176   if ( !(pthread_getspecific(_objc_thread_storage, &value)) )
177     return value;
178
179   return NULL;
180 }
181
182 /********
183  *  Allocate a mutex.  Return the mutex pointer if successful or NULL if the
184  *  allocation failed for any reason.
185  */
186 objc_mutex_t
187 objc_mutex_allocate(void)
188 {
189   objc_mutex_t mutex;
190     
191   if (!(mutex = (objc_mutex_t)objc_malloc(sizeof(struct objc_mutex))))
192     return NULL;                            /* Abort if malloc failed.  */
193
194   /* Create PCThread mutex */
195   if ( pthread_mutex_init(&(mutex->mutex), NULL) )
196     {
197       /* Failed */
198       objc_free(mutex);
199       return NULL;
200     }
201
202   mutex->owner = NULL;                        /* No owner.                */
203   mutex->depth = 0;                           /* No locks.                */
204   return mutex;                               /* Return mutex handle.     */
205 }
206
207 /********
208  *  Deallocate a mutex.  Note that this includes an implicit mutex_lock to
209  *  insure that no one else is using the lock.  It is legal to deallocate
210  *  a lock if we have a lock on it, but illegal to deallocate a lock held
211  *  by anyone else.
212  *  Returns the number of locks on the thread.  (1 for deallocate).
213  */
214 int
215 objc_mutex_deallocate(objc_mutex_t mutex)
216 {
217   int         depth;                          /* # of locks on mutex.     */
218
219   if (!mutex)                                 /* Is argument bad?         */
220     return -1;                              /* Yes, abort.              */
221   depth = objc_mutex_lock(mutex);             /* Must have lock.          */
222
223   /* Destroy PCThread mutex */
224   pthread_mutex_destroy(&(mutex->mutex));
225
226   objc_free(mutex);                           /* Free memory.             */
227   return depth;                               /* Return last depth.       */
228 }
229
230 /********
231  *  Grab a lock on a mutex.  If this thread already has a lock on this mutex
232  *  then we increment the lock count.  If another thread has a lock on the 
233  *  mutex we block and wait for the thread to release the lock.
234  *  Returns the lock count on the mutex held by this thread.
235  */
236 int
237 objc_mutex_lock(objc_mutex_t mutex)
238 {
239   objc_thread_t      thread_id;              /* Cache our thread id.     */
240   int status;
241
242   if (!mutex)                                 /* Is argument bad?         */
243     return -1;                              /* Yes, abort.              */
244   thread_id = objc_thread_id();               /* Get this thread's id.    */
245   if (mutex->owner == thread_id)              /* Already own lock?        */
246     {
247       return ++mutex->depth;                  /* Yes, increment depth.    */
248     }
249
250   /* Lock the PCThread mutex */
251   status = pthread_mutex_lock(&(mutex->mutex));
252   if (status)
253     {
254       return status;                            /* Failed */
255     }
256
257   mutex->owner = thread_id;                   /* Mark thread as owner.    */
258   return mutex->depth = 1;                    /* Increment depth to end.  */
259 }
260
261 /********
262  *  Try to grab a lock on a mutex.  If this thread already has a lock on
263  *  this mutex then we increment the lock count and return it.  If another
264  *  thread has a lock on the mutex returns -1.
265  */
266 int
267 objc_mutex_trylock(objc_mutex_t mutex)
268 {
269   objc_thread_t      thread_id;              /* Cache our thread id.     */
270   int status;
271
272   if (!mutex)                                 /* Is argument bad?         */
273     return -1;                              /* Yes, abort.              */
274   thread_id = objc_thread_id();               /* Get this thread's id.    */
275   if (mutex->owner == thread_id)              /* Already own lock?        */
276     return ++mutex->depth;                  /* Yes, increment depth.    */
277     
278   /* Lock the PCThread mutex */
279   status = pthread_mutex_trylock(&(mutex->mutex));
280   if (status)
281     return status;                            /* Failed */
282
283   mutex->owner = thread_id;                   /* Mark thread as owner.    */
284   return mutex->depth = 1;                    /* Increment depth to end.  */
285 }
286
287 /********
288  *  Decrements the lock count on this mutex by one.  If the lock count reaches
289  *  zero, release the lock on the mutex.  Returns the lock count on the mutex.
290  *  It is an error to attempt to unlock a mutex which this thread doesn't hold
291  *  in which case return -1 and the mutex is unaffected.
292  *  Will also return -1 if the mutex free fails.
293  */
294 int
295 objc_mutex_unlock(objc_mutex_t mutex)
296 {
297   objc_thread_t thread_id;                   /* Cache our thread id.     */
298   int status;
299     
300   if (!mutex)                                 /* Is argument bad?         */
301     return -1;                              /* Yes, abort.              */
302   thread_id = objc_thread_id();               /* Get this thread's id.    */
303   if (mutex->owner != thread_id)              /* Does some else own lock? */
304     return -1;                              /* Yes, abort.              */
305   if (mutex->depth > 1)                       /* Released last lock?      */
306     return --mutex->depth;                  /* No, Decrement depth, end.*/
307   mutex->depth = 0;                           /* Yes, reset depth to 0.   */
308   mutex->owner = NULL;                        /* Set owner to "no thread".*/
309
310   /* Unlock the PCThread mutex */
311   status = pthread_mutex_unlock(&(mutex->mutex));
312   if (status)
313     return status;                            /* Failed */
314
315   return 0;                                   /* No, return success.      */
316 }
317
318 /********
319  *  Allocate a condition.  Return the condition pointer if successful or NULL
320  * if the allocation failed for any reason.
321  */
322 objc_condition_t 
323 objc_condition_allocate(void)
324 {
325     objc_condition_t condition;
326     
327     if (!(condition = (objc_condition_t)objc_malloc(
328                         sizeof(struct objc_condition))))
329         return NULL;                            /* Abort if malloc failed.  */
330
331         if ( pthread_cond_init(&(condition->condition), NULL) ) {
332                 objc_free(condition);
333                 return NULL;
334         }
335     
336     return condition;                           /* Return condition handle. */
337 }
338
339 /********
340  *  Deallocate a condition. Note that this includes an implicit 
341  *  condition_broadcast to insure that waiting threads have the opportunity
342  *  to wake.  It is legal to dealloc a condition only if no other
343  *  thread is/will be using it. Here we do NOT check for other threads
344  *  waiting but just wake them up.
345  */
346 int
347 objc_condition_deallocate(objc_condition_t condition)
348 {
349         pthread_cond_broadcast(&(condition->condition));
350         pthread_cond_destroy(&(condition->condition));
351         objc_free(condition);
352         return 0;
353 }
354
355 /********
356  *  Wait on the condition unlocking the mutex until objc_condition_signal()
357  *  or objc_condition_broadcast() are called for the same condition. The
358  *  given mutex *must* have the depth set to 1 so that it can be unlocked
359  *  here, so that someone else can lock it and signal/broadcast the condition.
360  *  The mutex is used to lock access to the shared data that make up the
361  *  "condition" predicate.
362  */
363 int
364 objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
365 {
366     objc_thread_t    thread_id;                /* Cache our thread id.     */
367     
368     if (!mutex || !condition)                   /* Is argument bad?         */
369         return -1;                              /* Yes, abort.              */
370
371     thread_id = objc_thread_id();               /* Get this thread's id.    */
372     if (mutex->owner != thread_id)              /* Does some else own lock? */
373         return -1;                              /* Yes, abort.              */
374     if (mutex->depth > 1)                       /* Locked more than once ?  */
375         return -1;                              /* YES, return error        */
376                                                 /* mutex will be unlocked   */
377     mutex->depth = 0;                           /* Yes, reset depth to 0.   */
378     mutex->owner = (objc_thread_t) -1;         /* Set owner to "no thread".*/
379     
380     pthread_cond_wait(&(condition->condition),
381                 &(mutex->mutex));               /* unlock, wait ..., lock   */
382     
383     mutex->owner = thread_id;                   /* Mark thread as owner.    */
384     mutex->depth = 1;                           /* Increment depth to end.  */
385     return 0;                                   /* Return success.          */
386 }
387
388 /********
389  *  Wake up all threads waiting on this condition. It is recommended that 
390  *  the called would lock the same mutex as the threads in objc_condition_wait
391  *  before changing the "condition predicate" and make this call and unlock it
392  *  right away after this call.
393  */
394 int
395 objc_condition_broadcast(objc_condition_t condition)
396 {
397     if (!condition)
398                 return -1;
399         pthread_cond_broadcast(&(condition->condition));
400         return 0;
401 }
402
403 /********
404  *  Wake up one thread waiting on this condition. It is recommended that 
405  *  the called would lock the same mutex as the threads in objc_condition_wait
406  *  before changing the "condition predicate" and make this call and unlock it
407  *  right away after this call.
408  */
409 int
410 objc_condition_signal(objc_condition_t condition)
411 {
412     if (!condition)
413                 return -1;
414         pthread_cond_signal(&(condition->condition));
415         return 0;
416 }
417
418 /* End of File */