OSDN Git Service

Replace use of __objc_xmalloc and free with objc_malloc and objc_free.
[pf3gnuchains/gcc-fork.git] / gcc / objc / thr-posix.c
1 /* GNU Objective C Runtime Thread Interface for POSIX compliant threads
2    Copyright (C) 1996 Free Software Foundation, Inc.
3    Contributed by Galen C. Hunt (gchunt@cs.rochester.edu)
4    Modified for Linux/Pthreads by Kai-Uwe Sattler (kus@iti.cs.uni-magdeburg.de)
5
6 This file is part of GNU CC.
7
8 GNU CC is free software; you can redistribute it and/or modify it under the
9 terms of the GNU General Public License as published by the Free Software
10 Foundation; either version 2, or (at your option) any later version.
11
12 GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
15 details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU CC; see the file COPYING.  If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.  */
21
22 /* As a special exception, if you link this library with files compiled with
23    GCC to produce an executable, this does not cause the resulting executable
24    to be covered by the GNU General Public License. This exception does not
25    however invalidate any other reasons why the executable file might be
26    covered by the GNU General Public License.  */
27
28 #include <objc/thr.h>
29 #include "runtime.h"
30 #include <pthread.h>
31
32 /********
33  *  This structure represents a single mutual exclusion lock.  Lock semantics
34  *  are detailed with the subsequent functions.  We use whatever lock is
35  *  provided by the system.  We augment it with depth and current owner id
36  *  fields to implement and re-entrant lock.
37  */
38 struct _objc_mutex 
39 {
40     volatile _objc_thread_t     owner;          /* Id of thread that owns.  */
41     volatile int                depth;          /* # of acquires.           */
42     pthread_mutex_t             lock;           /* pthread mutex.           */
43 };
44
45 /*****************************************************************************
46  *  Static variables.
47  */
48 static pthread_key_t    __objc_thread_data_key; /* Data key for thread data.*/
49
50
51 /********
52  *  Initialize the threads subsystem.  Returns 0 if successful, or -1 if no
53  *  thread support is available.
54  */
55 int
56 __objc_init_thread_system(void)
57 {
58     if (pthread_key_create(&__objc_thread_data_key, NULL) == 0)
59         return 0;                               /* Yes, return success.     */
60     
61     return -1;                                  /* Failed.                  */
62 }
63
64 int
65 __objc_fini_thread_system(void)
66 {
67   return 0;
68 }
69
70 /********
71  *  Create a new thread of execution and return its id.  Return NULL if fails.
72  *  The new thread starts in "func" with the given argument.
73  */
74 _objc_thread_t
75 objc_thread_create(void (*func)(void *arg), void *arg)
76 {
77     _objc_thread_t      thread_id = NULL;       /* Detached thread id.      */
78     pthread_t           new_thread_handle;      /* DCE thread handle.       */
79
80     objc_mutex_lock(__objc_runtime_mutex);
81
82     if (pthread_create(&new_thread_handle, NULL,
83                        (void *)func, arg) == 0) {
84         thread_id = (_objc_thread_t) new_thread_handle;
85         pthread_detach(new_thread_handle);     /* Fully detach thread.     */
86         __objc_runtime_threads_alive++;
87     }
88     
89     objc_mutex_unlock(__objc_runtime_mutex);
90     return thread_id;
91 }
92
93 /********
94  *  Set the current thread's priority.
95  */
96 int
97 objc_thread_set_priority(int priority)
98 {
99 #if 0 /* no get/set priority in Linux pthreads */
100
101     int         sys_priority = 0;
102
103     switch (priority) {
104     case OBJC_THREAD_INTERACTIVE_PRIORITY:
105         sys_priority = (PRI_FG_MIN_NP + PRI_FG_MAX_NP) / 2;
106         break;
107     default:
108     case OBJC_THREAD_BACKGROUND_PRIORITY:
109         sys_priority = (PRI_BG_MIN_NP + PRI_BG_MAX_NP) / 2;
110         break;
111     case OBJC_THREAD_LOW_PRIORITY:
112         sys_priority = (PRI_BG_MIN_NP + PRI_BG_MAX_NP) / 2;
113         break;
114     }
115     
116     if (pthread_setprio(pthread_self(), sys_priority) >= 0)
117         return 0;                               /* Changed priority. End.   */
118     
119 #endif
120     return -1;                                  /* Failed.                  */
121 }
122
123 /********
124  *  Return the current thread's priority.
125  */
126 int
127 objc_thread_get_priority(void)
128 {
129 #if 0 /* no get/set priority in Linux pthreads */
130     int         sys_priority;                   /* DCE thread priority.     */
131     
132     if ((sys_priority = pthread_getprio(pthread_self())) >= 0) {
133         if (sys_priority >= PRI_FG_MIN_NP && sys_priority <= PRI_FG_MAX_NP)
134             return OBJC_THREAD_INTERACTIVE_PRIORITY;
135         if (sys_priority >= PRI_BG_MIN_NP && sys_priority <= PRI_BG_MAX_NP)
136             return OBJC_THREAD_BACKGROUND_PRIORITY;
137         return OBJC_THREAD_LOW_PRIORITY;
138     }
139 #endif
140     return -1;                                  /* Couldn't get priority.   */
141 }
142
143 /********
144  *  Yield our process time to another thread.  Any BUSY waiting that is done
145  *  by a thread should use this function to make sure that other threads can
146  *  make progress even on a lazy uniprocessor system.
147  */
148 void
149 objc_thread_yield(void)
150 {
151     pthread_yield();                            /* Yield to equal thread.   */
152 }
153
154 /********
155  *  Terminate the current tread.  Doesn't return anything.  Doesn't return.
156  *  Actually, if it failed returns -1.
157  */
158 int
159 objc_thread_exit(void)
160 {
161   objc_mutex_lock(__objc_runtime_mutex);
162   __objc_runtime_threads_alive--;
163   objc_mutex_unlock(__objc_runtime_mutex);
164       
165   pthread_exit(&__objc_thread_exit_status);     /* Terminate thread.        */
166   return -1;
167 }
168
169 /********
170  *  Returns an integer value which uniquely describes a thread.  Must not be
171  *  -1 which is reserved as a marker for "no thread".
172  */
173 _objc_thread_t
174 objc_thread_id(void)
175 {
176   pthread_t self = pthread_self();
177
178   return (_objc_thread_t) self;               /* Return thread handle.    */
179 }
180
181 /********
182  *  Sets the thread's local storage pointer.  Returns 0 if successful or -1
183  *  if failed.
184  */
185 int
186 objc_thread_set_data(void *value)
187 {
188     if (pthread_setspecific(__objc_thread_data_key, (void *)value) == 0)
189         return 0;                               /* Return thread data.      */
190     return -1;
191 }
192
193 /********
194  *  Returns the thread's local storage pointer.  Returns NULL on failure.
195  */
196 void *
197 objc_thread_get_data(void)
198 {
199     return pthread_getspecific(__objc_thread_data_key);
200 }
201
202 /********
203  *  Allocate a mutex.  Return the mutex pointer if successful or NULL if
204  *  the allocation fails for any reason.
205  */
206 _objc_mutex_t
207 objc_mutex_allocate(void)
208 {
209     _objc_mutex_t mutex;
210     int         err = 0;
211     
212     if (!(mutex = (_objc_mutex_t) objc_malloc(sizeof(struct _objc_mutex))))
213         return NULL;                            /* Abort if malloc failed.  */
214
215     err = pthread_mutex_init(&mutex->lock, NULL);
216     
217     if (err != 0) {                             /* System init failed?      */
218         objc_free(mutex);                       /* Yes, free local memory.  */
219         return NULL;                            /* Abort.                   */
220     }
221     mutex->owner = NULL;                        /* No owner.                */
222     mutex->depth = 0;                           /* No locks.                */
223     return mutex;                               /* Return mutex handle.     */
224 }
225
226 /********
227  *  Deallocate a mutex.  Note that this includes an implicit mutex_lock to
228  *  insure that no one else is using the lock.  It is legal to deallocate
229  *  a lock if we have a lock on it, but illegal to deallotcate a lock held
230  *  by anyone else.
231  *  Returns the number of locks on the thread.  (1 for deallocate).
232  */
233 int
234 objc_mutex_deallocate(_objc_mutex_t mutex)
235 {
236     int         depth;                          /* # of locks on mutex.     */
237
238     if (!mutex)                                 /* Is argument bad?         */
239         return -1;                              /* Yes, abort.              */
240     depth = objc_mutex_lock(mutex);             /* Must have lock.          */
241     
242     pthread_mutex_unlock(&mutex->lock);         /* Must unlock system mutex.*/
243     pthread_mutex_destroy(&mutex->lock);        /* Free system mutex.       */
244     
245     objc_free(mutex);                           /* Free memory.             */
246     return depth;                               /* Return last depth.       */
247 }
248
249 /********
250  *  Grab a lock on a mutex.  If this thread already has a lock on this mutex
251  *  then we increment the lock count.  If another thread has a lock on the 
252  *  mutex we block and wait for the thread to release the lock.
253  *  Returns the lock count on the mutex held by this thread.
254  */
255 int
256 objc_mutex_lock(_objc_mutex_t mutex)
257 {
258     _objc_thread_t     thread_id;                /* Cache our thread id. */
259
260     if (!mutex)                                 /* Is argument bad?         */
261         return -1;                              /* Yes, abort.              */
262     thread_id = objc_thread_id();               /* Get this thread's id.    */
263     if (mutex->owner == thread_id)              /* Already own lock?        */
264         return ++mutex->depth;                  /* Yes, increment depth.    */
265
266     if (pthread_mutex_lock(&mutex->lock) != 0)  /* Lock DCE system mutex.   */
267         return -1;                              /* Failed, abort.           */
268     
269     mutex->owner = thread_id;                   /* Mark thread as owner.    */
270     return mutex->depth = 1;                    /* Increment depth to end.  */
271 }
272
273 /********
274  *  Try to grab a lock on a mutex.  If this thread already has a lock on
275  *  this mutex then we increment the lock count and return it.  If another
276  *  thread has a lock on the mutex returns -1.
277  */
278 int
279 objc_mutex_trylock(_objc_mutex_t mutex)
280 {
281     _objc_thread_t    thread_id;                 /* Cache our thread id. */
282
283     if (!mutex)                                 /* Is argument bad?         */
284         return -1;                              /* Yes, abort.              */
285     thread_id = objc_thread_id();               /* Get this thread's id.    */
286     if (mutex->owner == thread_id)              /* Already own lock?        */
287         return ++mutex->depth;                  /* Yes, increment depth.    */
288     
289     if (pthread_mutex_trylock(&mutex->lock) != 1) /* Lock DCE system mutex. */
290         return -1;                              /* Failed, abort.           */
291     
292     mutex->owner = thread_id;                   /* Mark thread as owner.    */
293     return mutex->depth = 1;                    /* Increment depth to end.  */
294 }
295
296 /********
297  *  Decrements the lock count on this mutex by one.  If the lock count reaches
298  *  zero, release the lock on the mutex.  Returns the lock count on the mutex.
299  *  It is an error to attempt to unlock a mutex which this thread doesn't hold
300  *  in which case return -1 and the mutex is unaffected.
301  *  Will also return -1 if the mutex free fails.
302  */
303 int
304 objc_mutex_unlock(_objc_mutex_t mutex)
305 {
306     _objc_thread_t   thread_id;                 /* Cache our thread id.     */
307     
308     if (!mutex)                                 /* Is argument bad?         */
309         return -1;                              /* Yes, abort.              */
310     thread_id = objc_thread_id();               /* Get this thread's id.    */
311     if (mutex->owner != thread_id)              /* Does some else own lock? */
312         return -1;                              /* Yes, abort.              */
313     if (mutex->depth > 1)                       /* Released last lock?      */
314         return --mutex->depth;                  /* No, Decrement depth, end.*/
315     mutex->depth = 0;                           /* Yes, reset depth to 0.   */
316     mutex->owner = NULL;                        /* Set owner to "no thread".*/
317     
318     if (pthread_mutex_unlock(&mutex->lock) != 0)  /* Unlock system mutex.   */
319         return -1;                              /* Failed, abort.           */
320     
321     return 0;                                   /* No, return success.      */
322 }