From 8d95e9ad118bec98c40e2fa25a19abd766f4e1f3 Mon Sep 17 00:00:00 2001 From: Richard Kenner Date: Tue, 5 Mar 1996 09:22:13 -0500 Subject: [PATCH] Initial revision From-SVN: r11453 --- gcc/objc/objc-list.h | 150 +++++++++++++++++++ gcc/objc/thr-decosf1.c | 323 ++++++++++++++++++++++++++++++++++++++++ gcc/objc/thr-irix.c | 312 ++++++++++++++++++++++++++++++++++++++ gcc/objc/thr-single.c | 237 +++++++++++++++++++++++++++++ gcc/objc/thr-solaris.c | 326 ++++++++++++++++++++++++++++++++++++++++ gcc/objc/thr-win32.c | 331 +++++++++++++++++++++++++++++++++++++++++ gcc/objc/thr.c | 132 ++++++++++++++++ gcc/objc/thr.h | 77 ++++++++++ 8 files changed, 1888 insertions(+) create mode 100644 gcc/objc/objc-list.h create mode 100644 gcc/objc/thr-decosf1.c create mode 100644 gcc/objc/thr-irix.c create mode 100644 gcc/objc/thr-single.c create mode 100644 gcc/objc/thr-solaris.c create mode 100644 gcc/objc/thr-win32.c create mode 100644 gcc/objc/thr.c create mode 100644 gcc/objc/thr.h diff --git a/gcc/objc/objc-list.h b/gcc/objc/objc-list.h new file mode 100644 index 00000000000..fb06fc6d40d --- /dev/null +++ b/gcc/objc/objc-list.h @@ -0,0 +1,150 @@ +/* Generic single linked list to keep various information + Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc. + +Author: Kresten Krab Thorup + +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. */ + +#ifndef __GNU_OBJC_LIST_H +#define __GNU_OBJC_LIST_H +void * __objc_xrealloc (void *optr, size_t size); +void * __objc_xmalloc (size_t size); + +struct objc_list { + void *head; + struct objc_list *tail; +}; + +/* Return a cons cell produced from (head . tail) */ + +static inline struct objc_list* +list_cons(void* head, struct objc_list* tail) +{ + struct objc_list* cell; + + cell = (struct objc_list*)__objc_xmalloc(sizeof(struct objc_list)); + cell->head = head; + cell->tail = tail; + return cell; +} + +/* Return the length of a list, list_length(NULL) returns zero */ + +static inline int +list_length(struct objc_list* list) +{ + int i = 0; + while(list) + { + i += 1; + list = list->tail; + } + return i; +} + +/* Return the Nth element of LIST, where N count from zero. If N + larger than the list length, NULL is returned */ + +static inline void* +list_nth(int index, struct objc_list* list) +{ + while(index-- != 0) + { + if(list->tail) + list = list->tail; + else + return 0; + } + return list->head; +} + +/* Remove the element at the head by replacing it by its successor */ + +static inline void +list_remove_head(struct objc_list** list) +{ + if ((*list)->tail) + { + struct objc_list* tail = (*list)->tail; /* fetch next */ + *(*list) = *tail; /* copy next to list head */ + free(tail); /* free next */ + } + else /* only one element in list */ + { + free (*list); + (*list) = 0; + } +} + + +/* Remove the element with `car' set to ELEMENT */ + +static inline void +list_remove_elem(struct objc_list** list, void* elem) +{ + while (*list) { + if ((*list)->head == elem) + list_remove_head(list); + list = &((*list)->tail); + } +} + +/* Map FUNCTION over all elements in LIST */ + +static inline void +list_mapcar(struct objc_list* list, void(*function)(void*)) +{ + while(list) + { + (*function)(list->head); + list = list->tail; + } +} + +/* Return element that has ELEM as car */ + +static inline struct objc_list** +list_find(struct objc_list** list, void* elem) +{ + while(*list) + { + if ((*list)->head == elem) + return list; + list = &((*list)->tail); + } + return NULL; +} + +/* Free list (backwards recursive) */ + +static void +list_free(struct objc_list* list) +{ + if(list) + { + list_free(list->tail); + free(list); + } +} +#endif __GNU_OBJC_LIST_H diff --git a/gcc/objc/thr-decosf1.c b/gcc/objc/thr-decosf1.c new file mode 100644 index 00000000000..00e183d86b5 --- /dev/null +++ b/gcc/objc/thr-decosf1.c @@ -0,0 +1,323 @@ +/* GNU Objective C Runtime Thread Interface + Copyright (C) 1996 Free Software Foundation, Inc. + Contributed by Galen C. Hunt (gchunt@cs.rochester.edu) + +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) +{ + printf("__objc_init_thread_system\n"); + + if (pthread_keycreate(&__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, pthread_attr_default, + (void *)func, arg) == 0) { + thread_id = *(_objc_thread_t *)&new_thread_handle; /* ??? May not work! (64bit)*/ + 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) +{ + 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. */ + + return -1; /* Failed. */ +} + +/******** + * Return the current thread's priority. + */ +int +objc_thread_get_priority(void) +{ + 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; + } + 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". + */ +int +objc_thread_id(void) +{ + pthread_t self = pthread_self(); + + return *(int *)&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) +{ + void * value = NULL; + + if (pthread_getspecific(__objc_thread_data_key, (void *)&value) == 0) + return value; /* Return thread data. */ + + return NULL; +} + +/******** + * 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, pthread_mutexattr_default); + + if (err != 0) { /* System init failed? */ + free(mutex); /* Yes, free local memory. */ + return NULL; /* Abort. */ + } + mutex->owner = -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 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) +{ + int 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) +{ + int 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) +{ + int 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 = -1; /* Set owner to "no thread".*/ + + if (pthread_mutex_unlock(&mutex->lock) != 0) /* Unlock system mutex. */ + return -1; /* Failed, abort. */ + + return 0; /* No, return success. */ +} + +/* End of File */ diff --git a/gcc/objc/thr-irix.c b/gcc/objc/thr-irix.c new file mode 100644 index 00000000000..7e1236a5530 --- /dev/null +++ b/gcc/objc/thr-irix.c @@ -0,0 +1,312 @@ +/* GNU Objective C Runtime Thread Interface - SGI IRIX Implementation + Copyright (C) 1996 Free Software Foundation, Inc. + Contributed by Galen C. Hunt (gchunt@cs.rochester.edu) + +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 +#include +#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. */ + 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 +__objc_init_thread_system(void) +{ + char arena_name[64]; /* Name of IRIX arena. */ + + DEBUG_PRINTF("__objc_init_thread_system\n"); + sprintf(arena_name, "/usr/tmp/objc_%05u", (unsigned)getpid()); + usconfig(CONF_INITUSERS, 256); /* Up to 256 threads. */ + usconfig(CONF_ARENATYPE, US_SHAREDONLY); /* Arena only for threads. */ + if (!(__objc_shared_arena_handle = usinit(arena_name))) /* Init Failed? */ + return -1; /* Yes, return error code. */ + + return 0; +} + +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; + int sys_id; + + objc_mutex_lock(__objc_runtime_mutex); + if ((sys_id = sproc((void *)func, PR_SALL, arg)) >= 0) { + thread_id = (_objc_thread_t)sys_id; + __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) +{ + int sys_priority = 0; + + 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. + */ +int +objc_thread_get_priority(void) +{ + 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) +{ + sginap(0); /* Yield to equal process. */ +} + +/******** + * 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); + + exit(__objc_thread_exit_status); /* IRIX only has exit. */ + 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) +{ + return (_objc_thread_t)get_pid(); /* Threads are processes. */ +} + +/******** + * Sets the thread's local storage pointer. Returns 0 if successful or -1 + * if failed. + */ +int +objc_thread_set_data(void *value) +{ + *((void **)&PRDA->usr_prda) = value; /* Set thread data ptr. */ + return 0; +} + +/******** + * Returns the thread's local storage pointer. Returns NULL on failure. + */ +void * +objc_thread_get_data(void) +{ + return *((void **)&PRDA->usr_prda); /* Return thread data ptr. */ +} + +/******** + * 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. */ + + if (!(mutex->lock = usnewlock(__objc_shared_arena_handle))) + err = -1; + + 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. */ + + usfreelock(mutex->lock, __objc_shared_arena_handle); /* Free IRIX lock. */ + + 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? */ + DEBUG_PRINTF("lock owned by: %d:%d\n", mutex->owner, mutex->depth); + return ++mutex->depth; /* Yes, increment depth. */ + } + + DEBUG_PRINTF("lock owned by: %d:%d (attempt by %d)\n", + mutex->owner, mutex->depth, thread_id); + + if (ussetlock(mutex->lock) == 0) /* Did lock acquire fail? */ + return -1; /* Yes, abort. */ + + mutex->owner = thread_id; /* Mark thread as owner. */ + return mutex->depth = 1; /* Increment depth to end. */ +} + +/******** + * Try to grab a lock on a mutex. 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 (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. */ +} + +/******** + * 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. */ + + 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 */ diff --git a/gcc/objc/thr-single.c b/gcc/objc/thr-single.c new file mode 100644 index 00000000000..3821a2a15e6 --- /dev/null +++ b/gcc/objc/thr-single.c @@ -0,0 +1,237 @@ +/* GNU Objective C Runtime Thread Implementation + Copyright (C) 1996 Free Software Foundation, Inc. + Contributed by Galen C. Hunt (gchunt@cs.rochester.edu) + +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. */ + +/******** + * 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. */ +}; + +/******** + * 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 -1; /* Failed. */ +} + +/******** + * 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) +{ + return NULL; /* We can't start threads. */ +} + +/******** + * Set the current thread's priority. + */ +int +objc_thread_set_priority(int priority) +{ + return -1; /* Failed. */ +} + +/******** + * Return the current thread's priority. + */ +int +objc_thread_get_priority(void) +{ + return OBJC_THREAD_INTERACTIVE_PRIORITY; /* Highest 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) +{ + return; +} + +/******** + * Terminate the current tread. Doesn't return anything. Doesn't return. + * Actually, if it failed returns -1. + */ +int +objc_thread_exit(void) +{ + exit(__objc_thread_exit_status); + 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) +{ + return (_objc_thread_t)1; /* No thread support, use 1.*/ +} + +/******** + * Sets the thread's local storage pointer. Returns 0 if successful or -1 + * if failed. + */ + +static void *thread_local_storage = NULL; + +int +objc_thread_set_data(void *value) +{ + thread_local_storage = value; + return 0; +} + +/******** + * Returns the thread's local storage pointer. Returns NULL on failure. + */ +void * +objc_thread_get_data(void) +{ + return thread_local_storage; +} + +/******** + * Allocate a mutex. Return the mutex pointer if successful or NULL if the + * allocation failed for any reason. + */ +_objc_mutex_t +objc_mutex_allocate(void) +{ + _objc_mutex_t mutex; + + if (!(mutex = (_objc_mutex_t)__objc_xmalloc(sizeof(struct _objc_mutex)))) + return NULL; /* Abort if malloc failed. */ + + mutex->owner = NULL; /* No owner. */ + mutex->depth = 0; /* No locks. */ + return mutex; /* Return mutex handle. */ +} + +/******** + * Deallocate a mutex. Note that this includes an implicit mutex_lock to + * insure that no one else is using the lock. It is legal to deallocate + * a lock if we have a lock on it, but illegal to deallocate a lock held + * by anyone else. + * Returns the number of locks on the thread. (1 for deallocate). + */ +int +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. */ + + 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->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. */ + + 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) +{ + int 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 */ diff --git a/gcc/objc/thr-solaris.c b/gcc/objc/thr-solaris.c new file mode 100644 index 00000000000..d27fcb428e9 --- /dev/null +++ b/gcc/objc/thr-solaris.c @@ -0,0 +1,326 @@ +/* GNU Objective C Runtime Thread Interface + Copyright (C) 1996 Free Software Foundation, Inc. + Cobnrtibuted by Galen C. Hunt (gchunt@cs.rochester.edu) + +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 "runtime.h" + +#include +#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. */ + mutex_t lock; /* System mutex. */ +}; + +/***************************************************************************** + * 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 +__objc_init_thread_system(void) +{ + DEBUG_PRINTF("__objc_init_thread_system\n"); + + if (thr_keycreate(&__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 -1 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. */ + thread_t new_thread_id = 0; /* Solaris thread id type. */ + int errn; + + objc_mutex_lock(__objc_runtime_mutex); + + if (thr_create(NULL, 0, (void *)func, arg, + THR_DETACHED | THR_NEW_LWP, + &new_thread_id) == 0) { /* Created new thread? */ + thread_id = (_objc_thread_t)new_thread_id; /* Yes, remember its id. */ + __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) +{ + int sys_priority = 0; + + switch (priority) { + case OBJC_THREAD_INTERACTIVE_PRIORITY: + sys_priority = 300; + break; + default: + case OBJC_THREAD_BACKGROUND_PRIORITY: + sys_priority = 200; + break; + case OBJC_THREAD_LOW_PRIORITY: + sys_priority = 1000; + break; + } + + if (thr_setprio(thr_self(), sys_priority) == 0) + return 0; /* Changed priority. End. */ + + return -1; /* Failed. */ +} + +/******** + * Return the current thread's priority. + */ +int +objc_thread_get_priority(void) +{ + int sys_priority; /* Solaris thread priority. */ + + if (thr_getprio(thr_self(), &sys_priority) == 0) { + if (sys_priority >= 250) + return OBJC_THREAD_INTERACTIVE_PRIORITY; + else if (sys_priority >= 150) + return OBJC_THREAD_BACKGROUND_PRIORITY; + return OBJC_THREAD_LOW_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) +{ + thr_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); + + thr_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) +{ + return (_objc_thread_t)thr_self(); +} + +/******** + * Sets the thread's local storage pointer. Returns 0 if successful or -1 + * if failed. + */ +int +objc_thread_set_data(void *value) +{ + if (thr_setspecific(__objc_thread_data_key, value) == 0) + return 0; + return -1; +} + +/******** + * Returns the thread's local storage pointer. Returns NULL on failure. + */ +void * +objc_thread_get_data(void) +{ + void * value = NULL; + + if (thr_getspecific(__objc_thread_data_key, &value) == 0) + return value; /* Return thread data. */ + + return NULL; +} + +/******** + * Allocate a mutex. Return the mutex pointer if successful or NULL if + * the allocation fails for any reason. + */ +_objc_mutex_t +objc_mutex_allocate(void) +{ + struct _objc_mutex *mutex; + int err = 0; + + if (!(mutex = (_objc_mutex_t)__objc_xmalloc(sizeof(struct _objc_mutex)))) + return NULL; /* Abort if malloc failed. */ + + err = mutex_init(&mutex->lock, USYNC_THREAD, 0); + + 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. */ + + mutex_destroy(&mutex->lock); /* System deallocate. */ + + 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 (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. */ +} + +/******** + * 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_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. */ +} + +/******** + * 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 (mutex_unlock(&mutex->lock) != 0) /* Did lock release fail? */ + return -1; /* Yes, return error value. */ + + return 0; /* No, return success. */ +} + +/* End of File */ diff --git a/gcc/objc/thr-win32.c b/gcc/objc/thr-win32.c new file mode 100644 index 00000000000..d933999ccb7 --- /dev/null +++ b/gcc/objc/thr-win32.c @@ -0,0 +1,331 @@ +/* GNU Objective C Runtime Thread Interface - Win32 Implementation + Copyright (C) 1996 Free Software Foundation, Inc. + Contributed by Galen C. Hunt (gchunt@cs.rochester.edu) + +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. */ + 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 +__objc_init_thread_system(void) +{ + DEBUG_PRINTF("__objc_init_thread_system\n"); + + if ((__objc_data_tls = TlsAlloc()) != (DWORD)-1) + return 0; /* Yes, return success. */ + + return -1; /* Failed. */ +} + +int +__objc_fini_thread_system(void) +{ + if (__objc_data_tls != (DWORD)-1) { + TlsFree(__objc_data_tls); + return 0; + } + return -1; +} + +/******** + * 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) +{ + DWORD thread_id = 0; /* Detached thread id. */ + HANDLE win32_handle; /* Win32 thread handle. */ + + objc_mutex_lock(__objc_runtime_mutex); + + if ((win32_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func, + arg, 0, &thread_id))) { + __objc_runtime_threads_alive++; + } + else + thread_id = 0; + + 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) +{ + int sys_priority = 0; + + switch (priority) { + case OBJC_THREAD_INTERACTIVE_PRIORITY: + sys_priority = THREAD_PRIORITY_NORMAL; + break; + default: + case OBJC_THREAD_BACKGROUND_PRIORITY: + sys_priority = THREAD_PRIORITY_BELOW_NORMAL; + break; + case OBJC_THREAD_LOW_PRIORITY: + sys_priority = THREAD_PRIORITY_LOWEST; + break; + } + if (SetThreadPriority(GetCurrentThread(), sys_priority)) + return 0; /* Changed priority. End. */ + + return -1; /* Failed. */ +} + +/******** + * Return the current thread's priority. + */ +int +objc_thread_get_priority(void) +{ + int sys_priority; + + sys_priority = GetThreadPriority(GetCurrentThread()); + + switch (sys_priority) { + case THREAD_PRIORITY_HIGHEST: + case THREAD_PRIORITY_TIME_CRITICAL: + case THREAD_PRIORITY_ABOVE_NORMAL: + case THREAD_PRIORITY_NORMAL: + return OBJC_THREAD_INTERACTIVE_PRIORITY; + + default: + case THREAD_PRIORITY_BELOW_NORMAL: + return OBJC_THREAD_BACKGROUND_PRIORITY; + + case THREAD_PRIORITY_IDLE: + case THREAD_PRIORITY_LOWEST: + return OBJC_THREAD_LOW_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) +{ + Sleep(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); + + ExitThread(__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) +{ + return (_objc_thread_t)GetCurrentThreadId(); /* 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) +{ + if (TlsSetValue(__objc_data_tls, value)) + 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 TlsGetValue(__objc_data_tls); /* Return thread data. */ +} + +/******** + * 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 ((mutex->handle = CreateMutex(NULL, 0, NULL)) == NULL) { + free(mutex); /* Failed, free 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. */ + + CloseHandle(mutex->handle); /* Close Win32 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. */ + 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. */ + + 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. */ +} + +/******** + * 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. */ + DWORD status; /* Return status from Win32.*/ + + 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. */ +} + +/******** + * 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 (ReleaseMutex(mutex->handle) == 0) + return -1; /* Failed, abort. */ + + return 0; /* No, return success. */ +} + +/* End of File */ diff --git a/gcc/objc/thr.c b/gcc/objc/thr.c new file mode 100644 index 00000000000..1b51140ada9 --- /dev/null +++ b/gcc/objc/thr.c @@ -0,0 +1,132 @@ +/* GNU Objective C Runtime Thread Interface + Copyright (C) 1996 Free Software Foundation, Inc. + Contributed by Galen C. Hunt (gchunt@cs.rochester.edu) + +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 "runtime.h" + +/***************************************************************************** + * Universal static variables: + */ +int __objc_thread_exit_status = 0; /* Global exit status. */ + +/***************************************************************************** + * Universal Functionality + */ + +/******** + * First function called in a thread, starts everything else. + */ +struct __objc_thread_start_state +{ + SEL selector; + id object; + id argument; +}; + +static volatile void +__objc_thread_detach_function(struct __objc_thread_start_state *istate) +{ + if (istate) { /* Is state valid? */ + id (*imp)(id,SEL,id); + SEL selector = istate->selector; + id object = istate->object; + id argument = istate->argument; + + free(istate); + + if ((imp = (id(*)(id, SEL, id))objc_msg_lookup(object, selector))) { + (*imp)(object, selector, argument); + } + else + fprintf(stderr, "__objc_thread_start called with bad selector.\n"); + } + else { + fprintf(stderr, "__objc_thread_start called with NULL state.\n"); + } + objc_thread_exit(); +} + +/******** + * 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_detach(SEL selector, id object, id argument) +{ + struct __objc_thread_start_state *istate; /* Initialial thread state. */ + _objc_thread_t thread_id = NULL; /* Detached thread id. */ + + if (!(istate = (struct __objc_thread_start_state *) + __objc_xmalloc(sizeof(*istate)))) /* Can we allocate state? */ + return NULL; /* No, abort. */ + + istate->selector = selector; /* Initialize the thread's */ + istate->object = object; /* state structure. */ + istate->argument = argument; + + if ((thread_id = objc_thread_create((void *)__objc_thread_detach_function, + istate)) == NULL) { + free(istate); /* Release state if failed. */ + return thread_id; + } + return thread_id; +} + +#undef objc_mutex_lock() +#undef objc_mutex_unlock() + +int +objc_mutex_unlock_x(_objc_mutex_t mutex, const char *f, int l) +{ + printf("%16.16s#%4d < unlock", f, l); + return objc_mutex_unlock(mutex); +} + +int +objc_mutex_lock_x(_objc_mutex_t mutex, const char *f, int l) +{ + printf("%16.16s#%4d < lock", f, l); + return objc_mutex_lock(mutex); +} + +/***************************************************************************** + * Implementation specific functionality: + */ + +#if defined(__sparc__) && defined(__svr4__) /* Solaris only code. */ +#include "thread-solaris.c" +#elif defined(__sgi__) && defined(__mips__) /* IRIX only code. */ +#include "thread-irix.c" +#elif defined(__alpha__) && defined(__osf__) /* Alpha OSF/1 only code. */ +#include "thread-decosf1.c" +#elif defined(__WIN32__) +#include "thread-win32.c" +#else /* Single threaded code. */ +#include "thread-single.c" +#endif + +/* End of File */ diff --git a/gcc/objc/thr.h b/gcc/objc/thr.h new file mode 100644 index 00000000000..3bd1a0b4733 --- /dev/null +++ b/gcc/objc/thr.h @@ -0,0 +1,77 @@ +/* Thread and mutex controls for Objective C. + Copyright (C) 1996 Free Software Foundation, Inc. + Contributed by Galen C. Hunt (gchunt@cs.rochester.edu) + +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. + +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. */ + + +#ifndef __thread_INCLUDE_GNU +#define __thread_INCLUDE_GNU + +#include "objc/objc.h" + +/******** + * Thread safe implementation types and functions. + */ + +#define OBJC_THREAD_INTERACTIVE_PRIORITY 2 +#define OBJC_THREAD_BACKGROUND_PRIORITY 1 +#define OBJC_THREAD_LOW_PRIORITY 0 + +typedef struct _objc_mutex *_objc_mutex_t; +typedef void * _objc_thread_t; + +_objc_mutex_t objc_mutex_allocate(void); +int objc_mutex_deallocate(_objc_mutex_t mutex); +int objc_mutex_lock(_objc_mutex_t mutex); +int objc_mutex_unlock(_objc_mutex_t mutex); +int objc_mutex_trylock(_objc_mutex_t mutex); + +_objc_thread_t objc_thread_create(void (*func)(void *arg), void *arg); +void objc_thread_yield(void); +int objc_thread_exit(void); +int objc_thread_set_priority(int priority); +int objc_thread_get_priority(void); +void * objc_thread_get_data(void); +int objc_thread_set_data(void *value); +_objc_thread_t objc_thread_id(void); + +_objc_thread_t objc_thread_detach(SEL selector, id object, id argument); +int objc_mutex_lock_x(_objc_mutex_t mutex, const char *f, int l); +int objc_mutex_unlock_x(_objc_mutex_t mutex, const char *f, int l); + +/* For debugging of locks, uncomment these two macros: */ +/* #define objc_mutex_lock(x) objc_mutex_lock_x(x, __FILE__, __LINE__) */ +/* #define objc_mutex_unlock(x) objc_mutex_unlock_x(x, __FILE__, __LINE__)*/ + +#endif /* not __thread_INCLUDE_GNU */ -- 2.30.2