aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Kenner <kenner@gcc.gnu.org>1996-03-05 09:22:13 -0500
committerRichard Kenner <kenner@gcc.gnu.org>1996-03-05 09:22:13 -0500
commit8d95e9ad118bec98c40e2fa25a19abd766f4e1f3 (patch)
tree1b705e29bd7d1b6bd5c8702afe380ad95d399446
parentca10c449d67033a975dbb8a69ef0abfe77b3b61c (diff)
downloadgcc-8d95e9ad118bec98c40e2fa25a19abd766f4e1f3.zip
gcc-8d95e9ad118bec98c40e2fa25a19abd766f4e1f3.tar.gz
gcc-8d95e9ad118bec98c40e2fa25a19abd766f4e1f3.tar.bz2
Initial revision
From-SVN: r11453
-rw-r--r--gcc/objc/objc-list.h150
-rw-r--r--gcc/objc/thr-decosf1.c323
-rw-r--r--gcc/objc/thr-irix.c312
-rw-r--r--gcc/objc/thr-single.c237
-rw-r--r--gcc/objc/thr-solaris.c326
-rw-r--r--gcc/objc/thr-win32.c331
-rw-r--r--gcc/objc/thr.c132
-rw-r--r--gcc/objc/thr.h77
8 files changed, 1888 insertions, 0 deletions
diff --git a/gcc/objc/objc-list.h b/gcc/objc/objc-list.h
new file mode 100644
index 0000000..fb06fc6
--- /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 0000000..00e183d8
--- /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 <pthread.h>
+
+/********
+ * 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 0000000..7e1236a
--- /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 <stdlib.h>
+#include <sys/types.h>
+#include <sys/sysmp.h>
+#include <sys/prctl.h>
+#include <ulocks.h>
+
+/********
+ * 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 0000000..3821a2a
--- /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 0000000..d27fcb4
--- /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 <thread.h>
+#include <synch.h>
+#include <errno.h>
+
+/********
+ * 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 0000000..d933999
--- /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 <windows.h>
+
+/********
+ * 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 0000000..1b51140
--- /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 <stdlib.h>
+#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 0000000..3bd1a0b
--- /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 */