From fc94a55b9221b13ebe9ac1c01a096d18c5d92594 Mon Sep 17 00:00:00 2001 From: Richard Kenner Date: Fri, 17 May 1996 08:28:54 -0400 Subject: [PATCH] Initial revision From-SVN: r11985 --- gcc/objc/thr-mach.c | 359 +++++++++++++++++++++++++++++++++++++++++++ gcc/objc/thr-os2.c | 341 ++++++++++++++++++++++++++++++++++++++++ gcc/objc/thr-posix.c | 321 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 1021 insertions(+) create mode 100644 gcc/objc/thr-mach.c create mode 100644 gcc/objc/thr-os2.c create mode 100644 gcc/objc/thr-posix.c diff --git a/gcc/objc/thr-mach.c b/gcc/objc/thr-mach.c new file mode 100644 index 00000000000..22743d2cb56 --- /dev/null +++ b/gcc/objc/thr-mach.c @@ -0,0 +1,359 @@ +/* GNU Objective C Runtime Thread Implementation + Copyright (C) 1996 Free Software Foundation, Inc. + +Author: Galen C. Hunt (gchunt@cs.rochester.edu) +Modified for Mach threads by: Bill Bumgarner + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include +#include + +/******** + * 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. */ + struct mutex lock; /* cthread mutex */ +}; + + +/******** + * 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) + return -1; + + threadP = cthread_thread(t); /* get thread underlying */ + + error=thread_info(threadP, THREAD_SCHED_INFO, + (thread_info_t)&info, &info_count); + + if (error != KERN_SUCCESS) + return -1; + + if (base != NULL) + *base = info.base_priority; + + return info.max_priority; +} + +/******** + * Initialize the threads subsystem. Returns 0 if successful, or -1 if no + * thread support is available. + */ +int +__objc_init_thread_system(void) +{ + DEBUG_PRINTF("__objc_init_thread_system\n"); + return 0; /* Succeeded. */ +} + + +int +__objc_fini_thread_system(void) +{ + return 0; +} + +/******** + * Create a new thread of execution and return its id. Return NULL if fails. + * The new thread starts in "func" with the given argument. + */ +_objc_thread_t +objc_thread_create(void (*func)(void *arg), void *arg) +{ + _objc_thread_t thread_id = NULL; /* Detached thread id. */ + cthread_t new_thread_handle; /* cthread handle. */ + + objc_mutex_lock(__objc_runtime_mutex); + + /* create thread */ + new_thread_handle = cthread_fork((cthread_fn_t)func, arg); + + if(new_thread_handle) { + thread_id = *(_objc_thread_t *)&new_thread_handle; /* this is not terribly portable */ + cthread_detach(new_thread_handle); /* fully detach thread */ + __objc_runtime_threads_alive++; /* increment thread count */ + } + + objc_mutex_unlock(__objc_runtime_mutex); + return thread_id; +} + +/******** + * Set the current thread's priority. + */ +int +objc_thread_set_priority(int priority) +{ + _objc_thread_t *t = objc_thread_id(); + cthread_t cT = (cthread_t) t; /* see objc_thread_id() */ + int maxPriority = __mach_get_max_thread_priority(cT, NULL); + int sys_priority = 0; + + if (maxPriority == -1) + return -1; + + switch (priority) { + case OBJC_THREAD_INTERACTIVE_PRIORITY: + sys_priority = maxPriority; + break; + case OBJC_THREAD_BACKGROUND_PRIORITY: + sys_priority = (maxPriority * 2) / 3; + break; + case OBJC_THREAD_LOW_PRIORITY: + sys_priority = maxPriority / 3; + break; + default: + return -1; + } + + if (sys_priority == 0) + return -1; + + if (cthread_priority(cT, sys_priority, 0) == KERN_SUCCESS) + return 0; /* Changed priority. End. */ + + return -1; /* Failed. */ +} + +/******** + * Return the current thread's priority [well, whatever it is closest to]. + */ +int +objc_thread_get_priority(void) +{ + _objc_thread_t *t = objc_thread_id(); + cthread_t cT = (cthread_t) t; /* see objc_thread_id() */ + int basePriority; + int maxPriority; + int sys_priority = 0; + + int interactiveT, backgroundT, lowT; /* threasholds */ + + maxPriority = __mach_get_max_thread_priority(cT, &basePriority); + + if(maxPriority == -1) + return -1; + + if (basePriority > ( (maxPriority * 2) / 3)) + return OBJC_THREAD_INTERACTIVE_PRIORITY; /* interactive priority + */ + if (basePriority > ( maxPriority / 3)) + return OBJC_THREAD_BACKGROUND_PRIORITY; /* background priority + */ + return OBJC_THREAD_LOW_PRIORITY; /* everything else is low */ +} + +/******** + * 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) +{ + cthread_yield(); /* Yield to equal thread. */ +} + +/******** + * Terminate the current tread. Doesn't return anything. Doesn't return. + * Actually, if it failed returns -1. + */ +int +objc_thread_exit(void) +{ + objc_mutex_lock(__objc_runtime_mutex); + __objc_runtime_threads_alive--; + objc_mutex_unlock(__objc_runtime_mutex); + + cthread_exit(&__objc_thread_exit_status); /* Terminate thread. */ + return -1; +} + +/******** + * 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) +{ + cthread_t self = cthread_self(); + return (_objc_thread_t)self; +} + +/******** + * Sets the thread's local storage pointer. Returns 0 if successful or -1 + * if failed. + */ + +int +objc_thread_set_data(void *value) +{ + cthread_set_data(cthread_self(), (any_t) value); + return 0; +} + +/******** + * Returns the thread's local storage pointer. Returns NULL on failure. + */ +void * +objc_thread_get_data(void) +{ + return (void *) cthread_data(cthread_self()); +} + +/******** + * 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; + int err = 0; + + if (!(mutex = (_objc_mutex_t)__objc_xmalloc(sizeof(struct _objc_mutex)))) + return NULL; /* Abort if malloc failed. */ + + err = mutex_init(&(mutex->lock)); + + if (err != 0) { /* System init failed? */ + 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. 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; /* # of locks on mutex. */ + + if (!mutex) /* Is argument bad? */ + return -1; /* Yes, abort. */ + depth = objc_mutex_lock(mutex); /* Must have lock. */ + + mutex_unlock(&(mutex->lock)); /* Must unlock system mutex.*/ + mutex_clear(&(mutex->lock)); /* Free system mutex. */ + + 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 + * 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; /* 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) /* 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. 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; /* 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) /* 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. */ +} + +/******** + * 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 = (_objc_thread_t) -1; /* Set owner to "no thread".*/ + + mutex_unlock(&(mutex->lock)); /* unlock cthread mutex. */ + + return 0; /* No, return success. */ +} diff --git a/gcc/objc/thr-os2.c b/gcc/objc/thr-os2.c new file mode 100644 index 00000000000..0db006b8bc7 --- /dev/null +++ b/gcc/objc/thr-os2.c @@ -0,0 +1,341 @@ +/* GNU Objective C Runtime Thread Interface - OS/2 emx Implementation + Copyright (C) 1996 Free Software Foundation, Inc. + +Author: Thomas Baier (baier@ci.tuwien.ac.at) + +This file is included into thread.c + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#define INCL_DOSSEMAPHORES +#define INCL_DOSPROCESS + +/* + * conflicts with objc.h: SEL, BOOL, id + * solution: prefixing those with _OS2_ before including + */ +#define SEL _OS2_SEL +#define BOOL _OS2_BOOL +#define id _OS2_id +#include +#undef id +#undef SEL +#undef BOOL + +#include + +/******** + * 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. */ +}; + +/***************************************************************************** + * Static variables. + */ +/* none needed for OS/2 */ + +/******** + * Initialize the threads subsystem. Returns 0 if successful, or -1 if no + * thread support is available. + */ +int +__objc_init_thread_system(void) +{ + DEBUG_PRINTF("__objc_init_thread_system (os2-emx)\n"); + + /* no initialization of thread subsystem */ + return 0; /* Yes, return success. */ +} + +int +__objc_fini_thread_system(void) +{ + /* no termination code for thread subsystem */ + return 0; +} + +/******** + * Create a new thread of execution and return its id. Return NULL if fails. + * The new thread starts in "func" with the given argument. + */ +_objc_thread_t +objc_thread_create(void (*func)(void *arg), void *arg) +{ + int thread_id = 0; /* id of the newly created thread */ + + 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) + thread_id = 0; + else + __objc_runtime_threads_alive++; + + objc_mutex_unlock(__objc_runtime_mutex); + + return (_objc_thread_t)thread_id; +} + +/******** + * Set the current thread's priority. + */ +int +objc_thread_set_priority(int priority) +{ + ULONG sys_class = 0; + ULONG sys_priority = 0; + + /* OBJC_THREAD_INTERACTIVE_PRIORITY -> PRTYC_FOREGROUNDSERVER + * OBJC_THREAD_BACKGROUND_PRIORITY -> PRTYC_REGULSR + * OBJC_THREAD_LOW_PRIORITY -> PRTYC_IDLETIME */ + + switch (priority) { + case OBJC_THREAD_INTERACTIVE_PRIORITY: + sys_class = PRTYC_REGULAR; + sys_priority = 10; + break; + default: + case OBJC_THREAD_BACKGROUND_PRIORITY: + sys_class = PRTYC_IDLETIME; + sys_priority = 25; + break; + case OBJC_THREAD_LOW_PRIORITY: + sys_class = PRTYC_IDLETIME; + sys_priority = 0; + break; + } + if (!DosSetPriority (PRTYS_THREAD,sys_class,sys_priority,*_threadid)) + return 0; /* Changed priority. End. */ + + return -1; /* Failed. */ +} + +/******** + * Return the current thread's priority. + */ +int +objc_thread_get_priority(void) +{ + PTIB ptib; + PPIB ppib; + + DosGetInfoBlocks (&ptib,&ppib); /* get information about current thread */ + + switch (ptib->tib_ptib2->tib2_ulpri) { + 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. 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) +{ + DosSleep (0); /* Yield to equal thread. */ +} + +/******** + * Terminate the current tread. Doesn't return anything. Doesn't return. + * Actually, if it failed returns -1. + */ +int +objc_thread_exit(void) +{ + objc_mutex_lock(__objc_runtime_mutex); + __objc_runtime_threads_alive--; + objc_mutex_unlock(__objc_runtime_mutex); + + _endthread (); /* terminate the thread, NEVER use DosExit () */ + + return -1; +} + +/******** + * 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_id(void) +{ + return (_objc_thread_t) *_threadid; /* Return thread id. */ +} + +/******** + * Sets the thread's local storage pointer. Returns 0 if successful or -1 + * if failed. + */ +int +objc_thread_set_data(void *value) +{ + *_threadstore () = value; + + return 0; +} + +/******** + * Returns the thread's local storage pointer. Returns NULL on failure. + */ +void * +objc_thread_get_data(void) +{ + return *_threadstore (); +} + +/******** + * 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_xmalloc(sizeof(struct _objc_mutex)))) + return NULL; /* Abort if malloc failed. */ + + if (DosCreateMutexSem (NULL,&(mutex->handle),0L,0) > 0) { + free (mutex); + return NULL; + } + + mutex->owner = NULL; /* No owner. */ + mutex->depth = 0; /* No locks. */ + return mutex; /* Return mutex handle. */ +} + +/******** + * Deallocate a mutex. Note that this includes an implicit mutex_lock to + * insure that no one else is using the lock. It is legal to deallocate + * a lock if we have a lock on it, but illegal to deallotcate 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; /* # of locks on mutex. */ + + if (!mutex) /* Is argument bad? */ + return -1; /* Yes, abort. */ + depth = objc_mutex_lock(mutex); /* Must have lock. */ + + DosCloseMutexSem (mutex->handle); + + 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 + * 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; /* 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) /* Already own lock? */ + return ++mutex->depth; /* Yes, increment depth. */ + + if (DosRequestMutexSem (mutex->handle,-1L) != 0) + return -1; + + mutex->owner = thread_id; /* Mark thread as owner. */ + + return ++mutex->depth; /* Increment depth to end. */ +} + +/******** + * 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; /* 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) /* Already own lock? */ + return ++mutex->depth; /* Yes, increment depth. */ + + if (DosRequestMutexSem (mutex->handle,0L) != 0) + return -1; + + mutex->owner = thread_id; /* Mark thread as owner. */ + return ++mutex->depth; /* 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".*/ + + if (DosReleaseMutexSem(mutex->handle) != 0) + return -1; /* Failed, abort. */ + + return 0; /* No, return success. */ +} diff --git a/gcc/objc/thr-posix.c b/gcc/objc/thr-posix.c new file mode 100644 index 00000000000..fd9be1bfc12 --- /dev/null +++ b/gcc/objc/thr-posix.c @@ -0,0 +1,321 @@ +/* GNU Objective C Runtime Thread Interface for POSIX compliant threads + Copyright (C) 1996 Free Software Foundation, Inc. + +Author: Galen C. Hunt (gchunt@cs.rochester.edu) +Modified for Linux & Pthreads: Kai-Uwe Sattler (kus@iti.cs.uni-magdeburg.de) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include + +/******** + * 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 lock; /* pthread mutex. */ +}; + +/***************************************************************************** + * Static variables. + */ +static pthread_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 +__objc_init_thread_system(void) +{ + if (pthread_key_create(&__objc_thread_data_key, NULL) == 0) + return 0; /* Yes, return success. */ + + return -1; /* Failed. */ +} + +int +__objc_fini_thread_system(void) +{ + return 0; +} + +/******** + * Create a new thread of execution and return its id. Return NULL if fails. + * The new thread starts in "func" with the given argument. + */ +_objc_thread_t +objc_thread_create(void (*func)(void *arg), void *arg) +{ + _objc_thread_t thread_id = NULL; /* Detached thread id. */ + pthread_t new_thread_handle; /* DCE thread handle. */ + + objc_mutex_lock(__objc_runtime_mutex); + + if (pthread_create(&new_thread_handle, NULL, + (void *)func, arg) == 0) { + thread_id = (_objc_thread_t) new_thread_handle; + pthread_detach(new_thread_handle); /* Fully detach thread. */ + __objc_runtime_threads_alive++; + } + + objc_mutex_unlock(__objc_runtime_mutex); + return thread_id; +} + +/******** + * Set the current thread's priority. + */ +int +objc_thread_set_priority(int priority) +{ +#if 0 /* no get/set priority in Linux pthreads */ + + 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. + */ +int +objc_thread_get_priority(void) +{ +#if 0 /* no get/set priority in Linux pthreads */ + int sys_priority; /* DCE thread priority. */ + + 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. 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) +{ + pthread_yield(); /* Yield to equal thread. */ +} + +/******** + * Terminate the current tread. Doesn't return anything. Doesn't return. + * Actually, if it failed returns -1. + */ +int +objc_thread_exit(void) +{ + objc_mutex_lock(__objc_runtime_mutex); + __objc_runtime_threads_alive--; + objc_mutex_unlock(__objc_runtime_mutex); + + pthread_exit(&__objc_thread_exit_status); /* Terminate thread. */ + return -1; +} + +/******** + * 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_id(void) +{ + pthread_t self = pthread_self(); + + return (_objc_thread_t) self; /* Return thread handle. */ +} + +/******** + * Sets the thread's local storage pointer. Returns 0 if successful or -1 + * if failed. + */ +int +objc_thread_set_data(void *value) +{ + if (pthread_setspecific(__objc_thread_data_key, (void *)value) == 0) + return 0; /* Return thread data. */ + return -1; +} + +/******** + * Returns the thread's local storage pointer. Returns NULL on failure. + */ +void * +objc_thread_get_data(void) +{ + return pthread_getspecific(__objc_thread_data_key); +} + +/******** + * 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_xmalloc(sizeof(struct _objc_mutex)))) + return NULL; /* Abort if malloc failed. */ + + err = pthread_mutex_init(&mutex->lock, NULL); + + if (err != 0) { /* System init failed? */ + free(mutex); /* Yes, free local memory. */ + return NULL; /* Abort. */ + } + mutex->owner = NULL; /* No owner. */ + mutex->depth = 0; /* No locks. */ + return mutex; /* Return mutex handle. */ +} + +/******** + * Deallocate a mutex. 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 +objc_mutex_deallocate(_objc_mutex_t mutex) +{ + int depth; /* # of locks on mutex. */ + + 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. */ + + 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 + * 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; /* 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) /* 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. */ +} + +/******** + * 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; /* 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) /* 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. */ +} + +/******** + * 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".*/ + + if (pthread_mutex_unlock(&mutex->lock) != 0) /* Unlock system mutex. */ + return -1; /* Failed, abort. */ + + return 0; /* No, return success. */ +} -- 2.30.2