Commit 2024f9e4 by Richard Kenner

Completely rework according to new interface.

From-SVN: r14310
parent f15e9e7e
...@@ -28,299 +28,254 @@ Boston, MA 02111-1307, USA. */ ...@@ -28,299 +28,254 @@ 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. */
};
/*****************************************************************************
* 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)
{ {
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,
(void *)func, arg) == 0)
if (pthread_create(&new_thread_handle, pthread_attr_default, {
(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
objc_mutex_unlock(__objc_runtime_mutex); thread_id = NULL;
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;
default: default:
case OBJC_THREAD_BACKGROUND_PRIORITY: case OBJC_THREAD_BACKGROUND_PRIORITY:
sys_priority = (PRI_BG_MIN_NP + PRI_BG_MAX_NP) / 2; sys_priority = (PRI_BG_MIN_NP + PRI_BG_MAX_NP) / 2;
break; break;
case OBJC_THREAD_LOW_PRIORITY: case OBJC_THREAD_LOW_PRIORITY:
sys_priority = (PRI_BG_MIN_NP + PRI_BG_MAX_NP) / 2; sys_priority = (PRI_BG_MIN_NP + PRI_BG_MAX_NP) / 2;
break; break;
} }
if (pthread_setprio(pthread_self(), sys_priority) >= 0) /* Change the priority. */
return 0; /* Changed priority. End. */ if (pthread_setprio(pthread_self(), sys_priority) >= 0)
return 0;
return -1; /* Failed. */ else
/* 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)
return OBJC_THREAD_INTERACTIVE_PRIORITY; return OBJC_THREAD_INTERACTIVE_PRIORITY;
if (sys_priority >= PRI_BG_MIN_NP && sys_priority <= PRI_BG_MAX_NP) if (sys_priority >= PRI_BG_MIN_NP && sys_priority <= PRI_BG_MAX_NP)
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);
/* Failed if we reached here */
pthread_exit(&__objc_thread_exit_status); /* Terminate thread. */
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;
if (!(mutex = (objc_mutex_t)objc_malloc(sizeof(struct objc_mutex)))) else
return NULL; /* Abort if malloc failed. */ return 0;
err = pthread_mutex_init(&mutex->lock, pthread_mutexattr_default);
if (err != 0) { /* System init failed? */
objc_free(mutex); /* Yes, free local memory. */
return NULL; /* Abort. */
}
mutex->owner = (objc_thread_t) -1; /* 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. */ if (pthread_mutex_destroy((pthread_mutex_t *)(&(mutex->backend))))
return -1;
else
return 0;
}
if (!mutex) /* Is argument bad? */ /* Grab a lock on a mutex. */
return -1; /* Yes, abort. */ int
depth = objc_mutex_lock(mutex); /* Must have lock. */ __objc_mutex_lock(objc_mutex_t mutex)
{
pthread_mutex_unlock(&mutex->lock); /* Must unlock system mutex.*/ return pthread_mutex_lock((pthread_mutex_t *)(&(mutex->backend)));
pthread_mutex_destroy(&mutex->lock); /* Free system mutex. */
objc_free(mutex); /* Free memory. */
return depth; /* Return last depth. */
} }
/******** /* 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. */ if (pthread_mutex_trylock((pthread_mutex_t *)(&(mutex->backend))) != 1)
return -1;
else
return 0;
}
/* Unlock the mutex */
int
__objc_mutex_unlock(objc_mutex_t mutex)
{
return pthread_mutex_unlock((pthread_mutex_t *)(&(mutex->backend)));
}
if (!mutex) /* Is argument bad? */ /* Backend condition mutex functions */
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. */ /* Allocate a condition. */
return -1; /* Failed, abort. */ int
__objc_condition_allocate(objc_condition_t condition)
mutex->owner = thread_id; /* Mark thread as owner. */ {
return mutex->depth = 1; /* Increment depth to end. */ /* Unimplemented. */
return -1;
/*
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. */ /* Unimplemented. */
return -1;
if (!mutex) /* Is argument bad? */ /*
return -1; /* Yes, abort. */ return pthread_cond_destroy((pthread_cond_t *)(&(condition->backend)));
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. */
return -1; /* Failed, abort. */
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. */ /* 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_wait((pthread_cond_t *)(&(condition->backend)),
if (mutex->owner != thread_id) /* Does some else own lock? */ (pthread_mutex_t *)(&(mutex->backend)));
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. */ /* Wake up all threads waiting on this condition. */
mutex->owner = (objc_thread_t) -1; /* Set owner to "no thread".*/ int
__objc_condition_broadcast(objc_condition_t condition)
if (pthread_mutex_unlock(&mutex->lock) != 0) /* Unlock system mutex. */ {
return -1; /* Failed, abort. */ /* Unimplemented. */
return -1;
return 0; /* No, return success. */
/*
return pthread_cond_broadcast((pthread_cond_t *)(&(condition->backend)));
*/
}
/* Wake up one thread waiting on this condition. */
int
__objc_condition_signal(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
/*
return pthread_cond_signal((pthread_cond_t *)(&(condition->backend)));
*/
} }
/* 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");
sprintf(arena_name, "/usr/tmp/objc_%05u", (unsigned)getpid()); DEBUG_PRINTF("__objc_init_thread_system\n");
usconfig(CONF_INITUSERS, 256); /* Up to 256 threads. */
usconfig(CONF_ARENATYPE, US_SHAREDONLY); /* Arena only for threads. */ /* Construct a temporary name for arena. */
if (!(__objc_shared_arena_handle = usinit(arena_name))) /* Init Failed? */ sprintf(arena_name, "/usr/tmp/objc_%05u", (unsigned)getpid());
return -1; /* Yes, return error code. */
/* Up to 256 threads. Arena only for threads. */
return 0; usconfig(CONF_INITUSERS, 256);
usconfig(CONF_ARENATYPE, US_SHAREDONLY);
/* Initialize the arena */
if (!(__objc_shared_arena_handle = usinit(arena_name)))
/* Failed */
return -1;
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; else
__objc_runtime_threads_alive++; 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);
}
/* Backend mutex functions */
/* Allocate a mutex. */
int
__objc_mutex_allocate(objc_mutex_t mutex)
{
if (!( (ulock_t)(mutex->backend) = usnewlock(__objc_shared_arena_handle) ))
return -1;
else
return 0;
}
/* Deallocate a mutex. */
int
__objc_mutex_deallocate(objc_mutex_t mutex)
{ {
return *((void **)&PRDA->usr_prda); /* Return thread data ptr. */ usfreelock((ulock_t)(mutex->backend), __objc_shared_arena_handle);
return 0;
} }
/******** /* Grab a lock on a mutex. */
* Allocate a mutex. int
* Return the mutex pointer if successful or NULL if the allocation failed __objc_mutex_lock(objc_mutex_t mutex)
* for any reason.
*/
objc_mutex_t
objc_mutex_allocate(void)
{ {
objc_mutex_t mutex; if (ussetlock((ulock_t)(mutex->backend)) == 0)
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. */
} }
/******** /* Try to grab a lock on 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_trylock(objc_mutex_t mutex)
{ {
int depth; /* # of locks on mutex. */ if (ustestlock((ulock_t)(mutex->backend)) == 0)
return -1;
if (!mutex) /* Is argument bad? */ else
return -1; /* Yes, abort. */ return 0;
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. */
} }
/******** /* Unlock the 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_unlock(objc_mutex_t mutex)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ usunsetlock((ulock_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? */
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. */
} }
/******** /* 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. */
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 (ustestlock(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. */
} }
/******** /* Deallocate a condition. */
* Decrements the lock count on this mutex by one. If the lock count reaches int
* zero, release the lock on the mutex. Returns the lock count on the mutex. __objc_condition_deallocate(objc_condition_t condition)
* 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. /* Unimplemented. */
* Will also return -1 if the mutex free fails. return -1;
*/ }
/* Wait on the condition */
int
__objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
{
/* Unimplemented. */
return -1;
}
/* Wake up all threads waiting on this condition. */
int
__objc_condition_broadcast(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
}
/* Wake up one thread waiting on this condition. */
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. */
DEBUG_PRINTF("unlock by: %d:%d\n", mutex->owner, mutex->depth - 1);
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".*/
usunsetlock(mutex->lock); /* Free lock. */
return 0; /* No, return success. */
} }
/* End of File */ /* End of File */
...@@ -31,434 +31,282 @@ Boston, MA 02111-1307, USA. */ ...@@ -31,434 +31,282 @@ 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. */ thread_t threadP;
volatile int depth; /* # of acquires. */ kern_return_t error;
struct mutex lock; /* cthread mutex */ struct thread_sched_info info;
}; unsigned int info_count=THREAD_SCHED_INFO_COUNT;
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;
kern_return_t error;
struct thread_sched_info info;
unsigned int info_count=THREAD_SCHED_INFO_COUNT;
if (t == NULL) if (t == NULL)
return -1; return -1;
threadP = cthread_thread(t); /* get thread underlying */ threadP = cthread_thread(t); /* get thread underlying */
error=thread_info(threadP, THREAD_SCHED_INFO, error=thread_info(threadP, THREAD_SCHED_INFO,
(thread_info_t)&info, &info_count); (thread_info_t)&info, &info_count);
if (error != KERN_SUCCESS) if (error != KERN_SUCCESS)
return -1; return -1;
if (base != NULL) if (base != NULL)
*base = info.base_priority; *base = info.base_priority;
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 */
new_thread_handle = cthread_fork((cthread_fn_t)func, arg);
/* create thread */
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
objc_mutex_unlock(__objc_runtime_mutex); thread_id = NULL;
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;
int maxPriority = __mach_get_max_thread_priority(cT, NULL); int maxPriority = __mach_get_max_thread_priority(cT, NULL);
int sys_priority = 0; int sys_priority = 0;
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;
case OBJC_THREAD_BACKGROUND_PRIORITY: case OBJC_THREAD_BACKGROUND_PRIORITY:
sys_priority = (maxPriority * 2) / 3; sys_priority = (maxPriority * 2) / 3;
break; break;
case OBJC_THREAD_LOW_PRIORITY: case OBJC_THREAD_LOW_PRIORITY:
sys_priority = maxPriority / 3; sys_priority = maxPriority / 3;
break; break;
default: default:
return -1; return -1;
} }
if (sys_priority == 0) if (sys_priority == 0)
return -1; return -1;
if (cthread_priority(cT, sys_priority, 0) == KERN_SUCCESS) /* Change the priority */
return 0; /* Changed priority. End. */ if (cthread_priority(cT, sys_priority, 0) == KERN_SUCCESS)
return 0;
return -1; /* Failed. */ else
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() */
int basePriority; int basePriority;
int maxPriority; int maxPriority;
int sys_priority = 0; int sys_priority = 0;
int interactiveT, backgroundT, lowT; /* threasholds */ int interactiveT, backgroundT, lowT; /* threasholds */
maxPriority = __mach_get_max_thread_priority(cT, &basePriority); maxPriority = __mach_get_max_thread_priority(cT, &basePriority);
if(maxPriority == -1) if(maxPriority == -1)
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);
/* Failed if we reached here */
cthread_exit(&__objc_thread_exit_status); /* Terminate thread. */
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))))
return NULL; /* Abort if malloc failed. */
err = mutex_init(&(mutex->lock)); err = mutex_init((mutex_t)(mutex->backend));
if (err != 0) { /* System init failed? */ if (err != 0)
objc_free(mutex); /* Yes, free local memory. */ {
return NULL; /* Abort. */ objc_free(mutex->backend);
return -1;
} }
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)); /* Allocate a condition. */
int
return condition; /* Return mutex handle. */ __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; return 0;
condition_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) condition_signal((condition_t)(condition->backend));
return -1; return 0;
condition_signal(&(condition->condition));
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,210 +100,168 @@ objc_thread_set_priority(int priority) ...@@ -132,210 +100,168 @@ objc_thread_set_priority(int priority)
sys_priority = 0; sys_priority = 0;
break; break;
} }
/* Change priority */
if (!DosSetPriority (PRTYS_THREAD,sys_class,sys_priority,*_threadid)) if (!DosSetPriority (PRTYS_THREAD,sys_class,sys_priority,*_threadid))
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)
{ {
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)
{
case PRTYC_IDLETIME:
case PRTYC_REGULAR:
case PRTYC_TIMECRITICAL:
case PRTYC_FOREGROUNDSERVER:
default:
return OBJC_THREAD_INTERACTIVE_PRIORITY;
}
switch (ptib->tib_ptib2->tib2_ulpri) { return -1;
case PRTYC_IDLETIME:
case PRTYC_REGULAR:
case PRTYC_TIMECRITICAL:
case PRTYC_FOREGROUNDSERVER:
default:
return OBJC_THREAD_INTERACTIVE_PRIORITY;
}
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)
{ {
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))))
return NULL; /* Abort if malloc failed. */
if (DosCreateMutexSem (NULL,&(mutex->handle),0L,0) > 0) {
objc_free(mutex);
return NULL;
}
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)
{
if (DosCreateMutexSem (NULL, (HMTX)(&(mutex->backend)),0L,0) > 0)
return -1;
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. */ 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 */
return -1; int
__objc_mutex_unlock(objc_mutex_t mutex)
{
if (DosReleaseMutexSem((HMTX)(mutex->backend)) != 0)
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 */
return -1; int
__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 (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, (void *)func, arg)) )
thread_id = *(objc_thread_t *)&new_thread_handle;
if (pthread_create(&new_thread_handle, NULL, else
(void *)func, arg) == 0) { thread_id = NULL;
thread_id = (objc_thread_t) new_thread_handle;
pthread_detach(new_thread_handle); /* Fully detach thread. */ return thread_id;
__objc_runtime_threads_alive++;
}
objc_mutex_unlock(__objc_runtime_mutex);
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);
/* Failed if we reached here */
pthread_exit(&__objc_thread_exit_status); /* Terminate thread. */
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_storage);
}
/* Backend mutex functions */
/* Allocate a mutex. */
int
__objc_mutex_allocate(objc_mutex_t mutex)
{ {
return pthread_getspecific(__objc_thread_data_key); if (pthread_mutex_init((pthread_mutex_t *)(&(mutex->backend)), NULL))
return -1;
else
return 0;
} }
/******** /* Deallocate a mutex. */
* Allocate a mutex. Return the mutex pointer if successful or NULL if int
* the allocation fails for any reason. __objc_mutex_deallocate(objc_mutex_t mutex)
*/
objc_mutex_t
objc_mutex_allocate(void)
{ {
objc_mutex_t mutex; if (pthread_mutex_destroy((pthread_mutex_t *)(&(mutex->backend))))
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. */
err = pthread_mutex_init(&mutex->lock, NULL);
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. */
} }
/******** /* Grab a lock on 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_lock(objc_mutex_t mutex)
{ {
int depth; /* # of locks on mutex. */ return pthread_mutex_lock((pthread_mutex_t *)(&(mutex->backend)));
if (!mutex) /* Is argument bad? */
return -1; /* Yes, abort. */
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. */
return depth; /* Return last depth. */
} }
/******** /* 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? */
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. */
} }
/******** /* Unlock the 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_unlock(objc_mutex_t mutex)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ return pthread_mutex_unlock((pthread_mutex_t *)(&(mutex->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. */
return -1; /* Failed, abort. */
mutex->owner = thread_id; /* Mark thread as owner. */
return mutex->depth = 1; /* Increment depth to end. */
} }
/******** /* 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. /* Allocate a condition. */
* 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_allocate(objc_condition_t condition)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ if (pthread_cond_init((pthread_cond_t *)(&(condition->backend)), NULL))
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 (pthread_mutex_unlock(&mutex->lock) != 0) /* Unlock system mutex. */
return -1; /* Failed, abort. */
return 0; /* No, return success. */
} }
/* Deallocate a condition. */
int
__objc_condition_deallocate(objc_condition_t condition)
{
return pthread_cond_destroy((pthread_cond_t *)(&(condition->backend)));
}
/* Wait on the condition */
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)));
}
/* Wake up all threads waiting on this condition. */
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. */
int
__objc_condition_signal(objc_condition_t condition)
{
return pthread_cond_signal((pthread_cond_t *)(&(condition->backend)));
}
/* 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);
/* Failed if we reached here */
pthread_exit(&__objc_thread_exit_status); /* Terminate thread. */
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. /* 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)), NULL))
return -1;
if (!(mutex = (objc_mutex_t)objc_malloc(sizeof(struct objc_mutex)))) else
return NULL; /* Abort if malloc failed. */ return 0;
/* Create PCThread 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. */
* 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. */ 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. */
/* Destroy PCThread mutex */
pthread_mutex_destroy(&(mutex->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. */ 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_lock(&(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. */
* 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. */ 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) /* 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. */
} }
/******** /* 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. */ return pthread_mutex_unlock((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. */
} }
/******** /* Backend condition mutex functions */
* Allocate a condition. Return the condition pointer if successful or NULL
* if the allocation failed for any reason. /* Allocate a condition. */
*/ int
objc_condition_t __objc_condition_allocate(objc_condition_t condition)
objc_condition_allocate(void)
{ {
objc_condition_t condition; if (pthread_cond_init((pthread_cond_t *)(&(condition->backend)), NULL))
return -1;
if (!(condition = (objc_condition_t)objc_malloc( else
sizeof(struct objc_condition)))) return 0;
return NULL; /* Abort if malloc failed. */
if ( pthread_cond_init(&(condition->condition), NULL) ) {
objc_free(condition);
return NULL;
}
return condition; /* Return condition handle. */
} }
/******** /* 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. /* Allocate a mutex. */
*/ int
objc_mutex_t __objc_mutex_allocate(objc_mutex_t mutex)
objc_mutex_allocate(void) {
{ return 0;
objc_mutex_t mutex; }
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)
mutex->owner = NULL; /* No owner. */ {
mutex->depth = 0; /* No locks. */ return 0;
return mutex; /* Return mutex handle. */ }
}
/* Grab a lock on a mutex. */
/******** int
* Deallocate a mutex. Note that this includes an implicit mutex_lock to __objc_mutex_lock(objc_mutex_t mutex)
* 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 /* There can only be one thread, so we always get the lock */
* by anyone else. return 0;
* Returns the number of locks on the thread. (1 for deallocate). }
*/
int /* Try to grab a lock on a mutex. */
objc_mutex_deallocate(objc_mutex_t mutex) int
{ __objc_mutex_trylock(objc_mutex_t mutex)
int depth; /* # of locks on mutex. */ {
/* There can only be one thread, so we always get the lock */
if (!mutex) /* Is argument bad? */ return 0;
return -1; /* Yes, abort. */ }
depth = objc_mutex_lock(mutex); /* Must have lock. */
/* Unlock the mutex */
objc_free(mutex); /* Free memory. */ int
return depth; /* Return last depth. */ __objc_mutex_unlock(objc_mutex_t mutex)
} {
return 0;
/******** }
* 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 /* Backend condition mutex functions */
* mutex we block and wait for the thread to release the lock.
* Returns the lock count on the mutex held by this thread. /* Allocate a condition. */
*/ int
int __objc_condition_allocate(objc_condition_t condition)
objc_mutex_lock(objc_mutex_t mutex) {
{ return 0;
objc_thread_t thread_id; /* Cache our thread id. */ }
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. */ return 0;
}
mutex->owner = thread_id; /* Mark thread as owner. */
/* Wait on the condition */
return mutex->depth = 1; /* Increment depth to end. */ int
} __objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
{
/******** return 0;
* 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. /* Wake up all threads waiting on this condition. */
*/ int
int __objc_condition_broadcast(objc_condition_t condition)
objc_mutex_trylock(objc_mutex_t mutex) {
{ return 0;
objc_thread_t thread_id; /* Cache our thread id. */ }
if (!mutex) /* Is argument bad? */ /* Wake up one thread waiting on this condition. */
return -1; /* Yes, abort. */ int
thread_id = objc_thread_id(); /* Get this thread's id. */ __objc_condition_signal(objc_condition_t condition)
if (mutex->owner == thread_id) /* Already own lock? */ {
return ++mutex->depth; /* Yes, increment depth. */ return 0;
mutex->owner = thread_id; /* Mark thread as owner. */
return mutex->depth = 1; /* Increment depth to end. */
}
/********
* 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
objc_mutex_unlock(objc_mutex_t mutex)
{
objc_thread_t thread_id; /* Cache our thread id. */
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".*/
return 0; /* No, return success. */
} }
/* End of File */ /* End of File */
...@@ -32,400 +32,228 @@ Boston, MA 02111-1307, USA. */ ...@@ -32,400 +32,228 @@ 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;
return 0; /* Yes, return success. */ else
return -1;
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 -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;
default: default:
case OBJC_THREAD_BACKGROUND_PRIORITY: case OBJC_THREAD_BACKGROUND_PRIORITY:
sys_priority = 200; sys_priority = 200;
break; break;
case OBJC_THREAD_LOW_PRIORITY: case OBJC_THREAD_LOW_PRIORITY:
sys_priority = 1000; sys_priority = 1000;
break; break;
} }
if (thr_setprio(thr_self(), sys_priority) == 0) /* Change priority */
return 0; /* Changed priority. End. */ if (thr_setprio(thr_self(), sys_priority) == 0)
return 0;
return -1; /* Failed. */ 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; /* 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) {
return OBJC_THREAD_INTERACTIVE_PRIORITY; if (sys_priority >= 250)
else if (sys_priority >= 150) return OBJC_THREAD_INTERACTIVE_PRIORITY;
return OBJC_THREAD_BACKGROUND_PRIORITY; else if (sys_priority >= 150)
return OBJC_THREAD_LOW_PRIORITY; return OBJC_THREAD_BACKGROUND_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);
/* Failed if we reached here */
thr_exit(&__objc_thread_exit_status); /* Terminate thread. */
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)
return value; /* Return thread data. */
return NULL;
}
/******** if (thr_getspecific(__objc_thread_data_key, &value) == 0)
* Allocate a mutex. Return the mutex pointer if successful or NULL if return value;
* the allocation fails for any reason.
*/ return NULL;
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. */
} }
/******** /* Backend mutex functions */
* 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 /* Allocate a mutex. */
* 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,306 +32,241 @@ Boston, MA 02111-1307, USA. */ ...@@ -32,306 +32,241 @@ 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,
arg, 0, &thread_id)))
if ((win32_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func, thread_id = 0;
arg, 0, &thread_id))) {
__objc_runtime_threads_alive++;
}
else
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: {
sys_priority = THREAD_PRIORITY_NORMAL; case OBJC_THREAD_INTERACTIVE_PRIORITY:
break; sys_priority = THREAD_PRIORITY_NORMAL;
default: break;
case OBJC_THREAD_BACKGROUND_PRIORITY: default:
sys_priority = THREAD_PRIORITY_BELOW_NORMAL; case OBJC_THREAD_BACKGROUND_PRIORITY:
break; sys_priority = THREAD_PRIORITY_BELOW_NORMAL;
case OBJC_THREAD_LOW_PRIORITY: break;
sys_priority = THREAD_PRIORITY_LOWEST; case OBJC_THREAD_LOW_PRIORITY:
break; sys_priority = THREAD_PRIORITY_LOWEST;
} break;
}
/* Change priority */
if (SetThreadPriority(GetCurrentThread(), sys_priority)) if (SetThreadPriority(GetCurrentThread(), sys_priority))
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; int sys_priority;
sys_priority = GetThreadPriority(GetCurrentThread()); sys_priority = GetThreadPriority(GetCurrentThread());
switch (sys_priority) { switch (sys_priority)
case THREAD_PRIORITY_HIGHEST: {
case THREAD_PRIORITY_TIME_CRITICAL: case THREAD_PRIORITY_HIGHEST:
case THREAD_PRIORITY_ABOVE_NORMAL: case THREAD_PRIORITY_TIME_CRITICAL:
case THREAD_PRIORITY_NORMAL: case THREAD_PRIORITY_ABOVE_NORMAL:
return OBJC_THREAD_INTERACTIVE_PRIORITY; case THREAD_PRIORITY_NORMAL:
return OBJC_THREAD_INTERACTIVE_PRIORITY;
default:
case THREAD_PRIORITY_BELOW_NORMAL: default:
return OBJC_THREAD_BACKGROUND_PRIORITY; case THREAD_PRIORITY_BELOW_NORMAL:
return OBJC_THREAD_BACKGROUND_PRIORITY;
case THREAD_PRIORITY_IDLE: case THREAD_PRIORITY_IDLE:
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);
/* Failed if we reached here */
ExitThread(__objc_thread_exit_status); /* Terminate thread. */
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;
return -1; else
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. /* Allocate a mutex. */
*/ int
objc_mutex_t __objc_mutex_allocate(objc_mutex_t mutex)
objc_mutex_allocate(void) {
if ((mutex->backend = (void *)CreateMutex(NULL, 0, NULL)) == NULL)
return -1;
else
return 0;
}
/* Deallocate a mutex. */
int
__objc_mutex_deallocate(objc_mutex_t mutex)
{ {
objc_mutex_t mutex; CloseHandle((HANDLE)(mutex->backend));
int err = 0; return 0;
}
if (!(mutex = (objc_mutex_t)objc_malloc(sizeof(struct objc_mutex)))) /* Grab a lock on a mutex. */
return NULL; /* Abort if malloc failed. */ int
__objc_mutex_lock(objc_mutex_t mutex)
{
int status;
if ((mutex->handle = CreateMutex(NULL, 0, NULL)) == NULL) { status = WaitForSingleObject((HANDLE)(mutex->backend), INFINITE);
objc_free(mutex); /* Failed, free memory. */ if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
return NULL; /* Abort. */ return -1;
} else
mutex->owner = NULL; /* No owner. */ return 0;
mutex->depth = 0; /* No locks. */
return mutex; /* Return mutex handle. */
} }
/******** /* Try to grab a lock on 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_trylock(objc_mutex_t mutex)
{ {
int depth; /* # of locks on mutex. */ int status;
if (!mutex) /* Is argument bad? */ status = WaitForSingleObject((HANDLE)(mutex->backend), 0);
return -1; /* Yes, abort. */ if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
depth = objc_mutex_lock(mutex); /* Must have lock. */ return -1;
else
return 0;
}
CloseHandle(mutex->handle); /* Close Win32 handle. */ /* Unlock the mutex */
int
objc_free(mutex); /* Free memory. */ __objc_mutex_unlock(objc_mutex_t mutex)
return depth; /* Return last depth. */ {
if (ReleaseMutex((HANDLE)(mutex->backend)) == 0)
return -1;
else
return 0;
} }
/******** /* Backend condition mutex functions */
* 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 /* Allocate a condition. */
* 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_allocate(objc_condition_t condition)
{ {
objc_thread_t thread_id; /* Cache our thread id. */ /* Unimplemented. */
int status; 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. */
status = WaitForSingleObject(mutex->handle, INFINITE);
if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
return -1; /* Failed, abort. */
mutex->owner = thread_id; /* Mark thread as owner. */
return ++mutex->depth; /* Increment depth to end. */ /* Deallocate a condition. */
int
__objc_condition_deallocate(objc_condition_t condition)
{
/* Unimplemented. */
return -1;
} }
/******** /* 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. */
DWORD status; /* Return status from Win32.*/ 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. */
status = WaitForSingleObject(mutex->handle, 0);
if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
return -1; /* Failed, abort. */
mutex->owner = thread_id; /* Mark thread as owner. */
return ++mutex->depth; /* Increment depth to end. */
} }
/******** /* Wake up all threads 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_broadcast(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. */ /* Wake up one thread waiting on this condition. */
if (mutex->owner != thread_id) /* Does some else own lock? */ int
return -1; /* Yes, abort. */ __objc_condition_signal(objc_condition_t condition)
if (mutex->depth > 1) /* Released last lock? */ {
return --mutex->depth; /* No, Decrement depth, end.*/ /* Unimplemented. */
mutex->depth = 0; /* Yes, reset depth to 0. */ return -1;
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,94 +55,480 @@ objc_thread_callback objc_set_thread_callback(objc_thread_callback func) ...@@ -60,94 +55,480 @@ 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
{ {
SEL selector; SEL selector;
id object; id object;
id argument; id argument;
}; };
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? */
id (*imp)(id,SEL,id); if (istate) {
SEL selector = istate->selector; id (*imp)(id,SEL,id);
id object = istate->object; SEL selector = istate->selector;
id argument = istate->argument; id object = istate->object;
id argument = istate->argument;
objc_free(istate); /* Don't need anymore so free it */
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 */
if (_objc_became_multi_threaded != NULL) if (_objc_became_multi_threaded != NULL)
(*_objc_became_multi_threaded)(); (*_objc_became_multi_threaded)();
} }
if ((imp = (id(*)(id, SEL, id))objc_msg_lookup(object, selector))) { /* Call the method */
(*imp)(object, selector, argument); if ((imp = (id(*)(id, SEL, id))objc_msg_lookup(object, selector)))
} (*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_exit(); "objc_thread_detach called with NULL state.\n");
/* Exit the thread */
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 int
objc_mutex_unlock_x(objc_mutex_t mutex, const char *f, int l) objc_thread_get_priority(void)
{ {
printf("%16.16s#%4d < unlock", f, l); /* Call the backend */
return objc_mutex_unlock(mutex); 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 int
objc_mutex_lock_x(objc_mutex_t mutex, const char *f, int l) objc_thread_exit(void)
{ {
printf("%16.16s#%4d < lock", f, l); /* Decrement our counter of the number of threads alive */
return objc_mutex_lock(mutex); 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
objc_mutex_trylock(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 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
objc_mutex_unlock(objc_mutex_t mutex)
{
objc_thread_t thread_id;
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