OSDN Git Service

Initial revision
authorkenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 5 Mar 1996 14:22:13 +0000 (14:22 +0000)
committerkenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 5 Mar 1996 14:22:13 +0000 (14:22 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@11453 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/objc/objc-list.h [new file with mode: 0644]
gcc/objc/thr-decosf1.c [new file with mode: 0644]
gcc/objc/thr-irix.c [new file with mode: 0644]
gcc/objc/thr-single.c [new file with mode: 0644]
gcc/objc/thr-solaris.c [new file with mode: 0644]
gcc/objc/thr-win32.c [new file with mode: 0644]
gcc/objc/thr.c [new file with mode: 0644]
gcc/objc/thr.h [new file with mode: 0644]

diff --git a/gcc/objc/objc-list.h b/gcc/objc/objc-list.h
new file mode 100644 (file)
index 0000000..fb06fc6
--- /dev/null
@@ -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 (file)
index 0000000..00e183d
--- /dev/null
@@ -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 (file)
index 0000000..7e1236a
--- /dev/null
@@ -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 (file)
index 0000000..3821a2a
--- /dev/null
@@ -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 (file)
index 0000000..d27fcb4
--- /dev/null
@@ -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 (file)
index 0000000..d933999
--- /dev/null
@@ -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 (file)
index 0000000..1b51140
--- /dev/null
@@ -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 (file)
index 0000000..3bd1a0b
--- /dev/null
@@ -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 */