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>
5 This file is part of GNU CC.
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.
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
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. */
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. */
27 #include <pthreads/pthread.h>
31 /* Key structure for maintiain thread specific storage */
32 static pthread_key_t _objc_thread_storage;
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.
42 volatile objc_thread_t owner; /* Id of thread that owns. */
43 volatile int depth; /* # of acquires. */
44 pthread_mutex_t mutex; /* PCThread mutex */
49 pthread_cond_t condition; /* cthread condition */
53 * Initialize the threads subsystem. Returns 0 if successful, or -1 if no
54 * thread support is available.
57 __objc_init_thread_system(void)
59 /* Initialize the thread storage key */
60 return pthread_key_create(&_objc_thread_storage, NULL);
64 * Finalize the threads subsystem. Returns 0 if successful, or -1 if not
67 __objc_fini_thread_system(void)
69 /* Destroy the thread storage key */
70 /* Not implemented yet */
71 /* return pthread_key_delete(&_objc_thread_storage); */
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.
80 objc_thread_create(void (*func)(void *arg), void *arg)
82 objc_thread_t thread_id;
83 pthread_t new_thread_handle;
85 objc_mutex_lock(__objc_runtime_mutex);
87 if ( !(pthread_create(&new_thread_handle, NULL, (void *)func, arg)) )
89 thread_id = *(objc_thread_t *)&new_thread_handle;
90 __objc_runtime_threads_alive++;
95 objc_mutex_unlock(__objc_runtime_mutex);
101 * Set the current thread's priority.
104 objc_thread_set_priority(int priority)
106 /* Not implemented yet */
107 return -1; /* Failed. */
111 * Return the current thread's priority.
114 objc_thread_get_priority(void)
116 /* Not implemented yet */
117 return OBJC_THREAD_INTERACTIVE_PRIORITY; /* Highest priority. */
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.
126 objc_thread_yield(void)
132 * Terminate the current tread. Doesn't return anything. Doesn't return.
133 * Actually, if it failed returns -1.
136 objc_thread_exit(void)
138 objc_mutex_lock(__objc_runtime_mutex);
139 __objc_runtime_threads_alive--;
140 objc_mutex_unlock(__objc_runtime_mutex);
142 pthread_exit(&__objc_thread_exit_status); /* Terminate thread. */
147 * Returns an integer value which uniquely describes a thread. Must not be
148 * NULL which is reserved as a marker for "no thread".
153 pthread_t self = pthread_self();
155 return *(objc_thread_t *)&self; /* Return thread handle. */
159 * Sets the thread's local storage pointer. Returns 0 if successful or -1
163 objc_thread_set_data(void *value)
165 return pthread_setspecific(_objc_thread_storage, value);
169 * Returns the thread's local storage pointer. Returns NULL on failure.
172 objc_thread_get_data(void)
176 if ( !(pthread_getspecific(_objc_thread_storage, &value)) )
183 * Allocate a mutex. Return the mutex pointer if successful or NULL if the
184 * allocation failed for any reason.
187 objc_mutex_allocate(void)
191 if (!(mutex = (objc_mutex_t)objc_malloc(sizeof(struct objc_mutex))))
192 return NULL; /* Abort if malloc failed. */
194 /* Create PCThread mutex */
195 if ( pthread_mutex_init(&(mutex->mutex), NULL) )
202 mutex->owner = NULL; /* No owner. */
203 mutex->depth = 0; /* No locks. */
204 return mutex; /* Return mutex handle. */
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
212 * Returns the number of locks on the thread. (1 for deallocate).
215 objc_mutex_deallocate(objc_mutex_t mutex)
217 int depth; /* # of locks on mutex. */
219 if (!mutex) /* Is argument bad? */
220 return -1; /* Yes, abort. */
221 depth = objc_mutex_lock(mutex); /* Must have lock. */
223 /* Destroy PCThread mutex */
224 pthread_mutex_destroy(&(mutex->mutex));
226 objc_free(mutex); /* Free memory. */
227 return depth; /* Return last depth. */
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.
237 objc_mutex_lock(objc_mutex_t mutex)
239 objc_thread_t thread_id; /* Cache our thread id. */
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? */
247 return ++mutex->depth; /* Yes, increment depth. */
250 /* Lock the PCThread mutex */
251 status = pthread_mutex_lock(&(mutex->mutex));
254 return status; /* Failed */
257 mutex->owner = thread_id; /* Mark thread as owner. */
258 return mutex->depth = 1; /* Increment depth to end. */
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.
267 objc_mutex_trylock(objc_mutex_t mutex)
269 objc_thread_t thread_id; /* Cache our thread id. */
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. */
278 /* Lock the PCThread mutex */
279 status = pthread_mutex_trylock(&(mutex->mutex));
281 return status; /* Failed */
283 mutex->owner = thread_id; /* Mark thread as owner. */
284 return mutex->depth = 1; /* Increment depth to end. */
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.
295 objc_mutex_unlock(objc_mutex_t mutex)
297 objc_thread_t thread_id; /* Cache our thread id. */
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".*/
310 /* Unlock the PCThread mutex */
311 status = pthread_mutex_unlock(&(mutex->mutex));
313 return status; /* Failed */
315 return 0; /* No, return success. */
319 * Allocate a condition. Return the condition pointer if successful or NULL
320 * if the allocation failed for any reason.
323 objc_condition_allocate(void)
325 objc_condition_t condition;
327 if (!(condition = (objc_condition_t)objc_malloc(
328 sizeof(struct objc_condition))))
329 return NULL; /* Abort if malloc failed. */
331 if ( pthread_cond_init(&(condition->condition), NULL) ) {
332 objc_free(condition);
336 return condition; /* Return condition handle. */
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.
347 objc_condition_deallocate(objc_condition_t condition)
349 pthread_cond_broadcast(&(condition->condition));
350 pthread_cond_destroy(&(condition->condition));
351 objc_free(condition);
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.
364 objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
366 objc_thread_t thread_id; /* Cache our thread id. */
368 if (!mutex || !condition) /* Is argument bad? */
369 return -1; /* Yes, abort. */
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".*/
380 pthread_cond_wait(&(condition->condition),
381 &(mutex->mutex)); /* unlock, wait ..., lock */
383 mutex->owner = thread_id; /* Mark thread as owner. */
384 mutex->depth = 1; /* Increment depth to end. */
385 return 0; /* Return success. */
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.
395 objc_condition_broadcast(objc_condition_t condition)
399 pthread_cond_broadcast(&(condition->condition));
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.
410 objc_condition_signal(objc_condition_t condition)
414 pthread_cond_signal(&(condition->condition));