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)
6 This file is part of GNU CC.
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.
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
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. */
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. */
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.
40 volatile _objc_thread_t owner; /* Id of thread that owns. */
41 volatile int depth; /* # of acquires. */
42 pthread_mutex_t lock; /* pthread mutex. */
45 /*****************************************************************************
48 static pthread_key_t __objc_thread_data_key; /* Data key for thread data.*/
52 * Initialize the threads subsystem. Returns 0 if successful, or -1 if no
53 * thread support is available.
56 __objc_init_thread_system(void)
58 if (pthread_key_create(&__objc_thread_data_key, NULL) == 0)
59 return 0; /* Yes, return success. */
61 return -1; /* Failed. */
65 __objc_fini_thread_system(void)
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.
75 objc_thread_create(void (*func)(void *arg), void *arg)
77 _objc_thread_t thread_id = NULL; /* Detached thread id. */
78 pthread_t new_thread_handle; /* DCE thread handle. */
80 objc_mutex_lock(__objc_runtime_mutex);
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++;
89 objc_mutex_unlock(__objc_runtime_mutex);
94 * Set the current thread's priority.
97 objc_thread_set_priority(int priority)
99 #if 0 /* no get/set priority in Linux pthreads */
101 int sys_priority = 0;
104 case OBJC_THREAD_INTERACTIVE_PRIORITY:
105 sys_priority = (PRI_FG_MIN_NP + PRI_FG_MAX_NP) / 2;
108 case OBJC_THREAD_BACKGROUND_PRIORITY:
109 sys_priority = (PRI_BG_MIN_NP + PRI_BG_MAX_NP) / 2;
111 case OBJC_THREAD_LOW_PRIORITY:
112 sys_priority = (PRI_BG_MIN_NP + PRI_BG_MAX_NP) / 2;
116 if (pthread_setprio(pthread_self(), sys_priority) >= 0)
117 return 0; /* Changed priority. End. */
120 return -1; /* Failed. */
124 * Return the current thread's priority.
127 objc_thread_get_priority(void)
129 #if 0 /* no get/set priority in Linux pthreads */
130 int sys_priority; /* DCE thread priority. */
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;
140 return -1; /* Couldn't get priority. */
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.
149 objc_thread_yield(void)
151 pthread_yield(); /* Yield to equal thread. */
155 * Terminate the current tread. Doesn't return anything. Doesn't return.
156 * Actually, if it failed returns -1.
159 objc_thread_exit(void)
161 objc_mutex_lock(__objc_runtime_mutex);
162 __objc_runtime_threads_alive--;
163 objc_mutex_unlock(__objc_runtime_mutex);
165 pthread_exit(&__objc_thread_exit_status); /* Terminate thread. */
170 * Returns an integer value which uniquely describes a thread. Must not be
171 * -1 which is reserved as a marker for "no thread".
176 pthread_t self = pthread_self();
178 return (_objc_thread_t) self; /* Return thread handle. */
182 * Sets the thread's local storage pointer. Returns 0 if successful or -1
186 objc_thread_set_data(void *value)
188 if (pthread_setspecific(__objc_thread_data_key, (void *)value) == 0)
189 return 0; /* Return thread data. */
194 * Returns the thread's local storage pointer. Returns NULL on failure.
197 objc_thread_get_data(void)
199 return pthread_getspecific(__objc_thread_data_key);
203 * Allocate a mutex. Return the mutex pointer if successful or NULL if
204 * the allocation fails for any reason.
207 objc_mutex_allocate(void)
212 if (!(mutex = (_objc_mutex_t) objc_malloc(sizeof(struct _objc_mutex))))
213 return NULL; /* Abort if malloc failed. */
215 err = pthread_mutex_init(&mutex->lock, NULL);
217 if (err != 0) { /* System init failed? */
218 objc_free(mutex); /* Yes, free local memory. */
219 return NULL; /* Abort. */
221 mutex->owner = NULL; /* No owner. */
222 mutex->depth = 0; /* No locks. */
223 return mutex; /* Return mutex handle. */
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
231 * Returns the number of locks on the thread. (1 for deallocate).
234 objc_mutex_deallocate(_objc_mutex_t mutex)
236 int depth; /* # of locks on mutex. */
238 if (!mutex) /* Is argument bad? */
239 return -1; /* Yes, abort. */
240 depth = objc_mutex_lock(mutex); /* Must have lock. */
242 pthread_mutex_unlock(&mutex->lock); /* Must unlock system mutex.*/
243 pthread_mutex_destroy(&mutex->lock); /* Free system mutex. */
245 objc_free(mutex); /* Free memory. */
246 return depth; /* Return last depth. */
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.
256 objc_mutex_lock(_objc_mutex_t mutex)
258 _objc_thread_t thread_id; /* Cache our thread id. */
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. */
266 if (pthread_mutex_lock(&mutex->lock) != 0) /* Lock DCE system mutex. */
267 return -1; /* Failed, abort. */
269 mutex->owner = thread_id; /* Mark thread as owner. */
270 return mutex->depth = 1; /* Increment depth to end. */
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.
279 objc_mutex_trylock(_objc_mutex_t mutex)
281 _objc_thread_t thread_id; /* Cache our thread id. */
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. */
289 if (pthread_mutex_trylock(&mutex->lock) != 1) /* Lock DCE system mutex. */
290 return -1; /* Failed, abort. */
292 mutex->owner = thread_id; /* Mark thread as owner. */
293 return mutex->depth = 1; /* Increment depth to end. */
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.
304 objc_mutex_unlock(_objc_mutex_t mutex)
306 _objc_thread_t thread_id; /* Cache our thread id. */
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".*/
318 if (pthread_mutex_unlock(&mutex->lock) != 0) /* Unlock system mutex. */
319 return -1; /* Failed, abort. */
321 return 0; /* No, return success. */