Commit 2024f9e4 by Richard Kenner

Completely rework according to new interface.

From-SVN: r14310
parent f15e9e7e
...@@ -28,79 +28,59 @@ Boston, MA 02111-1307, USA. */ ...@@ -28,79 +28,59 @@ Boston, MA 02111-1307, USA. */
#include <objc/thr.h> #include <objc/thr.h>
#include "runtime.h" #include "runtime.h"
/******** /* Key structure for maintiain thread specific storage */
* This structure represents a single mutual exclusion lock. Lock semantics static pthread_key_t _objc_thread_storage;
* are detailed with the subsequent functions. We use whatever lock is
* provided by the system. We augment it with depth and current owner id
* fields to implement and re-entrant lock.
*/
struct objc_mutex
{
volatile objc_thread_t owner; /* Id of thread that owns. */
volatile int depth; /* # of acquires. */
pthread_mutex_t lock; /* pthread mutex. */
};
/***************************************************************************** /* Backend initialization functions */
* Static variables.
*/
static pthread_key_t __objc_thread_data_key; /* Data key for thread data.*/
/* Initialize the threads subsystem. */
/********
* Initialize the threads subsystem. Returns 0 if successful, or -1 if no
* thread support is available.
*/
int int
__objc_init_thread_system(void) __objc_init_thread_system(void)
{ {
printf("__objc_init_thread_system\n"); /* Initialize the thread storage key */
return pthread_keycreate(&_objc_thread_storage, NULL);
if (pthread_keycreate(&__objc_thread_data_key, NULL) == 0)
return 0; /* Yes, return success. */
return -1; /* Failed. */
} }
/* Close the threads subsystem. */
int int
__objc_fini_thread_system(void) __objc_close_thread_system(void)
{ {
/* Destroy the thread storage key */
/* Not implemented yet */
/* return pthread_key_delete(&_objc_thread_storage); */
return 0; return 0;
} }
/******** /* Backend thread functions */
* Create a new thread of execution and return its id. Return NULL if fails.
* The new thread starts in "func" with the given argument. /* Create a new thread of execution. */
*/
objc_thread_t objc_thread_t
objc_thread_create(void (*func)(void *arg), void *arg) __objc_thread_detach(void (*func)(void *arg), void *arg)
{ {
objc_thread_t thread_id = NULL; /* Detached thread id. */ objc_thread_t thread_id;
pthread_t new_thread_handle; /* DCE thread handle. */ pthread_t new_thread_handle;
objc_mutex_lock(__objc_runtime_mutex);
if (pthread_create(&new_thread_handle, pthread_attr_default, if (pthread_create(&new_thread_handle, pthread_attr_default,
(void *)func, arg) == 0) { (void *)func, arg) == 0)
/* ??? May not work! (64bit)*/ {
/* ??? May not work! (64bit) */
thread_id = *(objc_thread_t *)&new_thread_handle; thread_id = *(objc_thread_t *)&new_thread_handle;
pthread_detach(&new_thread_handle); /* Fully detach thread. */ pthread_detach(&new_thread_handle); /* Fully detach thread. */
__objc_runtime_threads_alive++;
} }
else
thread_id = NULL;
objc_mutex_unlock(__objc_runtime_mutex);
return thread_id; return thread_id;
} }
/******** /* Set the current thread's priority. */
* Set the current thread's priority.
*/
int int
objc_thread_set_priority(int priority) __objc_thread_set_priority(int priority)
{ {
int sys_priority = 0; int sys_priority = 0;
switch (priority) { switch (priority)
{
case OBJC_THREAD_INTERACTIVE_PRIORITY: case OBJC_THREAD_INTERACTIVE_PRIORITY:
sys_priority = (PRI_FG_MIN_NP + PRI_FG_MAX_NP) / 2; sys_priority = (PRI_FG_MIN_NP + PRI_FG_MAX_NP) / 2;
break; break;
...@@ -113,19 +93,19 @@ objc_thread_set_priority(int priority) ...@@ -113,19 +93,19 @@ objc_thread_set_priority(int priority)
break; break;
} }
/* Change the priority. */
if (pthread_setprio(pthread_self(), sys_priority) >= 0) if (pthread_setprio(pthread_self(), sys_priority) >= 0)
return 0; /* Changed priority. End. */ return 0;
else
return -1; /* Failed. */ /* Failed */
return -1;
} }
/******** /* Return the current thread's priority. */
* Return the current thread's priority.
*/
int int
objc_thread_get_priority(void) __objc_thread_get_priority(void)
{ {
int sys_priority; /* DCE thread priority. */ int sys_priority;
if ((sys_priority = pthread_getprio(pthread_self())) >= 0) { if ((sys_priority = pthread_getprio(pthread_self())) >= 0) {
if (sys_priority >= PRI_FG_MIN_NP && sys_priority <= PRI_FG_MAX_NP) if (sys_priority >= PRI_FG_MIN_NP && sys_priority <= PRI_FG_MAX_NP)
...@@ -134,193 +114,168 @@ objc_thread_get_priority(void) ...@@ -134,193 +114,168 @@ objc_thread_get_priority(void)
return OBJC_THREAD_BACKGROUND_PRIORITY; return OBJC_THREAD_BACKGROUND_PRIORITY;
return OBJC_THREAD_LOW_PRIORITY; return OBJC_THREAD_LOW_PRIORITY;
} }
return -1; /* Couldn't get priority. */
/* Failed */
return -1;
} }
/******** /* Yield our process time to another thread. */
* Yield our process time to another thread. Any BUSY waiting that is done
* by a thread should use this function to make sure that other threads can
* make progress even on a lazy uniprocessor system.
*/
void void
objc_thread_yield(void) __objc_thread_yield(void)
{ {
pthread_yield(); /* Yield to equal thread. */ pthread_yield();
} }
/******** /* Terminate the current thread. */
* Terminate the current tread. Doesn't return anything. Doesn't return.
* Actually, if it failed returns -1.
*/
int int
objc_thread_exit(void) __objc_thread_exit(void)
{ {
objc_mutex_lock(__objc_runtime_mutex); /* exit the thread */
__objc_runtime_threads_alive--; pthread_exit(&__objc_thread_exit_status);
objc_mutex_unlock(__objc_runtime_mutex);
pthread_exit(&__objc_thread_exit_status); /* Terminate thread. */ /* Failed if we reached here */
return -1; return -1;
} }
/******** /* Returns an integer value which uniquely describes a thread. */
* Returns an integer value which uniquely describes a thread. Must not be
* -1 which is reserved as a marker for "no thread".
*/
objc_thread_t objc_thread_t
objc_thread_id(void) __objc_thread_id(void)
{ {
pthread_t self = pthread_self(); pthread_t self = pthread_self();
return (objc_thread_t) pthread_getuniqe_np (&self); return (objc_thread_t) pthread_getuniqe_np (&self);
} }
/******** /* Sets the thread's local storage pointer. */
* Sets the thread's local storage pointer. Returns 0 if successful or -1
* if failed.
*/
int int
objc_thread_set_data(void *value) __objc_thread_set_data(void *value)
{ {
if (pthread_setspecific(__objc_thread_data_key, (void *)value) == 0) return pthread_setspecific(_objc_thread_storage, value);
return 0; /* Return thread data. */
return -1;
} }
/******** /* Returns the thread's local storage pointer. */
* Returns the thread's local storage pointer. Returns NULL on failure.
*/
void * void *
objc_thread_get_data(void) __objc_thread_get_data(void)
{ {
void * value = NULL; void *value = NULL;
if (pthread_getspecific(__objc_thread_data_key, (void *)&value) == 0) if ( !(pthread_getspecific(_objc_thread_storage, &value)) )
return value; /* Return thread data. */ return value;
return NULL; return NULL;
} }
/******** /* Backend mutex functions */
* Allocate a mutex. Return the mutex pointer if successful or NULL if
* the allocation fails for any reason. /* Allocate a mutex. */
*/ int
objc_mutex_t __objc_mutex_allocate(objc_mutex_t mutex)
objc_mutex_allocate(void)
{ {
objc_mutex_t mutex; if (pthread_mutex_init((pthread_mutex_t *)(&(mutex->backend)),
int err = 0; pthread_mutexattr_default))
return -1;
else
return 0;
}
if (!(mutex = (objc_mutex_t)objc_malloc(sizeof(struct objc_mutex)))) /* Deallocate a mutex. */
return NULL; /* Abort if malloc failed. */ int
__objc_mutex_deallocate(objc_mutex_t mutex)
{
if (pthread_mutex_destroy((pthread_mutex_t *)(&(mutex->backend))))
return -1;
else
return 0;
}
err = pthread_mutex_init(&mutex->lock, pthread_mutexattr_default); /* Grab a lock on a mutex. */
int
__objc_mutex_lock(objc_mutex_t mutex)
{
return pthread_mutex_lock((pthread_mutex_t *)(&(mutex->backend)));
}
if (err != 0) { /* System init failed? */ /* Try to grab a lock on a mutex. */
objc_free(mutex); /* Yes, free local memory. */ int
return NULL; /* Abort. */ __objc_mutex_trylock(objc_mutex_t mutex)
} {
mutex->owner = (objc_thread_t) -1; /* No owner. */ if (pthread_mutex_trylock((pthread_mutex_t *)(&(mutex->backend))) != 1)
mutex->depth = 0; /* No locks. */ return -1;
return mutex; /* Return mutex handle. */ else
return 0;
} }
/******** /* Unlock the mutex */
* Deallocate a mutex. Note that this includes an implicit mutex_lock to
* insure that no one else is using the lock. It is legal to deallocate
* a lock if we have a lock on it, but illegal to deallotcate a lock held
* by anyone else.
* Returns the number of locks on the thread. (1 for deallocate).
*/
int int
objc_mutex_deallocate(objc_mutex_t mutex) __objc_mutex_unlock(objc_mutex_t mutex)
{ {
int depth; /* # of locks on mutex. */ return pthread_mutex_unlock((pthread_mutex_t *)(&(mutex->backend)));
}
if (!mutex) /* Is argument bad? */ /* Backend condition mutex functions */
return -1; /* Yes, abort. */
depth = objc_mutex_lock(mutex); /* Must have lock. */
pthread_mutex_unlock(&mutex->lock); /* Must unlock system mutex.*/ /* Allocate a condition. */
pthread_mutex_destroy(&mutex->lock); /* Free system mutex. */ int
__objc_condition_allocate(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
objc_free(mutex); /* Free memory. */ /*
return depth; /* Return last depth. */ if (pthread_cond_init((pthread_cond_t *)(&(condition->backend)), NULL))
return -1;
else
return 0;
*/
} }
/******** /* Deallocate a condition. */
* Grab a lock on a mutex. If this thread already has a lock on this mutex
* then we increment the lock count. If another thread has a lock on the
* mutex we block and wait for the thread to release the lock.
* Returns the lock count on the mutex held by this thread.
*/
int int
objc_mutex_lock(objc_mutex_t mutex) __objc_condition_deallocate(objc_condition_t condition)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ /* Unimplemented. */
return -1;
if (!mutex) /* Is argument bad? */
return -1; /* Yes, abort. */
thread_id = objc_thread_id(); /* Get this thread's id. */
if (mutex->owner == thread_id) /* Already own lock? */
return ++mutex->depth; /* Yes, increment depth. */
if (pthread_mutex_lock(&mutex->lock) != 0) /* Lock DCE system mutex. */
return -1; /* Failed, abort. */
mutex->owner = thread_id; /* Mark thread as owner. */ /*
return mutex->depth = 1; /* Increment depth to end. */ return pthread_cond_destroy((pthread_cond_t *)(&(condition->backend)));
*/
} }
/******** /* Wait on the condition */
* Try to grab a lock on a mutex. If this thread already has a lock on
* this mutex then we increment the lock count and return it. If another
* thread has a lock on the mutex returns -1.
*/
int int
objc_mutex_trylock(objc_mutex_t mutex) __objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ /* Unimplemented. */
return -1;
if (!mutex) /* Is argument bad? */ /*
return -1; /* Yes, abort. */ return pthread_cond_wait((pthread_cond_t *)(&(condition->backend)),
thread_id = objc_thread_id(); /* Get this thread's id. */ (pthread_mutex_t *)(&(mutex->backend)));
if (mutex->owner == thread_id) /* Already own lock? */ */
return ++mutex->depth; /* Yes, increment depth. */ }
if (pthread_mutex_trylock(&mutex->lock) != 1) /* Lock DCE system mutex. */ /* Wake up all threads waiting on this condition. */
return -1; /* Failed, abort. */ int
__objc_condition_broadcast(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
mutex->owner = thread_id; /* Mark thread as owner. */ /*
return mutex->depth = 1; /* Increment depth to end. */ return pthread_cond_broadcast((pthread_cond_t *)(&(condition->backend)));
*/
} }
/******** /* Wake up one thread waiting on this condition. */
* Decrements the lock count on this mutex by one. If the lock count reaches
* zero, release the lock on the mutex. Returns the lock count on the mutex.
* It is an error to attempt to unlock a mutex which this thread doesn't hold
* in which case return -1 and the mutex is unaffected.
* Will also return -1 if the mutex free fails.
*/
int int
objc_mutex_unlock(objc_mutex_t mutex) __objc_condition_signal(objc_condition_t condition)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ /* Unimplemented. */
return -1;
if (!mutex) /* Is argument bad? */
return -1; /* Yes, abort. */ /*
thread_id = objc_thread_id(); /* Get this thread's id. */ return pthread_cond_signal((pthread_cond_t *)(&(condition->backend)));
if (mutex->owner != thread_id) /* Does some else own lock? */ */
return -1; /* Yes, abort. */
if (mutex->depth > 1) /* Released last lock? */
return --mutex->depth; /* No, Decrement depth, end.*/
mutex->depth = 0; /* Yes, reset depth to 0. */
mutex->owner = (objc_thread_t) -1; /* Set owner to "no thread".*/
if (pthread_mutex_unlock(&mutex->lock) != 0) /* Unlock system mutex. */
return -1; /* Failed, abort. */
return 0; /* No, return success. */
} }
/* End of File */ /* End of File */
...@@ -32,283 +32,204 @@ Boston, MA 02111-1307, USA. */ ...@@ -32,283 +32,204 @@ Boston, MA 02111-1307, USA. */
#include <objc/thr.h> #include <objc/thr.h>
#include "runtime.h" #include "runtime.h"
/******** /* Key structure for maintiain thread specific storage */
* This structure represents a single mutual exclusion lock. Lock semantics static void * __objc_shared_arena_handle = NULL;
* are detailed with the subsequent functions. We use whatever lock is
* provided by the system. We augment it with depth and current owner id /* Backend initialization functions */
* fields to implement and re-entrant lock.
*/ /* Initialize the threads subsystem. */
struct objc_mutex
{
volatile objc_thread_t owner; /* Id of thread that owns. */
volatile int depth; /* # of acquires. */
ulock_t lock; /* Irix lock. */
};
/*****************************************************************************
* Static variables.
*/
static void * __objc_shared_arena_handle = NULL; /* Storage arena locks. */
/********
* Initialize the threads subsystem. Returns 0 if successful, or -1 if no
* thread support is available.
*/
int int
__objc_init_thread_system(void) __objc_init_thread_system(void)
{ {
char arena_name[64]; /* Name of IRIX arena. */ /* Name of IRIX arena. */
char arena_name[64];
DEBUG_PRINTF("__objc_init_thread_system\n"); DEBUG_PRINTF("__objc_init_thread_system\n");
/* Construct a temporary name for arena. */
sprintf(arena_name, "/usr/tmp/objc_%05u", (unsigned)getpid()); sprintf(arena_name, "/usr/tmp/objc_%05u", (unsigned)getpid());
usconfig(CONF_INITUSERS, 256); /* Up to 256 threads. */
usconfig(CONF_ARENATYPE, US_SHAREDONLY); /* Arena only for threads. */ /* Up to 256 threads. Arena only for threads. */
if (!(__objc_shared_arena_handle = usinit(arena_name))) /* Init Failed? */ usconfig(CONF_INITUSERS, 256);
return -1; /* Yes, return error code. */ usconfig(CONF_ARENATYPE, US_SHAREDONLY);
/* Initialize the arena */
if (!(__objc_shared_arena_handle = usinit(arena_name)))
/* Failed */
return -1;
return 0; return 0;
} }
/* Close the threads subsystem. */
int int
__objc_fini_thread_system(void) __objc_close_thread_system(void)
{ {
return 0; return 0;
} }
/******** /* Backend thread functions */
* Create a new thread of execution and return its id. Return NULL if fails.
* The new thread starts in "func" with the given argument. /* Create a new thread of execution. */
*/
objc_thread_t objc_thread_t
objc_thread_create(void (*func)(void *arg), void *arg) __objc_thread_detach(void (*func)(void *arg), void *arg)
{ {
objc_thread_t thread_id = NULL; objc_thread_t thread_id;
int sys_id; int sys_id;
objc_mutex_lock(__objc_runtime_mutex); if ((sys_id = sproc((void *)func, PR_SALL, arg)) >= 0)
if ((sys_id = sproc((void *)func, PR_SALL, arg)) >= 0) {
thread_id = (objc_thread_t)sys_id; thread_id = (objc_thread_t)sys_id;
__objc_runtime_threads_alive++; else
} thread_id = NULL;
objc_mutex_unlock(__objc_runtime_mutex);
return thread_id; return thread_id;
} }
/******** /* Set the current thread's priority. */
* Set the current thread's priority.
*/
int int
objc_thread_set_priority(int priority) __objc_thread_set_priority(int priority)
{ {
int sys_priority = 0; /* Not implemented yet */
return -1;
switch (priority) {
case OBJC_THREAD_INTERACTIVE_PRIORITY:
break;
default:
case OBJC_THREAD_BACKGROUND_PRIORITY:
break;
case OBJC_THREAD_LOW_PRIORITY:
break;
}
return -1; /* Failed. */
} }
/******** /* Return the current thread's priority. */
* Return the current thread's priority.
*/
int int
objc_thread_get_priority(void) __objc_thread_get_priority(void)
{ {
return -1; /* Couldn't get priority. */ /* Not implemented yet */
return OBJC_THREAD_INTERACTIVE_PRIORITY;
} }
/******** /* Yield our process time to another thread. */
* Yield our process time to another thread. Any BUSY waiting that is done
* by a thread should use this function to make sure that other threads can
* make progress even on a lazy uniprocessor system.
*/
void void
objc_thread_yield(void) __objc_thread_yield(void)
{ {
sginap(0); /* Yield to equal process. */ sginap(0);
} }
/******** /* Terminate the current thread. */
* Terminate the current tread. Doesn't return anything. Doesn't return.
* Actually, if it failed returns -1.
*/
int int
objc_thread_exit(void) __objc_thread_exit(void)
{ {
objc_mutex_lock(__objc_runtime_mutex); /* IRIX only has exit. */
__objc_runtime_threads_alive--; exit(__objc_thread_exit_status);
objc_mutex_unlock(__objc_runtime_mutex);
exit(__objc_thread_exit_status); /* IRIX only has exit. */ /* Failed if we reached here */
return -1; return -1;
} }
/******** /* Returns an integer value which uniquely describes a thread. */
* Returns an integer value which uniquely describes a thread. Must not be
* NULL which is reserved as a marker for "no thread".
*/
objc_thread_t objc_thread_t
objc_thread_id(void) __objc_thread_id(void)
{ {
return (objc_thread_t)get_pid(); /* Threads are processes. */ /* Threads are processes. */
return (objc_thread_t)get_pid();
} }
/******** /* Sets the thread's local storage pointer. */
* Sets the thread's local storage pointer. Returns 0 if successful or -1
* if failed.
*/
int int
objc_thread_set_data(void *value) __objc_thread_set_data(void *value)
{ {
*((void **)&PRDA->usr_prda) = value; /* Set thread data ptr. */ *((void **)&PRDA->usr_prda) = value;
return 0; return 0;
} }
/******** /* Returns the thread's local storage pointer. */
* Returns the thread's local storage pointer. Returns NULL on failure.
*/
void * void *
objc_thread_get_data(void) __objc_thread_get_data(void)
{ {
return *((void **)&PRDA->usr_prda); /* Return thread data ptr. */ return *((void **)&PRDA->usr_prda);
} }
/******** /* Backend mutex functions */
* Allocate a mutex.
* Return the mutex pointer if successful or NULL if the allocation failed /* Allocate a mutex. */
* for any reason. int
*/ __objc_mutex_allocate(objc_mutex_t mutex)
objc_mutex_t
objc_mutex_allocate(void)
{ {
objc_mutex_t mutex; if (!( (ulock_t)(mutex->backend) = usnewlock(__objc_shared_arena_handle) ))
int err = 0; return -1;
else
if (!(mutex = (objc_mutex_t)objc_malloc(sizeof(struct objc_mutex)))) return 0;
return NULL; /* Abort if malloc failed. */
if (!(mutex->lock = usnewlock(__objc_shared_arena_handle)))
err = -1;
if (err != 0) { /* System init failed? */
objc_free(mutex); /* Yes, free local memory. */
return NULL; /* Abort. */
}
mutex->owner = NULL; /* No owner. */
mutex->depth = 0; /* No locks. */
return mutex; /* Return mutex handle. */
} }
/******** /* Deallocate a mutex. */
* Deallocate a mutex. Note that this includes an implicit mutex_lock to
* insure that no one else is using the lock. It is legal to deallocate
* a lock if we have a lock on it, but illegal to deallotcate a lock held
* by anyone else.
* Returns the number of locks on the thread. (1 for deallocate).
*/
int int
objc_mutex_deallocate(objc_mutex_t mutex) __objc_mutex_deallocate(objc_mutex_t mutex)
{ {
int depth; /* # of locks on mutex. */ usfreelock((ulock_t)(mutex->backend), __objc_shared_arena_handle);
return 0;
if (!mutex) /* Is argument bad? */
return -1; /* Yes, abort. */
depth = objc_mutex_lock(mutex); /* Must have lock. */
usfreelock(mutex->lock, __objc_shared_arena_handle); /* Free IRIX lock. */
objc_free(mutex); /* Free memory. */
return depth; /* Return last depth. */
} }
/******** /* Grab a lock on a mutex. */
* Grab a lock on a mutex. If this thread already has a lock on this mutex
* then we increment the lock count. If another thread has a lock on the
* mutex we block and wait for the thread to release the lock.
* Returns the lock count on the mutex held by this thread.
*/
int int
objc_mutex_lock(objc_mutex_t mutex) __objc_mutex_lock(objc_mutex_t mutex)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ if (ussetlock((ulock_t)(mutex->backend)) == 0)
return -1;
if (!mutex) /* Is argument bad? */ else
return -1; /* Yes, abort. */ return 0;
thread_id = objc_thread_id(); /* Get this thread's id. */
if (mutex->owner == thread_id) { /* Already own lock? */
DEBUG_PRINTF("lock owned by: %d:%d\n", mutex->owner, mutex->depth);
return ++mutex->depth; /* Yes, increment depth. */
}
DEBUG_PRINTF("lock owned by: %d:%d (attempt by %d)\n",
mutex->owner, mutex->depth, thread_id);
if (ussetlock(mutex->lock) == 0) /* Did lock acquire fail? */
return -1; /* Yes, abort. */
mutex->owner = thread_id; /* Mark thread as owner. */
return mutex->depth = 1; /* Increment depth to end. */
} }
/******** /* Try to grab a lock on a mutex. */
* Try to grab a lock on a mutex. If this thread already has a lock on
* this mutex then we increment the lock count and return it. If another
* thread has a lock on the mutex returns -1.
*/
int int
objc_mutex_trylock(objc_mutex_t mutex) __objc_mutex_trylock(objc_mutex_t mutex)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ if (ustestlock((ulock_t)(mutex->backend)) == 0)
return -1;
if (!mutex) /* Is argument bad? */ else
return -1; /* Yes, abort. */ return 0;
thread_id = objc_thread_id(); /* Get this thread's id. */ }
if (mutex->owner == thread_id) /* Already own lock? */
return ++mutex->depth; /* Yes, increment depth. */
if (ustestlock(mutex->lock) == 0) /* Did lock acquire fail? */
return -1; /* Yes, abort. */
mutex->owner = thread_id; /* Mark thread as owner. */ /* Unlock the mutex */
return mutex->depth = 1; /* Increment depth to end. */ int
__objc_mutex_unlock(objc_mutex_t mutex)
{
usunsetlock((ulock_t)(mutex->backend));
return 0;
} }
/******** /* Backend condition mutex functions */
* Decrements the lock count on this mutex by one. If the lock count reaches
* zero, release the lock on the mutex. Returns the lock count on the mutex.
* It is an error to attempt to unlock a mutex which this thread doesn't hold
* in which case return -1 and the mutex is unaffected.
* Will also return -1 if the mutex free fails.
*/
/* Allocate a condition. */
int int
objc_mutex_unlock(objc_mutex_t mutex) __objc_condition_allocate(objc_condition_t condition)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ /* Unimplemented. */
return -1;
if (!mutex) /* Is argument bad? */ }
return -1; /* Yes, abort. */
thread_id = objc_thread_id(); /* Get this thread's id. */
if (mutex->owner != thread_id) /* Does some else own lock? */
return -1; /* Yes, abort. */
DEBUG_PRINTF("unlock by: %d:%d\n", mutex->owner, mutex->depth - 1); /* Deallocate a condition. */
int
__objc_condition_deallocate(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
}
if (mutex->depth > 1) /* Released last lock? */ /* Wait on the condition */
return --mutex->depth; /* No, Decrement depth, end.*/ int
mutex->depth = 0; /* Yes, reset depth to 0. */ __objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
mutex->owner = NULL; /* Set owner to "no thread".*/ {
/* Unimplemented. */
return -1;
}
usunsetlock(mutex->lock); /* Free lock. */ /* Wake up all threads waiting on this condition. */
int
__objc_condition_broadcast(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
}
return 0; /* No, return success. */ /* Wake up one thread waiting on this condition. */
int
__objc_condition_signal(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
} }
/* End of File */ /* End of File */
...@@ -31,31 +31,14 @@ Boston, MA 02111-1307, USA. */ ...@@ -31,31 +31,14 @@ Boston, MA 02111-1307, USA. */
#include <objc/thr.h> #include <objc/thr.h>
#include "runtime.h" #include "runtime.h"
/******** /*
* This structure represents a single mutual exclusion lock. Lock semantics Obtain the maximum thread priority that can set for t. Under the
* are detailed with the subsequent functions. We use whatever lock is mach threading model, it is possible for the developer to adjust the
* provided by the system. We augment it with depth and current owner id maximum priority downward only-- cannot be raised without superuser
* fields to implement and re-entrant lock. priviledges. Once lowered, it cannot be raised.
*/ */
struct objc_mutex static int __mach_get_max_thread_priority(cthread_t t, int *base)
{ {
volatile objc_thread_t owner; /* Id of thread that owns. */
volatile int depth; /* # of acquires. */
struct mutex lock; /* cthread mutex */
};
struct objc_condition
{
struct condition condition; /* cthread condition */
};
/********
* obtain the maximum thread priority that can set for t. Under the
* mach threading model, it is possible for the developer to adjust the
* maximum priority downward only-- cannot be raised without superuser
* priviledges. Once lowered, it cannot be raised.
*/
static int __mach_get_max_thread_priority(cthread_t t, int *base) {
thread_t threadP; thread_t threadP;
kern_return_t error; kern_return_t error;
struct thread_sched_info info; struct thread_sched_info info;
...@@ -78,55 +61,49 @@ static int __mach_get_max_thread_priority(cthread_t t, int *base) { ...@@ -78,55 +61,49 @@ static int __mach_get_max_thread_priority(cthread_t t, int *base) {
return info.max_priority; return info.max_priority;
} }
/******** /* Backend initialization functions */
* Initialize the threads subsystem. Returns 0 if successful, or -1 if no
* thread support is available. /* Initialize the threads subsystem. */
*/
int int
__objc_init_thread_system(void) __objc_init_thread_system(void)
{ {
DEBUG_PRINTF("__objc_init_thread_system\n"); return 0;
return 0; /* Succeeded. */
} }
/* Close the threads subsystem. */
int int
__objc_fini_thread_system(void) __objc_close_thread_system(void)
{ {
return 0; return 0;
} }
/******** /* Backend thread functions */
* Create a new thread of execution and return its id. Return NULL if fails.
* The new thread starts in "func" with the given argument. /* Create a new thread of execution. */
*/
objc_thread_t objc_thread_t
objc_thread_create(void (*func)(void *arg), void *arg) __objc_thread_detach(void (*func)(void *arg), void *arg)
{ {
objc_thread_t thread_id = NULL; /* Detached thread id. */ objc_thread_t thread_id;
cthread_t new_thread_handle; /* cthread handle. */ cthread_t new_thread_handle;
objc_mutex_lock(__objc_runtime_mutex);
/* create thread */ /* create thread */
new_thread_handle = cthread_fork((cthread_fn_t)func, arg); new_thread_handle = cthread_fork((cthread_fn_t)func, arg);
if(new_thread_handle) { if(new_thread_handle)
{
/* this is not terribly portable */ /* this is not terribly portable */
thread_id = *(objc_thread_t *)&new_thread_handle; thread_id = *(objc_thread_t *)&new_thread_handle;
cthread_detach(new_thread_handle); /* fully detach thread */ cthread_detach(new_thread_handle);
__objc_runtime_threads_alive++; /* increment thread count */
} }
else
thread_id = NULL;
objc_mutex_unlock(__objc_runtime_mutex);
return thread_id; return thread_id;
} }
/******** /* Set the current thread's priority. */
* Set the current thread's priority.
*/
int int
objc_thread_set_priority(int priority) __objc_thread_set_priority(int priority)
{ {
objc_thread_t *t = objc_thread_id(); objc_thread_t *t = objc_thread_id();
cthread_t cT = (cthread_t) t; cthread_t cT = (cthread_t) t;
...@@ -136,7 +113,8 @@ objc_thread_set_priority(int priority) ...@@ -136,7 +113,8 @@ objc_thread_set_priority(int priority)
if (maxPriority == -1) if (maxPriority == -1)
return -1; return -1;
switch (priority) { switch (priority)
{
case OBJC_THREAD_INTERACTIVE_PRIORITY: case OBJC_THREAD_INTERACTIVE_PRIORITY:
sys_priority = maxPriority; sys_priority = maxPriority;
break; break;
...@@ -153,17 +131,16 @@ objc_thread_set_priority(int priority) ...@@ -153,17 +131,16 @@ objc_thread_set_priority(int priority)
if (sys_priority == 0) if (sys_priority == 0)
return -1; return -1;
/* Change the priority */
if (cthread_priority(cT, sys_priority, 0) == KERN_SUCCESS) if (cthread_priority(cT, sys_priority, 0) == KERN_SUCCESS)
return 0; /* Changed priority. End. */ return 0;
else
return -1; /* Failed. */ return -1;
} }
/******** /* Return the current thread's priority. */
* Return the current thread's priority [well, whatever it is closest to].
*/
int int
objc_thread_get_priority(void) __objc_thread_get_priority(void)
{ {
objc_thread_t *t = objc_thread_id(); objc_thread_t *t = objc_thread_id();
cthread_t cT = (cthread_t) t; /* see objc_thread_id() */ cthread_t cT = (cthread_t) t; /* see objc_thread_id() */
...@@ -179,286 +156,157 @@ objc_thread_get_priority(void) ...@@ -179,286 +156,157 @@ objc_thread_get_priority(void)
return -1; return -1;
if (basePriority > ( (maxPriority * 2) / 3)) if (basePriority > ( (maxPriority * 2) / 3))
return OBJC_THREAD_INTERACTIVE_PRIORITY; /* interactive priority return OBJC_THREAD_INTERACTIVE_PRIORITY;
*/
if (basePriority > ( maxPriority / 3)) if (basePriority > ( maxPriority / 3))
return OBJC_THREAD_BACKGROUND_PRIORITY; /* background priority return OBJC_THREAD_BACKGROUND_PRIORITY;
*/
return OBJC_THREAD_LOW_PRIORITY; /* everything else is low */ return OBJC_THREAD_LOW_PRIORITY;
} }
/******** /* Yield our process time to another thread. */
* Yield our process time to another thread. Any BUSY waiting that is done
* by a thread should use this function to make sure that other threads can
* make progress even on a lazy uniprocessor system.
*/
void void
objc_thread_yield(void) __objc_thread_yield(void)
{ {
cthread_yield(); /* Yield to equal thread. */ cthread_yield();
} }
/******** /* Terminate the current thread. */
* Terminate the current tread. Doesn't return anything. Doesn't return.
* Actually, if it failed returns -1.
*/
int int
objc_thread_exit(void) __objc_thread_exit(void)
{ {
objc_mutex_lock(__objc_runtime_mutex); /* exit the thread */
__objc_runtime_threads_alive--; cthread_exit(&__objc_thread_exit_status);
objc_mutex_unlock(__objc_runtime_mutex);
cthread_exit(&__objc_thread_exit_status); /* Terminate thread. */ /* Failed if we reached here */
return -1; return -1;
} }
/******** /* Returns an integer value which uniquely describes a thread. */
* Returns an integer value which uniquely describes a thread. Must not be
* NULL which is reserved as a marker for "no thread".
*/
objc_thread_t objc_thread_t
objc_thread_id(void) __objc_thread_id(void)
{ {
cthread_t self = cthread_self(); cthread_t self = cthread_self();
return (objc_thread_t)self;
}
/******** return *(objc_thread_t *)&self;
* Sets the thread's local storage pointer. Returns 0 if successful or -1 }
* if failed.
*/
/* Sets the thread's local storage pointer. */
int int
objc_thread_set_data(void *value) __objc_thread_set_data(void *value)
{ {
cthread_set_data(cthread_self(), (any_t) value); cthread_set_data(cthread_self(), (any_t) value);
return 0; return 0;
} }
/******** /* Returns the thread's local storage pointer. */
* Returns the thread's local storage pointer. Returns NULL on failure.
*/
void * void *
objc_thread_get_data(void) __objc_thread_get_data(void)
{ {
return (void *) cthread_data(cthread_self()); return (void *) cthread_data(cthread_self());
} }
/******** /* Backend mutex functions */
* Allocate a mutex. Return the mutex pointer if successful or NULL if the
* allocation failed for any reason. /* Allocate a mutex. */
*/ int
objc_mutex_t __objc_mutex_allocate(objc_mutex_t mutex)
objc_mutex_allocate(void)
{ {
objc_mutex_t mutex;
int err = 0; int err = 0;
mutex->backend = objc_malloc(sizeof(struct mutex));
if (!(mutex = (objc_mutex_t)objc_malloc(sizeof(struct objc_mutex)))) err = mutex_init((mutex_t)(mutex->backend));
return NULL; /* Abort if malloc failed. */
err = mutex_init(&(mutex->lock)); if (err != 0)
{
if (err != 0) { /* System init failed? */ objc_free(mutex->backend);
objc_free(mutex); /* Yes, free local memory. */ return -1;
return NULL; /* Abort. */
} }
mutex->owner = (objc_thread_t) -1; /* No owner. */ else
mutex->depth = 0; /* No locks. */ return 0;
return mutex; /* Return mutex handle. */
} }
/******** /* Deallocate a mutex. */
* Deallocate a mutex. Note that this includes an implicit mutex_lock to
* insure that no one else is using the lock. It is legal to deallocate
* a lock if we have a lock on it, but illegal to deallocate a lock held
* by anyone else.
* Returns the number of locks on the thread. (1 for deallocate).
*/
int int
objc_mutex_deallocate(objc_mutex_t mutex) __objc_mutex_deallocate(objc_mutex_t mutex)
{ {
int depth; /* # of locks on mutex. */ mutex_clear((mutex_t)(mutex->backend));
if (!mutex) /* Is argument bad? */ objc_free(mutex->backend);
return -1; /* Yes, abort. */ mutex->backend = NULL;
depth = objc_mutex_lock(mutex); /* Must have lock. */ return 0;
mutex_unlock(&(mutex->lock)); /* Must unlock system mutex.*/
mutex_clear(&(mutex->lock)); /* Free system mutex. */
objc_free(mutex); /* Free memory. */
return depth; /* Return last depth. */
} }
/******** /* Grab a lock on a mutex. */
* Grab a lock on a mutex. If this thread already has a lock on this mutex
* then we increment the lock count. If another thread has a lock on the
* mutex we block and wait for the thread to release the lock.
* Returns the lock count on the mutex held by this thread.
*/
int int
objc_mutex_lock(objc_mutex_t mutex) __objc_mutex_lock(objc_mutex_t mutex)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ mutex_lock((mutex_t)(mutex->backend));
return 0;
if (!mutex) /* Is argument bad? */
return -1; /* Yes, abort. */
thread_id = objc_thread_id(); /* Get this thread's id. */
if (mutex->owner == thread_id) /* Already own lock? */
return ++mutex->depth; /* Yes, increment depth. */
mutex_lock(&(mutex->lock)); /* Lock cthread mutex. */
mutex->owner = thread_id; /* Mark thread as owner. */
return mutex->depth = 1; /* Increment depth to end. */
} }
/******** /* Try to grab a lock on a mutex. */
* Try to grab a lock on a mutex. If this thread already has a lock on
* this mutex then we increment the lock count and return it. If another
* thread has a lock on the mutex returns -1.
*/
int int
objc_mutex_trylock(objc_mutex_t mutex) __objc_mutex_trylock(objc_mutex_t mutex)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ if (mutex_try_lock((mutex_t)(mutex->backend)) == 0)
return -1;
if (!mutex) /* Is argument bad? */ else
return -1; /* Yes, abort. */ return 0;
thread_id = objc_thread_id(); /* Get this thread's id. */
if (mutex->owner == thread_id) /* Already own lock? */
return ++mutex->depth; /* Yes, increment depth. */
if (mutex_try_lock(&(mutex->lock)) == 0) /* Lock cthread mutex. */
return -1; /* Failed, abort. */
mutex->owner = thread_id; /* Mark thread as owner. */
return mutex->depth = 1; /* Increment depth to end. */
} }
/******** /* Unlock the mutex */
* Decrements the lock count on this mutex by one. If the lock count reaches
* zero, release the lock on the mutex. Returns the lock count on the mutex.
* It is an error to attempt to unlock a mutex which this thread doesn't hold
* in which case return -1 and the mutex is unaffected.
* Will also return -1 if the mutex free fails.
*/
int int
objc_mutex_unlock(objc_mutex_t mutex) __objc_mutex_unlock(objc_mutex_t mutex)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ mutex_unlock((mutex_t)(mutex->backend));
return 0;
if (!mutex) /* Is argument bad? */
return -1; /* Yes, abort. */
thread_id = objc_thread_id(); /* Get this thread's id. */
if (mutex->owner != thread_id) /* Does some else own lock? */
return -1; /* Yes, abort. */
if (mutex->depth > 1) /* Released last lock? */
return --mutex->depth; /* No, Decrement depth, end.*/
mutex->depth = 0; /* Yes, reset depth to 0. */
mutex->owner = (objc_thread_t) -1; /* Set owner to "no thread".*/
mutex_unlock(&(mutex->lock)); /* unlock cthread mutex. */
return 0; /* No, return success. */
} }
/******** /* Backend condition mutex functions */
* Allocate a condition. Return the condition pointer if successful or NULL
* if the allocation failed for any reason.
*/
objc_condition_t
objc_condition_allocate(void)
{
objc_condition_t condition;
if (!(condition = (objc_condition_t)objc_malloc(
sizeof(struct objc_condition))))
return NULL; /* Abort if malloc failed. */
condition_init(&(condition->condition));
return condition; /* Return mutex handle. */ /* Allocate a condition. */
int
__objc_condition_allocate(objc_condition_t condition)
{
condition->backend = objc_malloc(sizeof(struct condition));
condition_init((condition_t)(condition->backend));
return 0;
} }
/******** /* Deallocate a condition. */
* Deallocate a condition. Note that this includes an implicit
* condition_broadcast to insure that waiting threads have the opportunity
* to wake. It is legal to dealloc a condition only if no other
* thread is/will be using it. Here we do NOT check for other threads
* waiting but just wake them up.
*/
int int
objc_condition_deallocate(objc_condition_t condition) __objc_condition_deallocate(objc_condition_t condition)
{ {
condition_broadcast(&(condition->condition)); condition_clear((condition_t)(condition->backend));
condition_clear(&(condition->condition)); objc_free(condition->backend);
objc_free(condition); condition->backend = NULL;
return 0; return 0;
} }
/******** /* Wait on the condition */
* Wait on the condition unlocking the mutex until objc_condition_signal()
* or objc_condition_broadcast() are called for the same condition. The
* given mutex *must* have the depth set to 1 so that it can be unlocked
* here, so that someone else can lock it and signal/broadcast the condition.
* The mutex is used to lock access to the shared data that make up the
* "condition" predicate.
*/
int int
objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex) __objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ condition_wait((condition_t)(condition->backend),
(mutex_t)(mutex->backend));
if (!mutex || !condition) /* Is argument bad? */ return 0;
return -1; /* Yes, abort. */
thread_id = objc_thread_id(); /* Get this thread's id. */
if (mutex->owner != thread_id) /* Does some else own lock? */
return -1; /* Yes, abort. */
if (mutex->depth > 1) /* Locked more than once ? */
return -1; /* YES, return error */
/* mutex will be unlocked */
mutex->depth = 0; /* Yes, reset depth to 0. */
mutex->owner = (objc_thread_t) -1; /* Set owner to "no thread".*/
condition_wait(&(condition->condition),
&(mutex->lock)); /* unlock, wait ..., lock */
mutex->owner = thread_id; /* Mark thread as owner. */
mutex->depth = 1; /* Increment depth to end. */
return 0; /* Return success. */
} }
/******** /* Wake up all threads waiting on this condition. */
* Wake up all threads waiting on this condition. It is recommended that
* the called would lock the same mutex as the threads in objc_condition_wait
* before changing the "condition predicate" and make this call and unlock it
* right away after this call.
*/
int int
objc_condition_broadcast(objc_condition_t condition) __objc_condition_broadcast(objc_condition_t condition)
{ {
if (!condition) condition_broadcast((condition_t)(condition->backend));
return -1;
condition_broadcast(&(condition->condition));
return 0; return 0;
} }
/******** /* Wake up one thread waiting on this condition. */
* Wake up one thread waiting on this condition. It is recommended that
* the called would lock the same mutex as the threads in objc_condition_wait
* before changing the "condition predicate" and make this call and unlock it
* right away after this call.
*/
int int
objc_condition_signal(objc_condition_t condition) __objc_condition_signal(objc_condition_t condition)
{ {
if (!condition) condition_signal((condition_t)(condition->backend));
return -1;
condition_signal(&(condition->condition));
return 0; return 0;
} }
/* End of File */
...@@ -44,71 +44,39 @@ Boston, MA 02111-1307, USA. */ ...@@ -44,71 +44,39 @@ Boston, MA 02111-1307, USA. */
#include <stdlib.h> #include <stdlib.h>
/******** /* Backend initialization functions */
* This structure represents a single mutual exclusion lock. Lock semantics
* are detailed with the subsequent functions. We use whatever lock is
* provided by the system. We augment it with depth and current owner id
* fields to implement and re-entrant lock.
*/
struct objc_mutex
{
volatile objc_thread_t owner; /* Id of thread that owns. */
volatile int depth; /* # of acquires. */
HMTX handle; /* OS/2 mutex HANDLE. */
};
/***************************************************************************** /* Initialize the threads subsystem. */
* Static variables.
*/
/* none needed for OS/2 */
/********
* Initialize the threads subsystem. Returns 0 if successful, or -1 if no
* thread support is available.
*/
int int
__objc_init_thread_system(void) __objc_init_thread_system(void)
{ {
DEBUG_PRINTF("__objc_init_thread_system (os2-emx)\n"); return 0;
/* no initialization of thread subsystem */
return 0; /* Yes, return success. */
} }
/* Close the threads subsystem. */
int int
__objc_fini_thread_system(void) __objc_close_thread_system(void)
{ {
/* no termination code for thread subsystem */
return 0; return 0;
} }
/******** /* Backend thread functions */
* Create a new thread of execution and return its id. Return NULL if fails.
* The new thread starts in "func" with the given argument. /* Create a new thread of execution. */
*/
objc_thread_t objc_thread_t
objc_thread_create(void (*func)(void *arg), void *arg) __objc_thread_detach(void (*func)(void *arg), void *arg)
{ {
int thread_id = 0; /* id of the newly created thread */ int thread_id = 0;
objc_mutex_lock(__objc_runtime_mutex);
/* create a thread calling "func", args "arg", stack size 32768 bytes */
if ((thread_id = _beginthread (func,NULL,32768,arg)) < 0) if ((thread_id = _beginthread (func,NULL,32768,arg)) < 0)
thread_id = 0; thread_id = 0;
else
__objc_runtime_threads_alive++;
objc_mutex_unlock(__objc_runtime_mutex);
return (objc_thread_t)thread_id; return (objc_thread_t)thread_id;
} }
/******** /* Set the current thread's priority. */
* Set the current thread's priority.
*/
int int
objc_thread_set_priority(int priority) __objc_thread_set_priority(int priority)
{ {
ULONG sys_class = 0; ULONG sys_class = 0;
ULONG sys_priority = 0; ULONG sys_priority = 0;
...@@ -132,24 +100,26 @@ objc_thread_set_priority(int priority) ...@@ -132,24 +100,26 @@ objc_thread_set_priority(int priority)
sys_priority = 0; sys_priority = 0;
break; break;
} }
if (!DosSetPriority (PRTYS_THREAD,sys_class,sys_priority,*_threadid))
return 0; /* Changed priority. End. */
return -1; /* Failed. */ /* Change priority */
if (!DosSetPriority (PRTYS_THREAD,sys_class,sys_priority,*_threadid))
return 0;
else
return -1;
} }
/******** /* Return the current thread's priority. */
* Return the current thread's priority.
*/
int int
objc_thread_get_priority(void) __objc_thread_get_priority(void)
{ {
PTIB ptib; PTIB ptib;
PPIB ppib; PPIB ppib;
DosGetInfoBlocks (&ptib,&ppib); /* get information about current thread */ /* get information about current thread */
DosGetInfoBlocks (&ptib,&ppib);
switch (ptib->tib_ptib2->tib2_ulpri) { switch (ptib->tib_ptib2->tib2_ulpri)
{
case PRTYC_IDLETIME: case PRTYC_IDLETIME:
case PRTYC_REGULAR: case PRTYC_REGULAR:
case PRTYC_TIMECRITICAL: case PRTYC_TIMECRITICAL:
...@@ -157,185 +127,141 @@ objc_thread_get_priority(void) ...@@ -157,185 +127,141 @@ objc_thread_get_priority(void)
default: default:
return OBJC_THREAD_INTERACTIVE_PRIORITY; return OBJC_THREAD_INTERACTIVE_PRIORITY;
} }
return -1; /* Couldn't get priority. */
return -1;
} }
/******** /* Yield our process time to another thread. */
* Yield our process time to another thread. Any BUSY waiting that is done
* by a thread should use this function to make sure that other threads can
* make progress even on a lazy uniprocessor system.
*/
void void
objc_thread_yield(void) __objc_thread_yield(void)
{ {
DosSleep (0); /* Yield to equal thread. */ DosSleep (0);
} }
/******** /* Terminate the current thread. */
* Terminate the current tread. Doesn't return anything. Doesn't return.
* Actually, if it failed returns -1.
*/
int int
objc_thread_exit(void) __objc_thread_exit(void)
{ {
objc_mutex_lock(__objc_runtime_mutex); /* terminate the thread, NEVER use DosExit () */
__objc_runtime_threads_alive--; _endthread ();
objc_mutex_unlock(__objc_runtime_mutex);
_endthread (); /* terminate the thread, NEVER use DosExit () */
/* Failed if we reached here */
return -1; return -1;
} }
/******** /* Returns an integer value which uniquely describes a thread. */
* Returns an integer value which uniquely describes a thread. Must not be
* -1 which is reserved as a marker for "no thread".
*/
objc_thread_t objc_thread_t
objc_thread_id(void) __objc_thread_id(void)
{ {
return (objc_thread_t) *_threadid; /* Return thread id. */ return (objc_thread_t) *_threadid;
} }
/******** /* Sets the thread's local storage pointer. */
* Sets the thread's local storage pointer. Returns 0 if successful or -1
* if failed.
*/
int int
objc_thread_set_data(void *value) __objc_thread_set_data(void *value)
{ {
*_threadstore () = value; *_threadstore () = value;
return 0; return 0;
} }
/******** /* Returns the thread's local storage pointer. */
* Returns the thread's local storage pointer. Returns NULL on failure.
*/
void * void *
objc_thread_get_data(void) __objc_thread_get_data(void)
{ {
return *_threadstore (); return *_threadstore ();
} }
/******** /* Backend mutex functions */
* Allocate a mutex. Return the mutex pointer if successful or NULL if
* the allocation fails for any reason.
*/
objc_mutex_t
objc_mutex_allocate(void)
{
objc_mutex_t mutex;
int err = 0;
if (!(mutex = (objc_mutex_t)objc_malloc(sizeof(struct objc_mutex)))) /* Allocate a mutex. */
return NULL; /* Abort if malloc failed. */ int
__objc_mutex_allocate(objc_mutex_t mutex)
if (DosCreateMutexSem (NULL,&(mutex->handle),0L,0) > 0) { {
objc_free(mutex); if (DosCreateMutexSem (NULL, (HMTX)(&(mutex->backend)),0L,0) > 0)
return NULL; return -1;
} else
return 0;
mutex->owner = NULL; /* No owner. */
mutex->depth = 0; /* No locks. */
return mutex; /* Return mutex handle. */
} }
/******** /* Deallocate a mutex. */
* Deallocate a mutex. Note that this includes an implicit mutex_lock to
* insure that no one else is using the lock. It is legal to deallocate
* a lock if we have a lock on it, but illegal to deallotcate a lock held
* by anyone else.
* Returns the number of locks on the thread. (1 for deallocate).
*/
int int
objc_mutex_deallocate(objc_mutex_t mutex) __objc_mutex_deallocate(objc_mutex_t mutex)
{ {
int depth; /* # of locks on mutex. */ DosCloseMutexSem ((HMTX)(mutex->backend));
return 0;
if (!mutex) /* Is argument bad? */
return -1; /* Yes, abort. */
depth = objc_mutex_lock(mutex); /* Must have lock. */
DosCloseMutexSem (mutex->handle);
objc_free(mutex); /* Free memory. */
return depth; /* Return last depth. */
} }
/******** /* Grab a lock on a mutex. */
* Grab a lock on a mutex. If this thread already has a lock on this mutex
* then we increment the lock count. If another thread has a lock on the
* mutex we block and wait for the thread to release the lock.
* Returns the lock count on the mutex held by this thread.
*/
int int
objc_mutex_lock(objc_mutex_t mutex) __objc_mutex_lock(objc_mutex_t mutex)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ if (DosRequestMutexSem ((HMTX)(mutex->backend),-1L) != 0)
return -1;
if (!mutex) /* Is argument bad? */ else
return -1; /* Yes, abort. */ return 0;
}
thread_id = objc_thread_id(); /* Get this thread's id. */ /* Try to grab a lock on a mutex. */
if (mutex->owner == thread_id) /* Already own lock? */ int
return ++mutex->depth; /* Yes, increment depth. */ __objc_mutex_trylock(objc_mutex_t mutex)
{
if (DosRequestMutexSem ((HMTX)(mutex->backend),0L) != 0)
return -1;
else
return 0;
}
if (DosRequestMutexSem (mutex->handle,-1L) != 0) /* Unlock the mutex */
int
__objc_mutex_unlock(objc_mutex_t mutex)
{
if (DosReleaseMutexSem((HMTX)(mutex->backend)) != 0)
return -1; return -1;
else
return 0;
}
mutex->owner = thread_id; /* Mark thread as owner. */ /* Backend condition mutex functions */
return ++mutex->depth; /* Increment depth to end. */ /* Allocate a condition. */
int
__objc_condition_allocate(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
} }
/******** /* Deallocate a condition. */
* Try to grab a lock on a mutex. If this thread already has a lock on
* this mutex then we increment the lock count and return it. If another
* thread has a lock on the mutex returns -1.
*/
int int
objc_mutex_trylock(objc_mutex_t mutex) __objc_condition_deallocate(objc_condition_t condition)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ /* Unimplemented. */
return -1;
if (!mutex) /* Is argument bad? */ }
return -1; /* Yes, abort. */
thread_id = objc_thread_id(); /* Get this thread's id. */
if (mutex->owner == thread_id) /* Already own lock? */
return ++mutex->depth; /* Yes, increment depth. */
if (DosRequestMutexSem (mutex->handle,0L) != 0) /* Wait on the condition */
int
__objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
{
/* Unimplemented. */
return -1; return -1;
}
mutex->owner = thread_id; /* Mark thread as owner. */ /* Wake up all threads waiting on this condition. */
return ++mutex->depth; /* Increment depth to end. */ int
__objc_condition_broadcast(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
} }
/******** /* Wake up one thread waiting on this condition. */
* Decrements the lock count on this mutex by one. If the lock count reaches
* zero, release the lock on the mutex. Returns the lock count on the mutex.
* It is an error to attempt to unlock a mutex which this thread doesn't hold
* in which case return -1 and the mutex is unaffected.
* Will also return -1 if the mutex free fails.
*/
int int
objc_mutex_unlock(objc_mutex_t mutex) __objc_condition_signal(objc_condition_t condition)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ /* Unimplemented. */
return -1;
if (!mutex) /* Is argument bad? */
return -1; /* Yes, abort. */
thread_id = objc_thread_id(); /* Get this thread's id. */
if (mutex->owner != thread_id) /* Does some else own lock? */
return -1; /* Yes, abort. */
if (mutex->depth > 1) /* Released last lock? */
return --mutex->depth; /* No, Decrement depth, end.*/
mutex->depth = 0; /* Yes, reset depth to 0. */
mutex->owner = NULL; /* Set owner to "no thread".*/
if (DosReleaseMutexSem(mutex->handle) != 0)
return -1; /* Failed, abort. */
return 0; /* No, return success. */
} }
/* End of File */
...@@ -29,294 +29,182 @@ Boston, MA 02111-1307, USA. */ ...@@ -29,294 +29,182 @@ Boston, MA 02111-1307, USA. */
#include "runtime.h" #include "runtime.h"
#include <pthread.h> #include <pthread.h>
/******** /* Key structure for maintiain thread specific storage */
* This structure represents a single mutual exclusion lock. Lock semantics static pthread_key_t _objc_thread_storage;
* are detailed with the subsequent functions. We use whatever lock is
* provided by the system. We augment it with depth and current owner id
* fields to implement and re-entrant lock.
*/
struct objc_mutex
{
volatile objc_thread_t owner; /* Id of thread that owns. */
volatile int depth; /* # of acquires. */
pthread_mutex_t lock; /* pthread mutex. */
};
/*****************************************************************************
* Static variables.
*/
static pthread_key_t __objc_thread_data_key; /* Data key for thread data.*/
/* Backend initialization functions */
/******** /* Initialize the threads subsystem. */
* Initialize the threads subsystem. Returns 0 if successful, or -1 if no
* thread support is available.
*/
int int
__objc_init_thread_system(void) __objc_init_thread_system(void)
{ {
if (pthread_key_create(&__objc_thread_data_key, NULL) == 0) /* Initialize the thread storage key */
return 0; /* Yes, return success. */ return pthread_key_create(&_objc_thread_storage, NULL);
return -1; /* Failed. */
} }
/* Close the threads subsystem. */
int int
__objc_fini_thread_system(void) __objc_close_thread_system(void)
{ {
return 0; return 0;
} }
/******** /* Backend thread functions */
* Create a new thread of execution and return its id. Return NULL if fails.
* The new thread starts in "func" with the given argument. /* Create a new thread of execution. */
*/
objc_thread_t objc_thread_t
objc_thread_create(void (*func)(void *arg), void *arg) __objc_thread_detach(void (*func)(void *arg), void *arg)
{ {
objc_thread_t thread_id = NULL; /* Detached thread id. */ objc_thread_t thread_id;
pthread_t new_thread_handle; /* DCE thread handle. */ pthread_t new_thread_handle;
objc_mutex_lock(__objc_runtime_mutex);
if (pthread_create(&new_thread_handle, NULL, if ( !(pthread_create(&new_thread_handle, NULL, (void *)func, arg)) )
(void *)func, arg) == 0) { thread_id = *(objc_thread_t *)&new_thread_handle;
thread_id = (objc_thread_t) new_thread_handle; else
pthread_detach(new_thread_handle); /* Fully detach thread. */ thread_id = NULL;
__objc_runtime_threads_alive++;
}
objc_mutex_unlock(__objc_runtime_mutex);
return thread_id; return thread_id;
} }
/******** /* Set the current thread's priority. */
* Set the current thread's priority.
*/
int int
objc_thread_set_priority(int priority) __objc_thread_set_priority(int priority)
{ {
#if 0 /* no get/set priority in Linux pthreads */ /* Not implemented yet */
return -1;
int sys_priority = 0;
switch (priority) {
case OBJC_THREAD_INTERACTIVE_PRIORITY:
sys_priority = (PRI_FG_MIN_NP + PRI_FG_MAX_NP) / 2;
break;
default:
case OBJC_THREAD_BACKGROUND_PRIORITY:
sys_priority = (PRI_BG_MIN_NP + PRI_BG_MAX_NP) / 2;
break;
case OBJC_THREAD_LOW_PRIORITY:
sys_priority = (PRI_BG_MIN_NP + PRI_BG_MAX_NP) / 2;
break;
}
if (pthread_setprio(pthread_self(), sys_priority) >= 0)
return 0; /* Changed priority. End. */
#endif
return -1; /* Failed. */
} }
/******** /* Return the current thread's priority. */
* Return the current thread's priority.
*/
int int
objc_thread_get_priority(void) __objc_thread_get_priority(void)
{ {
#if 0 /* no get/set priority in Linux pthreads */ /* Not implemented yet */
int sys_priority; /* DCE thread priority. */ return -1;
if ((sys_priority = pthread_getprio(pthread_self())) >= 0) {
if (sys_priority >= PRI_FG_MIN_NP && sys_priority <= PRI_FG_MAX_NP)
return OBJC_THREAD_INTERACTIVE_PRIORITY;
if (sys_priority >= PRI_BG_MIN_NP && sys_priority <= PRI_BG_MAX_NP)
return OBJC_THREAD_BACKGROUND_PRIORITY;
return OBJC_THREAD_LOW_PRIORITY;
}
#endif
return -1; /* Couldn't get priority. */
} }
/******** /* Yield our process time to another thread. */
* Yield our process time to another thread. Any BUSY waiting that is done
* by a thread should use this function to make sure that other threads can
* make progress even on a lazy uniprocessor system.
*/
void void
objc_thread_yield(void) __objc_thread_yield(void)
{ {
pthread_yield(); /* Yield to equal thread. */ pthread_yield();
} }
/******** /* Terminate the current thread. */
* Terminate the current tread. Doesn't return anything. Doesn't return.
* Actually, if it failed returns -1.
*/
int int
objc_thread_exit(void) __objc_thread_exit(void)
{ {
objc_mutex_lock(__objc_runtime_mutex); /* exit the thread */
__objc_runtime_threads_alive--; pthread_exit(&__objc_thread_exit_status);
objc_mutex_unlock(__objc_runtime_mutex);
pthread_exit(&__objc_thread_exit_status); /* Terminate thread. */ /* Failed if we reached here */
return -1; return -1;
} }
/******** /* Returns an integer value which uniquely describes a thread. */
* Returns an integer value which uniquely describes a thread. Must not be
* -1 which is reserved as a marker for "no thread".
*/
objc_thread_t objc_thread_t
objc_thread_id(void) __objc_thread_id(void)
{ {
pthread_t self = pthread_self(); pthread_t self = pthread_self();
return (objc_thread_t) self; /* Return thread handle. */ return *(objc_thread_t *)&self;
} }
/******** /* Sets the thread's local storage pointer. */
* Sets the thread's local storage pointer. Returns 0 if successful or -1
* if failed.
*/
int int
objc_thread_set_data(void *value) __objc_thread_set_data(void *value)
{ {
if (pthread_setspecific(__objc_thread_data_key, (void *)value) == 0) return pthread_setspecific(_objc_thread_storage, value);
return 0; /* Return thread data. */
return -1;
} }
/******** /* Returns the thread's local storage pointer. */
* Returns the thread's local storage pointer. Returns NULL on failure.
*/
void * void *
objc_thread_get_data(void) __objc_thread_get_data(void)
{ {
return pthread_getspecific(__objc_thread_data_key); return pthread_getspecific(_objc_thread_storage);
} }
/******** /* Backend mutex functions */
* Allocate a mutex. Return the mutex pointer if successful or NULL if
* the allocation fails for any reason.
*/
objc_mutex_t
objc_mutex_allocate(void)
{
objc_mutex_t mutex;
int err = 0;
if (!(mutex = (objc_mutex_t)objc_malloc(sizeof(struct objc_mutex))))
return NULL; /* Abort if malloc failed. */
err = pthread_mutex_init(&mutex->lock, NULL); /* Allocate a mutex. */
int
if (err != 0) { /* System init failed? */ __objc_mutex_allocate(objc_mutex_t mutex)
objc_free(mutex); /* Yes, free local memory. */ {
return NULL; /* Abort. */ if (pthread_mutex_init((pthread_mutex_t *)(&(mutex->backend)), NULL))
} return -1;
mutex->owner = NULL; /* No owner. */ else
mutex->depth = 0; /* No locks. */ return 0;
return mutex; /* Return mutex handle. */
} }
/******** /* Deallocate a mutex. */
* Deallocate a mutex. Note that this includes an implicit mutex_lock to
* insure that no one else is using the lock. It is legal to deallocate
* a lock if we have a lock on it, but illegal to deallotcate a lock held
* by anyone else.
* Returns the number of locks on the thread. (1 for deallocate).
*/
int int
objc_mutex_deallocate(objc_mutex_t mutex) __objc_mutex_deallocate(objc_mutex_t mutex)
{ {
int depth; /* # of locks on mutex. */ if (pthread_mutex_destroy((pthread_mutex_t *)(&(mutex->backend))))
return -1;
if (!mutex) /* Is argument bad? */ else
return -1; /* Yes, abort. */ return 0;
depth = objc_mutex_lock(mutex); /* Must have lock. */ }
pthread_mutex_unlock(&mutex->lock); /* Must unlock system mutex.*/
pthread_mutex_destroy(&mutex->lock); /* Free system mutex. */
objc_free(mutex); /* Free memory. */ /* Grab a lock on a mutex. */
return depth; /* Return last depth. */ int
__objc_mutex_lock(objc_mutex_t mutex)
{
return pthread_mutex_lock((pthread_mutex_t *)(&(mutex->backend)));
} }
/******** /* Try to grab a lock on a mutex. */
* Grab a lock on a mutex. If this thread already has a lock on this mutex
* then we increment the lock count. If another thread has a lock on the
* mutex we block and wait for the thread to release the lock.
* Returns the lock count on the mutex held by this thread.
*/
int int
objc_mutex_lock(objc_mutex_t mutex) __objc_mutex_trylock(objc_mutex_t mutex)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ return pthread_mutex_trylock((pthread_mutex_t *)(&(mutex->backend)));
}
if (!mutex) /* Is argument bad? */ /* Unlock the mutex */
return -1; /* Yes, abort. */ int
thread_id = objc_thread_id(); /* Get this thread's id. */ __objc_mutex_unlock(objc_mutex_t mutex)
if (mutex->owner == thread_id) /* Already own lock? */ {
return ++mutex->depth; /* Yes, increment depth. */ return pthread_mutex_unlock((pthread_mutex_t *)(&(mutex->backend)));
}
if (pthread_mutex_lock(&mutex->lock) != 0) /* Lock DCE system mutex. */ /* Backend condition mutex functions */
return -1; /* Failed, abort. */
mutex->owner = thread_id; /* Mark thread as owner. */ /* Allocate a condition. */
return mutex->depth = 1; /* Increment depth to end. */ int
__objc_condition_allocate(objc_condition_t condition)
{
if (pthread_cond_init((pthread_cond_t *)(&(condition->backend)), NULL))
return -1;
else
return 0;
} }
/******** /* Deallocate a condition. */
* Try to grab a lock on a mutex. If this thread already has a lock on
* this mutex then we increment the lock count and return it. If another
* thread has a lock on the mutex returns -1.
*/
int int
objc_mutex_trylock(objc_mutex_t mutex) __objc_condition_deallocate(objc_condition_t condition)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ return pthread_cond_destroy((pthread_cond_t *)(&(condition->backend)));
}
if (!mutex) /* Is argument bad? */
return -1; /* Yes, abort. */
thread_id = objc_thread_id(); /* Get this thread's id. */
if (mutex->owner == thread_id) /* Already own lock? */
return ++mutex->depth; /* Yes, increment depth. */
if (pthread_mutex_trylock(&mutex->lock) != 1) /* Lock DCE system mutex. */ /* Wait on the condition */
return -1; /* Failed, abort. */ int
__objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
{
return pthread_cond_wait((pthread_cond_t *)(&(condition->backend)),
(pthread_mutex_t *)(&(mutex->backend)));
}
mutex->owner = thread_id; /* Mark thread as owner. */ /* Wake up all threads waiting on this condition. */
return mutex->depth = 1; /* Increment depth to end. */ int
__objc_condition_broadcast(objc_condition_t condition)
{
return pthread_cond_broadcast((pthread_cond_t *)(&(condition->backend)));
} }
/******** /* Wake up one thread waiting on this condition. */
* Decrements the lock count on this mutex by one. If the lock count reaches
* zero, release the lock on the mutex. Returns the lock count on the mutex.
* It is an error to attempt to unlock a mutex which this thread doesn't hold
* in which case return -1 and the mutex is unaffected.
* Will also return -1 if the mutex free fails.
*/
int int
objc_mutex_unlock(objc_mutex_t mutex) __objc_condition_signal(objc_condition_t condition)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ return pthread_cond_signal((pthread_cond_t *)(&(condition->backend)));
if (!mutex) /* Is argument bad? */
return -1; /* Yes, abort. */
thread_id = objc_thread_id(); /* Get this thread's id. */
if (mutex->owner != thread_id) /* Does some else own lock? */
return -1; /* Yes, abort. */
if (mutex->depth > 1) /* Released last lock? */
return --mutex->depth; /* No, Decrement depth, end.*/
mutex->depth = 0; /* Yes, reset depth to 0. */
mutex->owner = NULL; /* Set owner to "no thread".*/
if (pthread_mutex_unlock(&mutex->lock) != 0) /* Unlock system mutex. */
return -1; /* Failed, abort. */
return 0; /* No, return success. */
} }
/* End of File */
/* GNU Objective C Runtime Thread Implementation for PCThreads under Linux. /* GNU Objective C Runtime Thread Implementation for PCThreads under Linux.
Copyright (C) 1996, 1997 Free Software Foundation, Inc. Copyright (C) 1996, 1997 Free Software Foundation, Inc.
Contributed by Scott Christley <scottc@net-community.com> Contributed by Scott Christley <scottc@net-community.com>
Condition functions added by: Mircea Oancea <mircea@first.elcom.pub.ro>
This file is part of GNU CC. This file is part of GNU CC.
...@@ -24,35 +25,16 @@ Boston, MA 02111-1307, USA. */ ...@@ -24,35 +25,16 @@ Boston, MA 02111-1307, USA. */
however invalidate any other reasons why the executable file might be however invalidate any other reasons why the executable file might be
covered by the GNU General Public License. */ covered by the GNU General Public License. */
#include <pthread.h> #include <pcthread.h>
#include <objc/thr.h> #include <objc/thr.h>
#include "runtime.h" #include "runtime.h"
/* Key structure for maintiain thread specific storage */ /* Key structure for maintiain thread specific storage */
static pthread_key_t _objc_thread_storage; static pthread_key_t _objc_thread_storage;
/******** /* Backend initialization functions */
* This structure represents a single mutual exclusion lock. Lock semantics
* are detailed with the subsequent functions. We use whatever lock is
* provided by the system. We augment it with depth and current owner id
* fields to implement and re-entrant lock.
*/
struct objc_mutex
{
volatile objc_thread_t owner; /* Id of thread that owns. */
volatile int depth; /* # of acquires. */
pthread_mutex_t mutex; /* PCThread mutex */
};
struct objc_condition
{
pthread_cond_t condition; /* cthread condition */
};
/******** /* Initialize the threads subsystem. */
* Initialize the threads subsystem. Returns 0 if successful, or -1 if no
* thread support is available.
*/
int int
__objc_init_thread_system(void) __objc_init_thread_system(void)
{ {
...@@ -60,11 +42,9 @@ __objc_init_thread_system(void) ...@@ -60,11 +42,9 @@ __objc_init_thread_system(void)
return pthread_key_create(&_objc_thread_storage, NULL); return pthread_key_create(&_objc_thread_storage, NULL);
} }
/******** /* Close the threads subsystem. */
* Finalize the threads subsystem. Returns 0 if successful, or -1 if not
*/
int int
__objc_fini_thread_system(void) __objc_close_thread_system(void)
{ {
/* Destroy the thread storage key */ /* Destroy the thread storage key */
/* Not implemented yet */ /* Not implemented yet */
...@@ -72,104 +52,76 @@ __objc_fini_thread_system(void) ...@@ -72,104 +52,76 @@ __objc_fini_thread_system(void)
return 0; return 0;
} }
/******** /* Backend thread functions */
* Create a new thread of execution and return its id. Return NULL if fails.
* The new thread starts in "func" with the given argument. /* Create a new thread of execution. */
*/
objc_thread_t objc_thread_t
objc_thread_create(void (*func)(void *arg), void *arg) __objc_thread_detach(void (*func)(void *arg), void *arg)
{ {
objc_thread_t thread_id; objc_thread_t thread_id;
pthread_t new_thread_handle; pthread_t new_thread_handle;
objc_mutex_lock(__objc_runtime_mutex);
if ( !(pthread_create(&new_thread_handle, NULL, (void *)func, arg)) ) if ( !(pthread_create(&new_thread_handle, NULL, (void *)func, arg)) )
{
thread_id = *(objc_thread_t *)&new_thread_handle; thread_id = *(objc_thread_t *)&new_thread_handle;
__objc_runtime_threads_alive++;
}
else else
thread_id = NULL; thread_id = NULL;
objc_mutex_unlock(__objc_runtime_mutex);
return thread_id; return thread_id;
} }
/******** /* Set the current thread's priority. */
* Set the current thread's priority.
*/
int int
objc_thread_set_priority(int priority) __objc_thread_set_priority(int priority)
{ {
/* Not implemented yet */ /* Not implemented yet */
return -1; /* Failed. */ return -1;
} }
/******** /* Return the current thread's priority. */
* Return the current thread's priority.
*/
int int
objc_thread_get_priority(void) __objc_thread_get_priority(void)
{ {
/* Not implemented yet */ /* Not implemented yet */
return OBJC_THREAD_INTERACTIVE_PRIORITY; /* Highest priority. */ return OBJC_THREAD_INTERACTIVE_PRIORITY;
} }
/******** /* Yield our process time to another thread. */
* Yield our process time to another thread. Any BUSY waiting that is done
* by a thread should use this function to make sure that other threads can
* make progress even on a lazy uniprocessor system.
*/
void void
objc_thread_yield(void) __objc_thread_yield(void)
{ {
pthread_yield(NULL); pthread_yield(NULL);
} }
/******** /* Terminate the current thread. */
* Terminate the current tread. Doesn't return anything. Doesn't return.
* Actually, if it failed returns -1.
*/
int int
objc_thread_exit(void) __objc_thread_exit(void)
{ {
objc_mutex_lock(__objc_runtime_mutex); /* exit the thread */
__objc_runtime_threads_alive--; pthread_exit(&__objc_thread_exit_status);
objc_mutex_unlock(__objc_runtime_mutex);
pthread_exit(&__objc_thread_exit_status); /* Terminate thread. */ /* Failed if we reached here */
return -1; return -1;
} }
/******** /* Returns an integer value which uniquely describes a thread. */
* Returns an integer value which uniquely describes a thread. Must not be
* NULL which is reserved as a marker for "no thread".
*/
objc_thread_t objc_thread_t
objc_thread_id(void) __objc_thread_id(void)
{ {
pthread_t self = pthread_self(); pthread_t self = pthread_self();
return *(objc_thread_t *)&self; /* Return thread handle. */ return *(objc_thread_t *)&self;
} }
/******** /* Sets the thread's local storage pointer. */
* Sets the thread's local storage pointer. Returns 0 if successful or -1
* if failed.
*/
int int
objc_thread_set_data(void *value) __objc_thread_set_data(void *value)
{ {
return pthread_setspecific(_objc_thread_storage, value); return pthread_setspecific(_objc_thread_storage, value);
} }
/******** /* Returns the thread's local storage pointer. */
* Returns the thread's local storage pointer. Returns NULL on failure.
*/
void * void *
objc_thread_get_data(void) __objc_thread_get_data(void)
{ {
void *value = NULL; void *value = NULL;
...@@ -179,240 +131,88 @@ objc_thread_get_data(void) ...@@ -179,240 +131,88 @@ objc_thread_get_data(void)
return NULL; return NULL;
} }
/******** /* Backend mutex functions */
* Allocate a mutex. Return the mutex pointer if successful or NULL if the
* allocation failed for any reason.
*/
objc_mutex_t
objc_mutex_allocate(void)
{
objc_mutex_t mutex;
if (!(mutex = (objc_mutex_t)objc_malloc(sizeof(struct objc_mutex))))
return NULL; /* Abort if malloc failed. */
/* Create PCThread mutex */ /* Allocate a mutex. */
if ( pthread_mutex_init(&(mutex->mutex), NULL) )
{
/* Failed */
objc_free(mutex);
return NULL;
}
mutex->owner = NULL; /* No owner. */
mutex->depth = 0; /* No locks. */
return mutex; /* Return mutex handle. */
}
/********
* Deallocate a mutex. Note that this includes an implicit mutex_lock to
* insure that no one else is using the lock. It is legal to deallocate
* a lock if we have a lock on it, but illegal to deallocate a lock held
* by anyone else.
* Returns the number of locks on the thread. (1 for deallocate).
*/
int int
objc_mutex_deallocate(objc_mutex_t mutex) __objc_mutex_allocate(objc_mutex_t mutex)
{ {
int depth; /* # of locks on mutex. */ if (pthread_mutex_init((pthread_mutex_t *)(&(mutex->backend)), NULL))
return -1;
if (!mutex) /* Is argument bad? */ else
return -1; /* Yes, abort. */ return 0;
depth = objc_mutex_lock(mutex); /* Must have lock. */
/* Destroy PCThread mutex */
pthread_mutex_destroy(&(mutex->mutex));
objc_free(mutex); /* Free memory. */
return depth; /* Return last depth. */
} }
/******** /* Deallocate a mutex. */
* Grab a lock on a mutex. If this thread already has a lock on this mutex
* then we increment the lock count. If another thread has a lock on the
* mutex we block and wait for the thread to release the lock.
* Returns the lock count on the mutex held by this thread.
*/
int int
objc_mutex_lock(objc_mutex_t mutex) __objc_mutex_deallocate(objc_mutex_t mutex)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ if (pthread_mutex_destroy((pthread_mutex_t *)(&(mutex->backend))))
int status; return -1;
else
if (!mutex) /* Is argument bad? */ return 0;
return -1; /* Yes, abort. */
thread_id = objc_thread_id(); /* Get this thread's id. */
if (mutex->owner == thread_id) /* Already own lock? */
{
return ++mutex->depth; /* Yes, increment depth. */
}
/* Lock the PCThread mutex */
status = pthread_mutex_lock(&(mutex->mutex));
if (status)
{
return status; /* Failed */
}
mutex->owner = thread_id; /* Mark thread as owner. */
return mutex->depth = 1; /* Increment depth to end. */
} }
/******** /* Grab a lock on a mutex. */
* Try to grab a lock on a mutex. If this thread already has a lock on
* this mutex then we increment the lock count and return it. If another
* thread has a lock on the mutex returns -1.
*/
int int
objc_mutex_trylock(objc_mutex_t mutex) __objc_mutex_lock(objc_mutex_t mutex)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ return pthread_mutex_lock((pthread_mutex_t *)(&(mutex->backend)));
int status;
if (!mutex) /* Is argument bad? */
return -1; /* Yes, abort. */
thread_id = objc_thread_id(); /* Get this thread's id. */
if (mutex->owner == thread_id) /* Already own lock? */
return ++mutex->depth; /* Yes, increment depth. */
/* Lock the PCThread mutex */
status = pthread_mutex_trylock(&(mutex->mutex));
if (status)
return status; /* Failed */
mutex->owner = thread_id; /* Mark thread as owner. */
return mutex->depth = 1; /* Increment depth to end. */
} }
/******** /* Try to grab a lock on a mutex. */
* Decrements the lock count on this mutex by one. If the lock count reaches
* zero, release the lock on the mutex. Returns the lock count on the mutex.
* It is an error to attempt to unlock a mutex which this thread doesn't hold
* in which case return -1 and the mutex is unaffected.
* Will also return -1 if the mutex free fails.
*/
int int
objc_mutex_unlock(objc_mutex_t mutex) __objc_mutex_trylock(objc_mutex_t mutex)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ return pthread_mutex_trylock((pthread_mutex_t *)(&(mutex->backend)));
int status;
if (!mutex) /* Is argument bad? */
return -1; /* Yes, abort. */
thread_id = objc_thread_id(); /* Get this thread's id. */
if (mutex->owner != thread_id) /* Does some else own lock? */
return -1; /* Yes, abort. */
if (mutex->depth > 1) /* Released last lock? */
return --mutex->depth; /* No, Decrement depth, end.*/
mutex->depth = 0; /* Yes, reset depth to 0. */
mutex->owner = NULL; /* Set owner to "no thread".*/
/* Unlock the PCThread mutex */
status = pthread_mutex_unlock(&(mutex->mutex));
if (status)
return status; /* Failed */
return 0; /* No, return success. */
} }
/******** /* Unlock the mutex */
* Allocate a condition. Return the condition pointer if successful or NULL int
* if the allocation failed for any reason. __objc_mutex_unlock(objc_mutex_t mutex)
*/
objc_condition_t
objc_condition_allocate(void)
{ {
objc_condition_t condition; return pthread_mutex_unlock((pthread_mutex_t *)(&(mutex->backend)));
}
if (!(condition = (objc_condition_t)objc_malloc(
sizeof(struct objc_condition))))
return NULL; /* Abort if malloc failed. */
if ( pthread_cond_init(&(condition->condition), NULL) ) { /* Backend condition mutex functions */
objc_free(condition);
return NULL;
}
return condition; /* Return condition handle. */ /* Allocate a condition. */
int
__objc_condition_allocate(objc_condition_t condition)
{
if (pthread_cond_init((pthread_cond_t *)(&(condition->backend)), NULL))
return -1;
else
return 0;
} }
/******** /* Deallocate a condition. */
* Deallocate a condition. Note that this includes an implicit
* condition_broadcast to insure that waiting threads have the opportunity
* to wake. It is legal to dealloc a condition only if no other
* thread is/will be using it. Here we do NOT check for other threads
* waiting but just wake them up.
*/
int int
objc_condition_deallocate(objc_condition_t condition) __objc_condition_deallocate(objc_condition_t condition)
{ {
pthread_cond_broadcast(&(condition->condition)); return pthread_cond_destroy((pthread_cond_t *)(&(condition->backend)));
pthread_cond_destroy(&(condition->condition));
objc_free(condition);
return 0;
} }
/******** /* Wait on the condition */
* Wait on the condition unlocking the mutex until objc_condition_signal()
* or objc_condition_broadcast() are called for the same condition. The
* given mutex *must* have the depth set to 1 so that it can be unlocked
* here, so that someone else can lock it and signal/broadcast the condition.
* The mutex is used to lock access to the shared data that make up the
* "condition" predicate.
*/
int int
objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex) __objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ return pthread_cond_wait((pthread_cond_t *)(&(condition->backend)),
(pthread_mutex_t *)(&(mutex->backend)));
if (!mutex || !condition) /* Is argument bad? */
return -1; /* Yes, abort. */
thread_id = objc_thread_id(); /* Get this thread's id. */
if (mutex->owner != thread_id) /* Does some else own lock? */
return -1; /* Yes, abort. */
if (mutex->depth > 1) /* Locked more than once ? */
return -1; /* YES, return error */
/* mutex will be unlocked */
mutex->depth = 0; /* Yes, reset depth to 0. */
mutex->owner = (objc_thread_t) -1; /* Set owner to "no thread".*/
pthread_cond_wait(&(condition->condition),
&(mutex->mutex)); /* unlock, wait ..., lock */
mutex->owner = thread_id; /* Mark thread as owner. */
mutex->depth = 1; /* Increment depth to end. */
return 0; /* Return success. */
} }
/******** /* Wake up all threads waiting on this condition. */
* Wake up all threads waiting on this condition. It is recommended that
* the called would lock the same mutex as the threads in objc_condition_wait
* before changing the "condition predicate" and make this call and unlock it
* right away after this call.
*/
int int
objc_condition_broadcast(objc_condition_t condition) __objc_condition_broadcast(objc_condition_t condition)
{ {
if (!condition) return pthread_cond_broadcast((pthread_cond_t *)(&(condition->backend)));
return -1;
pthread_cond_broadcast(&(condition->condition));
return 0;
} }
/******** /* Wake up one thread waiting on this condition. */
* Wake up one thread waiting on this condition. It is recommended that
* the called would lock the same mutex as the threads in objc_condition_wait
* before changing the "condition predicate" and make this call and unlock it
* right away after this call.
*/
int int
objc_condition_signal(objc_condition_t condition) __objc_condition_signal(objc_condition_t condition)
{ {
if (!condition) return pthread_cond_signal((pthread_cond_t *)(&(condition->backend)));
return -1;
pthread_cond_signal(&(condition->condition));
return 0;
} }
/* End of File */ /* End of File */
...@@ -27,214 +27,166 @@ Boston, MA 02111-1307, USA. */ ...@@ -27,214 +27,166 @@ Boston, MA 02111-1307, USA. */
#include <objc/thr.h> #include <objc/thr.h>
#include "runtime.h" #include "runtime.h"
/******** /* Thread local storage for a single thread */
* This structure represents a single mutual exclusion lock. Lock semantics static void *thread_local_storage = NULL;
* are detailed with the subsequent functions. We use whatever lock is
* provided by the system. We augment it with depth and current owner id /* Backend initialization functions */
* fields to implement and re-entrant lock.
*/ /* Initialize the threads subsystem. */
struct objc_mutex
{
volatile objc_thread_t owner; /* Id of thread that owns. */
volatile int depth; /* # of acquires. */
};
/********
* Initialize the threads subsystem. Returns 0 if successful, or -1 if no
* thread support is available.
*/
int int
__objc_init_thread_system(void) __objc_init_thread_system(void)
{ {
DEBUG_PRINTF("__objc_init_thread_system\n"); /* No thread support available */
return -1; /* Failed. */ return -1;
}
/* Close the threads subsystem. */
int
__objc_close_thread_system(void)
{
/* No thread support available */
return -1;
} }
/******** /* Backend thread functions */
* Create a new thread of execution and return its id. Return NULL if fails.
* The new thread starts in "func" with the given argument. /* Create a new thread of execution. */
*/
objc_thread_t objc_thread_t
objc_thread_create(void (*func)(void *arg), void *arg) __objc_thread_detach(void (*func)(void *arg), void *arg)
{ {
return NULL; /* We can't start threads. */ /* No thread support available */
return NULL;
} }
/******** /* Set the current thread's priority. */
* Set the current thread's priority.
*/
int int
objc_thread_set_priority(int priority) __objc_thread_set_priority(int priority)
{ {
return -1; /* Failed. */ /* No thread support available */
return -1;
} }
/******** /* Return the current thread's priority. */
* Return the current thread's priority.
*/
int int
objc_thread_get_priority(void) __objc_thread_get_priority(void)
{ {
return OBJC_THREAD_INTERACTIVE_PRIORITY; /* Highest priority. */ return OBJC_THREAD_INTERACTIVE_PRIORITY;
} }
/******** /* Yield our process time to another thread. */
* Yield our process time to another thread. Any BUSY waiting that is done
* by a thread should use this function to make sure that other threads can
* make progress even on a lazy uniprocessor system.
*/
void void
objc_thread_yield(void) __objc_thread_yield(void)
{ {
return; return;
} }
/******** /* Terminate the current thread. */
* Terminate the current tread. Doesn't return anything. Doesn't return.
* Actually, if it failed returns -1.
*/
int int
objc_thread_exit(void) __objc_thread_exit(void)
{ {
exit(__objc_thread_exit_status); /* No thread support available */
/* Should we really exit the program */
/* exit(&__objc_thread_exit_status); */
return -1; return -1;
} }
/******** /* Returns an integer value which uniquely describes a thread. */
* Returns an integer value which uniquely describes a thread. Must not be
* NULL which is reserved as a marker for "no thread".
*/
objc_thread_t objc_thread_t
objc_thread_id(void) __objc_thread_id(void)
{ {
return (objc_thread_t)1; /* No thread support, use 1.*/ /* No thread support, use 1. */
return (objc_thread_t)1;
} }
/******** /* Sets the thread's local storage pointer. */
* Sets the thread's local storage pointer. Returns 0 if successful or -1
* if failed.
*/
static void *thread_local_storage = NULL;
int int
objc_thread_set_data(void *value) __objc_thread_set_data(void *value)
{ {
thread_local_storage = value; thread_local_storage = value;
return 0; return 0;
} }
/******** /* Returns the thread's local storage pointer. */
* Returns the thread's local storage pointer. Returns NULL on failure.
*/
void * void *
objc_thread_get_data(void) __objc_thread_get_data(void)
{ {
return thread_local_storage; return thread_local_storage;
} }
/******** /* Backend mutex functions */
* Allocate a mutex. Return the mutex pointer if successful or NULL if the
* allocation failed for any reason.
*/
objc_mutex_t
objc_mutex_allocate(void)
{
objc_mutex_t mutex;
if (!(mutex = (objc_mutex_t)objc_malloc(sizeof(struct objc_mutex))))
return NULL; /* Abort if malloc failed. */
mutex->owner = NULL; /* No owner. */ /* Allocate a mutex. */
mutex->depth = 0; /* No locks. */ int
return mutex; /* Return mutex handle. */ __objc_mutex_allocate(objc_mutex_t mutex)
{
return 0;
} }
/******** /* Deallocate a mutex. */
* Deallocate a mutex. Note that this includes an implicit mutex_lock to
* insure that no one else is using the lock. It is legal to deallocate
* a lock if we have a lock on it, but illegal to deallocate a lock held
* by anyone else.
* Returns the number of locks on the thread. (1 for deallocate).
*/
int int
objc_mutex_deallocate(objc_mutex_t mutex) __objc_mutex_deallocate(objc_mutex_t mutex)
{ {
int depth; /* # of locks on mutex. */ return 0;
}
if (!mutex) /* Is argument bad? */
return -1; /* Yes, abort. */
depth = objc_mutex_lock(mutex); /* Must have lock. */
objc_free(mutex); /* Free memory. */ /* Grab a lock on a mutex. */
return depth; /* Return last depth. */ int
__objc_mutex_lock(objc_mutex_t mutex)
{
/* There can only be one thread, so we always get the lock */
return 0;
} }
/******** /* Try to grab a lock on a mutex. */
* Grab a lock on a mutex. If this thread already has a lock on this mutex
* then we increment the lock count. If another thread has a lock on the
* mutex we block and wait for the thread to release the lock.
* Returns the lock count on the mutex held by this thread.
*/
int int
objc_mutex_lock(objc_mutex_t mutex) __objc_mutex_trylock(objc_mutex_t mutex)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ /* There can only be one thread, so we always get the lock */
return 0;
}
if (!mutex) /* Is argument bad? */ /* Unlock the mutex */
return -1; /* Yes, abort. */ int
thread_id = objc_thread_id(); /* Get this thread's id. */ __objc_mutex_unlock(objc_mutex_t mutex)
if (mutex->owner == thread_id) /* Already own lock? */ {
return ++mutex->depth; /* Yes, increment depth. */ return 0;
}
mutex->owner = thread_id; /* Mark thread as owner. */ /* Backend condition mutex functions */
return mutex->depth = 1; /* Increment depth to end. */ /* Allocate a condition. */
int
__objc_condition_allocate(objc_condition_t condition)
{
return 0;
} }
/******** /* Deallocate a condition. */
* Try to grab a lock on a mutex. If this thread already has a lock on
* this mutex then we increment the lock count and return it. If another
* thread has a lock on the mutex returns -1.
*/
int int
objc_mutex_trylock(objc_mutex_t mutex) __objc_condition_deallocate(objc_condition_t condition)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ return 0;
if (!mutex) /* Is argument bad? */
return -1; /* Yes, abort. */
thread_id = objc_thread_id(); /* Get this thread's id. */
if (mutex->owner == thread_id) /* Already own lock? */
return ++mutex->depth; /* Yes, increment depth. */
mutex->owner = thread_id; /* Mark thread as owner. */
return mutex->depth = 1; /* Increment depth to end. */
} }
/******** /* Wait on the condition */
* Decrements the lock count on this mutex by one. If the lock count reaches
* zero, release the lock on the mutex. Returns the lock count on the mutex.
* It is an error to attempt to unlock a mutex which this thread doesn't hold
* in which case return -1 and the mutex is unaffected.
* Will also return -1 if the mutex free fails.
*/
int int
objc_mutex_unlock(objc_mutex_t mutex) __objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ return 0;
}
if (!mutex) /* Is argument bad? */ /* Wake up all threads waiting on this condition. */
return -1; /* Yes, abort. */ int
thread_id = objc_thread_id(); /* Get this thread's id. */ __objc_condition_broadcast(objc_condition_t condition)
if (mutex->owner != thread_id) /* Does some else own lock? */ {
return -1; /* Yes, abort. */ return 0;
if (mutex->depth > 1) /* Released last lock? */ }
return --mutex->depth; /* No, Decrement depth, end.*/
mutex->depth = 0; /* Yes, reset depth to 0. */
mutex->owner = NULL; /* Set owner to "no thread".*/
return 0; /* No, return success. */ /* Wake up one thread waiting on this condition. */
int
__objc_condition_signal(objc_condition_t condition)
{
return 0;
} }
/* End of File */ /* End of File */
...@@ -32,84 +32,56 @@ Boston, MA 02111-1307, USA. */ ...@@ -32,84 +32,56 @@ Boston, MA 02111-1307, USA. */
#include <synch.h> #include <synch.h>
#include <errno.h> #include <errno.h>
/******** /* Key structure for maintiain thread specific storage */
* This structure represents a single mutual exclusion lock. Lock semantics static thread_key_t __objc_thread_data_key;
* are detailed with the subsequent functions. We use whatever lock is
* provided by the system. We augment it with depth and current owner id
* fields to implement and re-entrant lock.
*/
struct objc_mutex
{
volatile objc_thread_t owner; /* Id of thread that owns. */
volatile int depth; /* # of acquires. */
mutex_t lock; /* System mutex. */
};
struct objc_condition /* Backend initialization functions */
{
cond_t condition; /* solaris condition */ /* Initialize the threads subsystem. */
};
/*****************************************************************************
* Static variables.
*/
static thread_key_t __objc_thread_data_key; /* Data key for thread data.*/
/********
* Initialize the threads subsystem. Returns 0 if successful, or -1 if no
* thread support is available.
*/
int int
__objc_init_thread_system(void) __objc_init_thread_system(void)
{ {
DEBUG_PRINTF("__objc_init_thread_system\n"); /* Initialize the thread storage key */
if (thr_keycreate(&__objc_thread_data_key, NULL) == 0) if (thr_keycreate(&__objc_thread_data_key, NULL) == 0)
return 0; /* Yes, return success. */ return 0;
else
return -1; /* Failed. */ return -1;
} }
/* Close the threads subsystem. */
int int
__objc_fini_thread_system(void) __objc_close_thread_system(void)
{ {
return 0; return 0;
} }
/******** /* Backend thread functions */
* Create a new thread of execution and return its id. Return -1 if fails.
* The new thread starts in "func" with the given argument. /* Create a new thread of execution. */
*/
objc_thread_t objc_thread_t
objc_thread_create(void (*func)(void *arg), void *arg) __objc_thread_detach(void (*func)(void *arg), void *arg)
{ {
objc_thread_t thread_id = NULL; /* Detached thread id. */ objc_thread_t thread_id;
thread_t new_thread_id = 0; /* Solaris thread id type. */ thread_t new_thread_id = 0;
int errn;
objc_mutex_lock(__objc_runtime_mutex);
if (thr_create(NULL, 0, (void *)func, arg, if (thr_create(NULL, 0, (void *)func, arg,
THR_DETACHED | THR_NEW_LWP, THR_DETACHED | THR_NEW_LWP,
&new_thread_id) == 0) { /* Created new thread? */ &new_thread_id) == 0)
thread_id = (objc_thread_t)new_thread_id; /* Yes, remember its id. */ thread_id = *(objc_thread_t *)&new_thread_id;
__objc_runtime_threads_alive++; else
} thread_id = NULL;
objc_mutex_unlock(__objc_runtime_mutex);
return thread_id; return thread_id;
} }
/******** /* Set the current thread's priority. */
* Set the current thread's priority.
*/
int int
objc_thread_set_priority(int priority) __objc_thread_set_priority(int priority)
{ {
int sys_priority = 0; int sys_priority = 0;
switch (priority) { switch (priority)
{
case OBJC_THREAD_INTERACTIVE_PRIORITY: case OBJC_THREAD_INTERACTIVE_PRIORITY:
sys_priority = 300; sys_priority = 300;
break; break;
...@@ -122,21 +94,21 @@ objc_thread_set_priority(int priority) ...@@ -122,21 +94,21 @@ objc_thread_set_priority(int priority)
break; break;
} }
/* Change priority */
if (thr_setprio(thr_self(), sys_priority) == 0) if (thr_setprio(thr_self(), sys_priority) == 0)
return 0; /* Changed priority. End. */ return 0;
else
return -1; /* Failed. */ return -1;
} }
/******** /* Return the current thread's priority. */
* Return the current thread's priority.
*/
int int
objc_thread_get_priority(void) __objc_thread_get_priority(void)
{ {
int sys_priority; /* Solaris thread priority. */ int sys_priority;
if (thr_getprio(thr_self(), &sys_priority) == 0) { if (thr_getprio(thr_self(), &sys_priority) == 0)
{
if (sys_priority >= 250) if (sys_priority >= 250)
return OBJC_THREAD_INTERACTIVE_PRIORITY; return OBJC_THREAD_INTERACTIVE_PRIORITY;
else if (sys_priority >= 150) else if (sys_priority >= 150)
...@@ -144,288 +116,144 @@ objc_thread_get_priority(void) ...@@ -144,288 +116,144 @@ objc_thread_get_priority(void)
return OBJC_THREAD_LOW_PRIORITY; return OBJC_THREAD_LOW_PRIORITY;
} }
return -1; /* Couldn't get priority. */ /* Couldn't get priority. */
return -1;
} }
/******** /* Yield our process time to another thread. */
* Yield our process time to another thread. Any BUSY waiting that is done
* by a thread should use this function to make sure that other threads can
* make progress even on a lazy uniprocessor system.
*/
void void
objc_thread_yield(void) __objc_thread_yield(void)
{ {
thr_yield(); /* Yield to equal thread. */ thr_yield();
} }
/******** /* Terminate the current thread. */
* Terminate the current tread. Doesn't return anything. Doesn't return.
* Actually, if it failed returns -1.
*/
int int
objc_thread_exit(void) __objc_thread_exit(void)
{ {
objc_mutex_lock(__objc_runtime_mutex); /* exit the thread */
__objc_runtime_threads_alive++; thr_exit(&__objc_thread_exit_status);
objc_mutex_unlock(__objc_runtime_mutex);
thr_exit(&__objc_thread_exit_status); /* Terminate thread. */ /* Failed if we reached here */
return -1; return -1;
} }
/******** /* Returns an integer value which uniquely describes a thread. */
* Returns an integer value which uniquely describes a thread. Must not be
* NULL which is reserved as a marker for "no thread".
*/
objc_thread_t objc_thread_t
objc_thread_id(void) __objc_thread_id(void)
{ {
return (objc_thread_t)thr_self(); return (objc_thread_t)thr_self();
} }
/******** /* Sets the thread's local storage pointer. */
* Sets the thread's local storage pointer. Returns 0 if successful or -1
* if failed.
*/
int int
objc_thread_set_data(void *value) __objc_thread_set_data(void *value)
{ {
if (thr_setspecific(__objc_thread_data_key, value) == 0) if (thr_setspecific(__objc_thread_data_key, value) == 0)
return 0; return 0;
else
return -1; return -1;
} }
/******** /* Returns the thread's local storage pointer. */
* Returns the thread's local storage pointer. Returns NULL on failure.
*/
void * void *
objc_thread_get_data(void) __objc_thread_get_data(void)
{ {
void * value = NULL; void *value = NULL;
if (thr_getspecific(__objc_thread_data_key, &value) == 0) if (thr_getspecific(__objc_thread_data_key, &value) == 0)
return value; /* Return thread data. */ return value;
return NULL; return NULL;
} }
/******** /* Backend mutex functions */
* Allocate a mutex. Return the mutex pointer if successful or NULL if
* the allocation fails for any reason.
*/
objc_mutex_t
objc_mutex_allocate(void)
{
struct objc_mutex *mutex;
int err = 0;
if (!(mutex = (objc_mutex_t)objc_malloc(sizeof(struct objc_mutex))))
return NULL; /* Abort if malloc failed. */
err = mutex_init(&mutex->lock, USYNC_THREAD, 0);
if (err != 0) { /* System init failed? */
objc_free(mutex); /* Yes, free local memory. */
return NULL; /* Abort. */
}
mutex->owner = NULL; /* No owner. */
mutex->depth = 0; /* No locks. */
return mutex; /* Return mutex handle. */
}
/******** /* Allocate a mutex. */
* Deallocate a mutex. Note that this includes an implicit mutex_lock to
* insure that no one else is using the lock. It is legal to deallocate
* a lock if we have a lock on it, but illegal to deallotcate a lock held
* by anyone else.
* Returns the number of locks on the thread. (1 for deallocate).
*/
int int
objc_mutex_deallocate(objc_mutex_t mutex) __objc_mutex_allocate(objc_mutex_t mutex)
{ {
int depth; /* # of locks on mutex. */ if (mutex_init( (mutex_t *)(&(mutex->backend)), USYNC_THREAD, 0))
return -1;
if (!mutex) /* Is argument bad? */ else
return -1; /* Yes, abort. */ return 0;
depth = objc_mutex_lock(mutex); /* Must have lock. */
mutex_destroy(&mutex->lock); /* System deallocate. */
objc_free(mutex); /* Free memory. */
return depth; /* Return last depth. */
} }
/********
* Grab a lock on a mutex. If this thread already has a lock on this mutex /* Deallocate a mutex. */
* then we increment the lock count. If another thread has a lock on the
* mutex we block and wait for the thread to release the lock.
* Returns the lock count on the mutex held by this thread.
*/
int int
objc_mutex_lock(objc_mutex_t mutex) __objc_mutex_deallocate(objc_mutex_t mutex)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ mutex_destroy((mutex_t *)(&(mutex->backend)));
return 0;
if (!mutex) /* Is argument bad? */
return -1; /* Yes, abort. */
thread_id = objc_thread_id(); /* Get this thread's id. */
if (mutex->owner == thread_id) /* Already own lock? */
return ++mutex->depth; /* Yes, increment depth. */
if (mutex_lock(&mutex->lock) != 0) /* Did lock acquire fail? */
return -1; /* Yes, abort. */
mutex->owner = thread_id; /* Mark thread as owner. */
return mutex->depth = 1; /* Increment depth to end. */
} }
/******** /* Grab a lock on a mutex. */
* Try to grab a lock on a mutex. If this thread already has a lock on
* this mutex then we increment the lock count and return it. If another
* thread has a lock on the mutex returns -1.
*/
int int
objc_mutex_trylock(objc_mutex_t mutex) __objc_mutex_lock(objc_mutex_t mutex)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ if (mutex_lock((mutex_t *)(&(mutex->backend))) != 0)
return -1;
if (!mutex) /* Is argument bad? */ else
return -1; /* Yes, abort. */ return 0;
thread_id = objc_thread_id(); /* Get this thread's id. */
if (mutex->owner == thread_id) /* Already own lock? */
return ++mutex->depth; /* Yes, increment depth. */
if (mutex_trylock(&mutex->lock) != 0) /* Did lock acquire fail? */
return -1; /* Yes, abort. */
mutex->owner = thread_id; /* Mark thread as owner. */
return mutex->depth = 1; /* Increment depth to end. */
} }
/******** /* Try to grab a lock on a mutex. */
* Decrements the lock count on this mutex by one. If the lock count reaches
* zero, release the lock on the mutex. Returns the lock count on the mutex.
* It is an error to attempt to unlock a mutex which this thread doesn't hold
* in which case return -1 and the mutex is unaffected.
* Will also return -1 if the mutex free fails.
*/
int int
objc_mutex_unlock(objc_mutex_t mutex) __objc_mutex_trylock(objc_mutex_t mutex)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ if (mutex_trylock((mutex_t *)(&(mutex->backend))) != 0)
return -1;
if (!mutex) /* Is argument bad? */ else
return -1; /* Yes, abort. */ return 0;
thread_id = objc_thread_id(); /* Get this thread's id. */
if (mutex->owner != thread_id) /* Does some else own lock? */
return -1; /* Yes, abort. */
if (mutex->depth > 1) /* Released last lock? */
return --mutex->depth; /* No, Decrement depth, end.*/
mutex->depth = 0; /* Yes, reset depth to 0. */
mutex->owner = NULL; /* Set owner to "no thread".*/
if (mutex_unlock(&mutex->lock) != 0) /* Did lock release fail? */
return -1; /* Yes, return error value. */
return 0; /* No, return success. */
} }
/******** /* Unlock the mutex */
* Allocate a condition. Return the condition pointer if successful or NULL int
* if the allocation failed for any reason. __objc_mutex_unlock(objc_mutex_t mutex)
*/
objc_condition_t
objc_condition_allocate(void)
{ {
objc_condition_t condition; if (mutex_unlock((mutex_t *)(&(mutex->backend))) != 0)
return -1;
if (!(condition = (objc_condition_t)objc_malloc( else
sizeof(struct objc_condition)))) return 0;
return NULL; /* Abort if malloc failed. */ }
cond_init(&(condition->condition), USYNC_THREAD, NULL); /* Backend condition mutex functions */
return condition; /* Return new condition */ /* Allocate a condition. */
int
__objc_condition_allocate(objc_condition_t condition)
{
return cond_init((cond_t *)(&(condition->backend)), USYNC_THREAD, NULL);
} }
/******** /* Deallocate a condition. */
* Deallocate a condition. Note that this includes an implicit
* condition_broadcast to insure that waiting threads have the opportunity
* to wake. It is legal to dealloc a condition only if no other
* thread is/will be using it. Here we do NOT check for other threads
* waiting but just wake them up.
*/
int int
objc_condition_deallocate(objc_condition_t condition) __objc_condition_deallocate(objc_condition_t condition)
{ {
cond_broadcast(&(condition->condition)); /* Wakeup waiting threads */ return cond_destroy((cond_t *)(&(condition->backend)));
cond_destroy(&(condition->condition)); /* Kill condition */
objc_free(condition); /* Release struct memory */
return 0;
} }
/******** /* Wait on the condition */
* Wait on the condition unlocking the mutex until objc_condition_signal()
* or objc_condition_broadcast() are called for the same condition. The
* given mutex *must* have the depth set to 1 so that it can be unlocked
* here, so that someone else can lock it and signal/broadcast the condition.
* The mutex is used to lock access to the shared data that make up the
* "condition" predicate.
*/
int int
objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex) __objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ return cond_wait((cond_t *)(&(condition->backend)),
(mutex_t *)(&(mutex->backend)));
if (!mutex || !condition) /* Is argument bad? */
return -1; /* Yes, abort. */
thread_id = objc_thread_id(); /* Get this thread's id. */
if (mutex->owner != thread_id) /* Does some else own lock? */
return -1; /* Yes, abort. */
if (mutex->depth > 1) /* Locked more than once ? */
return -1; /* YES, return error */
/* mutex will be unlocked */
mutex->depth = 0; /* Yes, reset depth to 0. */
mutex->owner = (objc_thread_t) -1; /* Set owner to "no thread".*/
cond_wait(&(condition->condition),
&(mutex->lock)); /* unlock, wait ..., lock */
mutex->owner = thread_id; /* Mark thread as owner. */
mutex->depth = 1; /* Must be here ! */
return 0; /* Return success. */
} }
/******** /* Wake up all threads waiting on this condition. */
* Wake up all threads waiting on this condition. It is recommended that
* the called would lock the same mutex as the threads in objc_condition_wait
* before changing the "condition predicate" and make this call and unlock it
* right away after this call.
*/
int int
objc_condition_broadcast(objc_condition_t condition) __objc_condition_broadcast(objc_condition_t condition)
{ {
if (!condition) return cond_broadcast((cond_t *)(&(condition->backend)));
return -1;
cond_broadcast(&(condition->condition));
return 0;
} }
/******** /* Wake up one thread waiting on this condition. */
* Wake up one thread waiting on this condition. It is recommended that
* the called would lock the same mutex as the threads in objc_condition_wait
* before changing the "condition predicate" and make this call and unlock it
* right away after this call.
*/
int int
objc_condition_signal(objc_condition_t condition) __objc_condition_signal(objc_condition_t condition)
{ {
if (!condition) return cond_signal((cond_t *)(&(condition->backend)));
return -1;
cond_signal(&(condition->condition));
return 0;
} }
/* End of File */ /* End of File */
...@@ -32,82 +32,55 @@ Boston, MA 02111-1307, USA. */ ...@@ -32,82 +32,55 @@ Boston, MA 02111-1307, USA. */
#endif #endif
#include <windows.h> #include <windows.h>
/******** /* Key structure for maintiain thread specific storage */
* This structure represents a single mutual exclusion lock. Lock semantics static DWORD __objc_data_tls = (DWORD)-1;
* are detailed with the subsequent functions. We use whatever lock is
* provided by the system. We augment it with depth and current owner id /* Backend initialization functions */
* fields to implement and re-entrant lock.
*/ /* Initialize the threads subsystem. */
struct objc_mutex
{
volatile objc_thread_t owner; /* Id of thread that owns. */
volatile int depth; /* # of acquires. */
HANDLE handle; /* Win32 mutex HANDLE. */
};
/*****************************************************************************
* Static variables.
*/
static DWORD __objc_data_tls = (DWORD)-1; /* Win32 Thread Local Index.*/
/********
* Initialize the threads subsystem. Returns 0 if successful, or -1 if no
* thread support is available.
*/
int int
__objc_init_thread_system(void) __objc_init_thread_system(void)
{ {
DEBUG_PRINTF("__objc_init_thread_system\n"); /* Initialize the thread storage key */
if ((__objc_data_tls = TlsAlloc()) != (DWORD)-1) if ((__objc_data_tls = TlsAlloc()) != (DWORD)-1)
return 0; /* Yes, return success. */ return 0;
else
return -1; /* Failed. */ return -1;
} }
/* Close the threads subsystem. */
int int
__objc_fini_thread_system(void) __objc_close_thread_system(void)
{ {
if (__objc_data_tls != (DWORD)-1) { if (__objc_data_tls != (DWORD)-1)
TlsFree(__objc_data_tls); TlsFree(__objc_data_tls);
return 0; return 0;
}
return -1;
} }
/******** /* Backend thread functions */
* Create a new thread of execution and return its id. Return NULL if fails.
* The new thread starts in "func" with the given argument. /* Create a new thread of execution. */
*/
objc_thread_t objc_thread_t
objc_thread_create(void (*func)(void *arg), void *arg) __objc_thread_detach(void (*func)(void *arg), void *arg)
{ {
DWORD thread_id = 0; /* Detached thread id. */ DWORD thread_id = 0;
HANDLE win32_handle; /* Win32 thread handle. */ HANDLE win32_handle;
objc_mutex_lock(__objc_runtime_mutex);
if ((win32_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func, if (!(win32_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func,
arg, 0, &thread_id))) { arg, 0, &thread_id)))
__objc_runtime_threads_alive++;
}
else
thread_id = 0; thread_id = 0;
objc_mutex_unlock(__objc_runtime_mutex);
return (objc_thread_t)thread_id; return (objc_thread_t)thread_id;
} }
/******** /* Set the current thread's priority. */
* Set the current thread's priority.
*/
int int
objc_thread_set_priority(int priority) __objc_thread_set_priority(int priority)
{ {
int sys_priority = 0; int sys_priority = 0;
switch (priority) { switch (priority)
{
case OBJC_THREAD_INTERACTIVE_PRIORITY: case OBJC_THREAD_INTERACTIVE_PRIORITY:
sys_priority = THREAD_PRIORITY_NORMAL; sys_priority = THREAD_PRIORITY_NORMAL;
break; break;
...@@ -119,23 +92,24 @@ objc_thread_set_priority(int priority) ...@@ -119,23 +92,24 @@ objc_thread_set_priority(int priority)
sys_priority = THREAD_PRIORITY_LOWEST; sys_priority = THREAD_PRIORITY_LOWEST;
break; break;
} }
if (SetThreadPriority(GetCurrentThread(), sys_priority))
return 0; /* Changed priority. End. */
return -1; /* Failed. */ /* Change priority */
if (SetThreadPriority(GetCurrentThread(), sys_priority))
return 0;
else
return -1;
} }
/******** /* Return the current thread's priority. */
* Return the current thread's priority.
*/
int int
objc_thread_get_priority(void) __objc_thread_get_priority(void)
{ {
int sys_priority; int sys_priority;
sys_priority = GetThreadPriority(GetCurrentThread()); sys_priority = GetThreadPriority(GetCurrentThread());
switch (sys_priority) { switch (sys_priority)
{
case THREAD_PRIORITY_HIGHEST: case THREAD_PRIORITY_HIGHEST:
case THREAD_PRIORITY_TIME_CRITICAL: case THREAD_PRIORITY_TIME_CRITICAL:
case THREAD_PRIORITY_ABOVE_NORMAL: case THREAD_PRIORITY_ABOVE_NORMAL:
...@@ -150,188 +124,149 @@ objc_thread_get_priority(void) ...@@ -150,188 +124,149 @@ objc_thread_get_priority(void)
case THREAD_PRIORITY_LOWEST: case THREAD_PRIORITY_LOWEST:
return OBJC_THREAD_LOW_PRIORITY; return OBJC_THREAD_LOW_PRIORITY;
} }
return -1; /* Couldn't get priority. */
/* Couldn't get priority. */
return -1;
} }
/******** /* Yield our process time to another thread. */
* Yield our process time to another thread. Any BUSY waiting that is done
* by a thread should use this function to make sure that other threads can
* make progress even on a lazy uniprocessor system.
*/
void void
objc_thread_yield(void) __objc_thread_yield(void)
{ {
Sleep(0); /* Yield to equal thread. */ Sleep(0);
} }
/******** /* Terminate the current thread. */
* Terminate the current tread. Doesn't return anything. Doesn't return.
* Actually, if it failed returns -1.
*/
int int
objc_thread_exit(void) __objc_thread_exit(void)
{ {
objc_mutex_lock(__objc_runtime_mutex); /* exit the thread */
__objc_runtime_threads_alive--; ExitThread(__objc_thread_exit_status);
objc_mutex_unlock(__objc_runtime_mutex);
ExitThread(__objc_thread_exit_status); /* Terminate thread. */ /* Failed if we reached here */
return -1; return -1;
} }
/******** /* Returns an integer value which uniquely describes a thread. */
* Returns an integer value which uniquely describes a thread. Must not be
* -1 which is reserved as a marker for "no thread".
*/
objc_thread_t objc_thread_t
objc_thread_id(void) __objc_thread_id(void)
{ {
return (objc_thread_t)GetCurrentThreadId(); /* Return thread id. */ return (objc_thread_t)GetCurrentThreadId();
} }
/******** /* Sets the thread's local storage pointer. */
* Sets the thread's local storage pointer. Returns 0 if successful or -1
* if failed.
*/
int int
objc_thread_set_data(void *value) __objc_thread_set_data(void *value)
{ {
if (TlsSetValue(__objc_data_tls, value)) if (TlsSetValue(__objc_data_tls, value))
return 0; /* Return thread data. */ return 0;
else
return -1; return -1;
} }
/******** /* Returns the thread's local storage pointer. */
* Returns the thread's local storage pointer. Returns NULL on failure.
*/
void * void *
objc_thread_get_data(void) __objc_thread_get_data(void)
{ {
return TlsGetValue(__objc_data_tls); /* Return thread data. */ return TlsGetValue(__objc_data_tls); /* Return thread data. */
} }
/******** /* Backend mutex functions */
* Allocate a mutex. Return the mutex pointer if successful or NULL if
* the allocation fails for any reason.
*/
objc_mutex_t
objc_mutex_allocate(void)
{
objc_mutex_t mutex;
int err = 0;
if (!(mutex = (objc_mutex_t)objc_malloc(sizeof(struct objc_mutex))))
return NULL; /* Abort if malloc failed. */
if ((mutex->handle = CreateMutex(NULL, 0, NULL)) == NULL) { /* Allocate a mutex. */
objc_free(mutex); /* Failed, free memory. */ int
return NULL; /* Abort. */ __objc_mutex_allocate(objc_mutex_t mutex)
} {
mutex->owner = NULL; /* No owner. */ if ((mutex->backend = (void *)CreateMutex(NULL, 0, NULL)) == NULL)
mutex->depth = 0; /* No locks. */ return -1;
return mutex; /* Return mutex handle. */ else
return 0;
} }
/******** /* Deallocate a mutex. */
* Deallocate a mutex. Note that this includes an implicit mutex_lock to
* insure that no one else is using the lock. It is legal to deallocate
* a lock if we have a lock on it, but illegal to deallotcate a lock held
* by anyone else.
* Returns the number of locks on the thread. (1 for deallocate).
*/
int int
objc_mutex_deallocate(objc_mutex_t mutex) __objc_mutex_deallocate(objc_mutex_t mutex)
{ {
int depth; /* # of locks on mutex. */ CloseHandle((HANDLE)(mutex->backend));
return 0;
if (!mutex) /* Is argument bad? */ }
return -1; /* Yes, abort. */
depth = objc_mutex_lock(mutex); /* Must have lock. */
CloseHandle(mutex->handle); /* Close Win32 handle. */ /* Grab a lock on a mutex. */
int
__objc_mutex_lock(objc_mutex_t mutex)
{
int status;
objc_free(mutex); /* Free memory. */ status = WaitForSingleObject((HANDLE)(mutex->backend), INFINITE);
return depth; /* Return last depth. */ if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
return -1;
else
return 0;
} }
/******** /* Try to grab a lock on a mutex. */
* Grab a lock on a mutex. If this thread already has a lock on this mutex
* then we increment the lock count. If another thread has a lock on the
* mutex we block and wait for the thread to release the lock.
* Returns the lock count on the mutex held by this thread.
*/
int int
objc_mutex_lock(objc_mutex_t mutex) __objc_mutex_trylock(objc_mutex_t mutex)
{ {
objc_thread_t thread_id; /* Cache our thread id. */
int status; int status;
if (!mutex) /* Is argument bad? */ status = WaitForSingleObject((HANDLE)(mutex->backend), 0);
return -1; /* Yes, abort. */
thread_id = objc_thread_id(); /* Get this thread's id. */
if (mutex->owner == thread_id) /* Already own lock? */
return ++mutex->depth; /* Yes, increment depth. */
status = WaitForSingleObject(mutex->handle, INFINITE);
if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED) if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
return -1; /* Failed, abort. */ return -1;
else
mutex->owner = thread_id; /* Mark thread as owner. */ return 0;
}
return ++mutex->depth; /* Increment depth to end. */ /* Unlock the mutex */
int
__objc_mutex_unlock(objc_mutex_t mutex)
{
if (ReleaseMutex((HANDLE)(mutex->backend)) == 0)
return -1;
else
return 0;
} }
/******** /* Backend condition mutex functions */
* Try to grab a lock on a mutex. If this thread already has a lock on
* this mutex then we increment the lock count and return it. If another /* Allocate a condition. */
* thread has a lock on the mutex returns -1.
*/
int int
objc_mutex_trylock(objc_mutex_t mutex) __objc_condition_allocate(objc_condition_t condition)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ /* Unimplemented. */
DWORD status; /* Return status from Win32.*/ return -1;
}
if (!mutex) /* Is argument bad? */ /* Deallocate a condition. */
return -1; /* Yes, abort. */ int
thread_id = objc_thread_id(); /* Get this thread's id. */ __objc_condition_deallocate(objc_condition_t condition)
if (mutex->owner == thread_id) /* Already own lock? */ {
return ++mutex->depth; /* Yes, increment depth. */ /* Unimplemented. */
return -1;
}
status = WaitForSingleObject(mutex->handle, 0); /* Wait on the condition */
if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED) int
return -1; /* Failed, abort. */ __objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
{
/* Unimplemented. */
return -1;
}
mutex->owner = thread_id; /* Mark thread as owner. */ /* Wake up all threads waiting on this condition. */
return ++mutex->depth; /* Increment depth to end. */ int
__objc_condition_broadcast(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
} }
/******** /* Wake up one thread waiting on this condition. */
* Decrements the lock count on this mutex by one. If the lock count reaches
* zero, release the lock on the mutex. Returns the lock count on the mutex.
* It is an error to attempt to unlock a mutex which this thread doesn't hold
* in which case return -1 and the mutex is unaffected.
* Will also return -1 if the mutex free fails.
*/
int int
objc_mutex_unlock(objc_mutex_t mutex) __objc_condition_signal(objc_condition_t condition)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ /* Unimplemented. */
return -1;
if (!mutex) /* Is argument bad? */
return -1; /* Yes, abort. */
thread_id = objc_thread_id(); /* Get this thread's id. */
if (mutex->owner != thread_id) /* Does some else own lock? */
return -1; /* Yes, abort. */
if (mutex->depth > 1) /* Released last lock? */
return --mutex->depth; /* No, Decrement depth, end.*/
mutex->depth = 0; /* Yes, reset depth to 0. */
mutex->owner = NULL; /* Set owner to "no thread".*/
if (ReleaseMutex(mutex->handle) == 0)
return -1; /* Failed, abort. */
return 0; /* No, return success. */
} }
/* End of File */ /* End of File */
...@@ -27,20 +27,15 @@ Boston, MA 02111-1307, USA. */ ...@@ -27,20 +27,15 @@ Boston, MA 02111-1307, USA. */
#include <stdlib.h> #include <stdlib.h>
#include "runtime.h" #include "runtime.h"
/************************************************************************* /* Global exit status. */
* Universal static variables: int __objc_thread_exit_status = 0;
*/
int __objc_thread_exit_status = 0; /* Global exit status. */
/* Flag which lets us know if we ever became multi threaded */ /* Flag which lets us know if we ever became multi threaded */
int __objc_is_multi_threaded = 0; int __objc_is_multi_threaded = 0;
/* The hook function called when the runtime becomes multi threaded */ /* The hook function called when the runtime becomes multi threaded */
objc_thread_callback _objc_became_multi_threaded = NULL; objc_thread_callback _objc_became_multi_threaded = NULL;
/*****************************************************************************
* Universal Functionality
*/
/* /*
Use this to set the hook function that will be called when the Use this to set the hook function that will be called when the
runtime initially becomes multi threaded. runtime initially becomes multi threaded.
...@@ -60,8 +55,18 @@ objc_thread_callback objc_set_thread_callback(objc_thread_callback func) ...@@ -60,8 +55,18 @@ objc_thread_callback objc_set_thread_callback(objc_thread_callback func)
return temp; return temp;
} }
/******** /*
* First function called in a thread, starts everything else. Private functions
These functions are utilized by the frontend, but they are not
considered part of the public interface.
*/
/*
First function called in a thread, starts everything else.
This function is passed to the backend by objc_thread_detach
as the starting function for a new thread.
*/ */
struct __objc_thread_start_state struct __objc_thread_start_state
{ {
...@@ -73,19 +78,22 @@ struct __objc_thread_start_state ...@@ -73,19 +78,22 @@ struct __objc_thread_start_state
static volatile void static volatile void
__objc_thread_detach_function(struct __objc_thread_start_state *istate) __objc_thread_detach_function(struct __objc_thread_start_state *istate)
{ {
if (istate) { /* Is state valid? */ /* Valid state? */
if (istate) {
id (*imp)(id,SEL,id); id (*imp)(id,SEL,id);
SEL selector = istate->selector; SEL selector = istate->selector;
id object = istate->object; id object = istate->object;
id argument = istate->argument; id argument = istate->argument;
/* Don't need anymore so free it */
objc_free(istate); objc_free(istate);
/* Clear out the thread local storage */ /* Clear out the thread local storage */
objc_thread_set_data(NULL); objc_thread_set_data(NULL);
/* Check to see if we just became multi threaded */ /* Check to see if we just became multi threaded */
if (!__objc_is_multi_threaded) { if (!__objc_is_multi_threaded)
{
__objc_is_multi_threaded = 1; __objc_is_multi_threaded = 1;
/* Call the hook function */ /* Call the hook function */
...@@ -93,61 +101,434 @@ __objc_thread_detach_function(struct __objc_thread_start_state *istate) ...@@ -93,61 +101,434 @@ __objc_thread_detach_function(struct __objc_thread_start_state *istate)
(*_objc_became_multi_threaded)(); (*_objc_became_multi_threaded)();
} }
if ((imp = (id(*)(id, SEL, id))objc_msg_lookup(object, selector))) { /* Call the method */
if ((imp = (id(*)(id, SEL, id))objc_msg_lookup(object, selector)))
(*imp)(object, selector, argument); (*imp)(object, selector, argument);
}
else else
fprintf(stderr, "__objc_thread_start called with bad selector.\n"); objc_error(object, OBJC_ERR_UNIMPLEMENTED,
} "objc_thread_detach called with bad selector.\n");
else {
fprintf(stderr, "__objc_thread_start called with NULL state.\n");
} }
else
objc_error(nil, OBJC_ERR_BAD_STATE,
"objc_thread_detach called with NULL state.\n");
/* Exit the thread */
objc_thread_exit(); objc_thread_exit();
} }
/******** /*
* Detach a new thread of execution and return its id. Returns NULL if fails. Frontend functions
* Thread is started by sending message with selector to object. Message
* takes a single argument. These functions constitute the public interface to the Objective-C thread
and mutex functionality.
*/
/* Frontend thread functions */
/*
Detach a new thread of execution and return its id. Returns NULL if fails.
Thread is started by sending message with selector to object. Message
takes a single argument.
*/ */
objc_thread_t objc_thread_t
objc_thread_detach(SEL selector, id object, id argument) objc_thread_detach(SEL selector, id object, id argument)
{ {
struct __objc_thread_start_state *istate; /* Initialial thread state. */ struct __objc_thread_start_state *istate;
objc_thread_t thread_id = NULL; /* Detached thread id. */ objc_thread_t thread_id = NULL;
/* Allocate the state structure */
if (!(istate = (struct __objc_thread_start_state *) if (!(istate = (struct __objc_thread_start_state *)
objc_malloc(sizeof(*istate)))) /* Can we allocate state? */ objc_malloc(sizeof(*istate))))
return NULL; /* No, abort. */ return NULL;
istate->selector = selector; /* Initialize the thread's */ /* Initialize the state structure */
istate->object = object; /* state structure. */ istate->selector = selector;
istate->object = object;
istate->argument = argument; istate->argument = argument;
if ((thread_id = objc_thread_create((void *)__objc_thread_detach_function, /* lock access */
istate)) == NULL) { objc_mutex_lock(__objc_runtime_mutex);
objc_free(istate); /* Release state if failed. */
return thread_id; /* Call the backend to spawn the thread */
if ((thread_id = __objc_thread_detach((void *)__objc_thread_detach_function,
istate)) == NULL)
{
/* failed! */
objc_mutex_unlock(__objc_runtime_mutex);
objc_free(istate);
return NULL;
} }
/* Increment our thread counter */
__objc_runtime_threads_alive++;
objc_mutex_unlock(__objc_runtime_mutex);
return thread_id; return thread_id;
} }
#undef objc_mutex_lock() /* Set the current thread's priority. */
#undef objc_mutex_unlock() int
objc_thread_set_priority(int priority)
{
/* Call the backend */
return __objc_thread_set_priority(priority);
}
/* Return the current thread's priority. */
int
objc_thread_get_priority(void)
{
/* Call the backend */
return __objc_thread_get_priority();
}
/*
Yield our process time to another thread. Any BUSY waiting that is done
by a thread should use this function to make sure that other threads can
make progress even on a lazy uniprocessor system.
*/
void
objc_thread_yield(void)
{
/* Call the backend */
__objc_thread_yield();
}
/*
Terminate the current tread. Doesn't return.
Actually, if it failed returns -1.
*/
int
objc_thread_exit(void)
{
/* Decrement our counter of the number of threads alive */
objc_mutex_lock(__objc_runtime_mutex);
__objc_runtime_threads_alive--;
objc_mutex_unlock(__objc_runtime_mutex);
/* Call the backend to terminate the thread */
return __objc_thread_exit();
}
/*
Returns an integer value which uniquely describes a thread. Must not be
NULL which is reserved as a marker for "no thread".
*/
objc_thread_t
objc_thread_id(void)
{
/* Call the backend */
return __objc_thread_id();
}
/*
Sets the thread's local storage pointer.
Returns 0 if successful or -1 if failed.
*/
int
objc_thread_set_data(void *value)
{
/* Call the backend */
return __objc_thread_set_data(value);
}
/*
Returns the thread's local storage pointer. Returns NULL on failure.
*/
void *
objc_thread_get_data(void)
{
/* Call the backend */
return __objc_thread_get_data();
}
/* Frontend mutex functions */
/*
Allocate a mutex. Return the mutex pointer if successful or NULL if the
allocation failed for any reason.
*/
objc_mutex_t
objc_mutex_allocate(void)
{
objc_mutex_t mutex;
/* Allocate the mutex structure */
if (!(mutex = (objc_mutex_t)objc_malloc(sizeof(struct objc_mutex))))
return NULL;
/* Call backend to create the mutex */
if (__objc_mutex_allocate(mutex))
{
/* failed! */
objc_free(mutex);
return NULL;
}
/* Initialize mutex */
mutex->owner = NULL;
mutex->depth = 0;
return mutex;
}
/*
Deallocate a mutex. Note that this includes an implicit mutex_lock to
insure that no one else is using the lock. It is legal to deallocate
a lock if we have a lock on it, but illegal to deallocate a lock held
by anyone else.
Returns the number of locks on the thread. (1 for deallocate).
*/
int
objc_mutex_deallocate(objc_mutex_t mutex)
{
int depth;
/* Valid mutex? */
if (!mutex)
return -1;
/* Acquire lock on mutex */
depth = objc_mutex_lock(mutex);
/* Call backend to destroy mutex */
if (__objc_mutex_deallocate(mutex))
return -1;
/* Free the mutex structure */
objc_free(mutex);
/* Return last depth */
return depth;
}
/*
Grab a lock on a mutex. If this thread already has a lock on this mutex
then we increment the lock count. If another thread has a lock on the
mutex we block and wait for the thread to release the lock.
Returns the lock count on the mutex held by this thread.
*/
int
objc_mutex_lock(objc_mutex_t mutex)
{
objc_thread_t thread_id;
int status;
/* Valid mutex? */
if (!mutex)
return -1;
/* If we already own the lock then increment depth */
thread_id = objc_thread_id();
if (mutex->owner == thread_id)
return ++mutex->depth;
/* Call the backend to lock the mutex */
status = __objc_mutex_lock(mutex);
/* Failed? */
if (status)
return status;
/* Successfully locked the thread */
mutex->owner = thread_id;
return mutex->depth = 1;
}
/*
Try to grab a lock on a mutex. If this thread already has a lock on
this mutex then we increment the lock count and return it. If another
thread has a lock on the mutex returns -1.
*/
int int
objc_mutex_unlock_x(objc_mutex_t mutex, const char *f, int l) objc_mutex_trylock(objc_mutex_t mutex)
{ {
printf("%16.16s#%4d < unlock", f, l); objc_thread_t thread_id;
return objc_mutex_unlock(mutex); int status;
/* Valid mutex? */
if (!mutex)
return -1;
/* If we already own the lock then increment depth */
thread_id = objc_thread_id();
if (mutex->owner == thread_id)
return ++mutex->depth;
/* Call the backend to try to lock the mutex */
status = __objc_mutex_trylock(mutex);
/* Failed? */
if (status)
return status;
/* Successfully locked the thread */
mutex->owner = thread_id;
return mutex->depth = 1;
} }
/*
Unlocks the mutex by one level.
Decrements the lock count on this mutex by one.
If the lock count reaches zero, release the lock on the mutex.
Returns the lock count on the mutex.
It is an error to attempt to unlock a mutex which this thread
doesn't hold in which case return -1 and the mutex is unaffected.
*/
int int
objc_mutex_lock_x(objc_mutex_t mutex, const char *f, int l) objc_mutex_unlock(objc_mutex_t mutex)
{ {
printf("%16.16s#%4d < lock", f, l); objc_thread_t thread_id;
return objc_mutex_lock(mutex); int status;
/* Valid mutex? */
if (!mutex)
return -1;
/* If another thread owns the lock then abort */
thread_id = objc_thread_id();
if (mutex->owner != thread_id)
return -1;
/* Decrement depth and return */
if (mutex->depth > 1)
return --mutex->depth;
/* Depth down to zero so we are no longer the owner */
mutex->depth = 0;
mutex->owner = NULL;
/* Have the backend unlock the mutex */
status = __objc_mutex_unlock(mutex);
/* Failed? */
if (status)
return status;
return 0;
}
/* Frontend condition mutex functions */
/*
Allocate a condition. Return the condition pointer if successful or NULL
if the allocation failed for any reason.
*/
objc_condition_t
objc_condition_allocate(void)
{
objc_condition_t condition;
/* Allocate the condition mutex structure */
if (!(condition =
(objc_condition_t)objc_malloc(sizeof(struct objc_condition))))
return NULL;
/* Call the backend to create the condition mutex */
if (__objc_condition_allocate(condition))
{
/* failed! */
objc_free(condition);
return NULL;
}
/* Success! */
return condition;
}
/*
Deallocate a condition. Note that this includes an implicit
condition_broadcast to insure that waiting threads have the opportunity
to wake. It is legal to dealloc a condition only if no other
thread is/will be using it. Here we do NOT check for other threads
waiting but just wake them up.
*/
int
objc_condition_deallocate(objc_condition_t condition)
{
/* Broadcast the condition */
if (objc_condition_broadcast(condition))
return -1;
/* Call the backend to destroy */
if (__objc_condition_deallocate(condition))
return -1;
/* Free the condition mutex structure */
objc_free(condition);
return 0;
}
/*
Wait on the condition unlocking the mutex until objc_condition_signal()
or objc_condition_broadcast() are called for the same condition. The
given mutex *must* have the depth set to 1 so that it can be unlocked
here, so that someone else can lock it and signal/broadcast the condition.
The mutex is used to lock access to the shared data that make up the
"condition" predicate.
*/
int
objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
{
objc_thread_t thread_id;
/* Valid arguments? */
if (!mutex || !condition)
return -1;
/* Make sure we are owner of mutex */
thread_id = objc_thread_id();
if (mutex->owner != thread_id)
return -1;
/* Cannot be locked more than once */
if (mutex->depth > 1)
return -1;
/* Virtually unlock the mutex */
mutex->depth = 0;
mutex->owner = (objc_thread_t)NULL;
/* Call the backend to wait */
__objc_condition_wait(condition, mutex);
/* Make ourselves owner of the mutex */
mutex->owner = thread_id;
mutex->depth = 1;
return 0;
}
/*
Wake up all threads waiting on this condition. It is recommended that
the called would lock the same mutex as the threads in objc_condition_wait
before changing the "condition predicate" and make this call and unlock it
right away after this call.
*/
int
objc_condition_broadcast(objc_condition_t condition)
{
/* Valid condition mutex? */
if (!condition)
return -1;
return __objc_condition_broadcast(condition);
}
/*
Wake up one thread waiting on this condition. It is recommended that
the called would lock the same mutex as the threads in objc_condition_wait
before changing the "condition predicate" and make this call and unlock it
right away after this call.
*/
int
objc_condition_signal(objc_condition_t condition)
{
/* Valid condition mutex? */
if (!condition)
return -1;
return __objc_condition_signal(condition);
} }
/* End of File */ /* End of File */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment