libs-base/gcc-objc.patch
mccallum 68ddaf3e77 New file.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@1680 72102866-910b-0410-8b05-ffd578937521
1996-09-02 15:59:13 +00:00

4040 lines
127 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

diff -rc2P objc/Makefile objc-threaded/Makefile
*** objc/Makefile Sat Jan 20 21:09:37 1996
--- objc-threaded/Makefile Fri Jan 26 14:39:17 1996
***************
*** 57,61 ****
OBJC_O = hash.o sarray.o class.o sendmsg.o init.o archive.o encoding.o \
! selector.o objects.o misc.o NXConstStr.o Object.o Protocol.o
libobjc.a: $(OBJC_O)
--- 57,61 ----
OBJC_O = hash.o sarray.o class.o sendmsg.o init.o archive.o encoding.o \
! selector.o objects.o misc.o NXConstStr.o Object.o Protocol.o thread.o
libobjc.a: $(OBJC_O)
***************
*** 64,70 ****
# ranlib is run in the parent directory's makefile.
! OBJC_H = hash.h list.h sarray.h objc.h \
objc-api.h \
! NXConstStr.h Object.h Protocol.h encoding.h typedstream.h
# copy objc headers to installation include directory
--- 64,70 ----
# ranlib is run in the parent directory's makefile.
! OBJC_H = hash.h objc-list.h sarray.h objc.h \
objc-api.h \
! NXConstStr.h Object.h Protocol.h encoding.h typedstream.h thread.h
# copy objc headers to installation include directory
***************
*** 99,100 ****
--- 99,102 ----
Object.o: Object.m
Protocol.o: Protocol.m
+ thread.o: thread.c thread-solaris.c thread-irix.c thread-win32.c thread-single.c
+
diff -rc2P objc/README.threads objc-threaded/README.threads
*** objc/README.threads Wed Dec 31 19:00:00 1969
--- objc-threaded/README.threads Sun Jan 21 21:28:14 1996
***************
*** 0 ****
--- 1,52 ----
+ ==============================================================================
+ README - Wed Nov 29 15:16:24 EST 1995
+ ------------------------------------------------------------------------------
+
+ Limited documentation is available in the THREADS file.
+
+ A simple multiple threaded test program is available in thread-test/.
+
+ This version has been tested on Sun Solaris, SGI Irix, and Windows NT.
+ It should also work on any single threaded system.
+
+ Thanks go to the following people for help test and debug the library:
+
+ Scott Christley, scottc@ocbi.com
+ Andrew McCallum, mccallum@cs.rochester.edu
+
+ galen
+ gchunt@cs.rochester.edu
+
+ Any questions, bug reports, etc should be directed to:
+
+ Scott Christley, scottc@ocbi.com
+
+ Please do not bug Galen with email as he no longer supports the code.
+
+ ==============================================================================
+ Changes from prior releases (in revered chronological order):
+ ------------------------------------------------------------------------------
+
+ * Fixed bug in copy part of sarray_realloc. I had an < which should
+ have been <=. (Bug report from Scott).
+
+ ------------------------------------------------------------------------------
+
+ * Support for DEC OSF/1 is definitely broken. My programs always
+ seg-fault when I link with libpthreads.a.
+
+ * Thread id's are no longer int's, but are instead of type
+ _objc_thread_t which is typedef'ed from a void *. An invalid thread
+ id is denoted by NULL and not -1 as before.
+
+ ------------------------------------------------------------------------------
+
+ * Renamed thread-winnt.c to thread-win32.c to better reflect support
+ for the API on both Windows NT and Windows 95 platforms.
+ (Who knows, maybe even Win32s :-).
+
+ * Fixed bugs in Win32 support as per report from Scott Christley.
+
+ * Fixed bug in sarray_get as per report from Scott Christley.
+
+
diff -rc2P objc/THREADS objc-threaded/THREADS
*** objc/THREADS Wed Dec 31 19:00:00 1969
--- objc-threaded/THREADS Sun Jan 21 21:34:30 1996
***************
*** 0 ****
--- 1,206 ----
+ This file describes in little detail the modifications to the
+ Objective-C runtime needed to make it thread safe.
+
+ First off, kudos to Galen Hunt who is the author of this great work.
+
+ If you have an comments or just want to know where to
+ send me money to express your undying graditude for threading the
+ Objective-C runtime you can reach Galen at:
+
+ gchunt@cs.rochester.edu
+
+ Any questions, comments, bug reports, etc. should send email either to the
+ GCC bug account or to:
+
+ Scott Christley <scottc@ocbi.com>
+
+ ******************************************************************************
+ * Simple test program:
+
+ A simple test program can be found in the thread-test directory.
+
+ ******************************************************************************
+ * Sarray Threading:
+
+ The most critical component of the Objective-C runtime is the sparse array
+ structure (sarray). Sarrays store object selectors and implementations.
+ Following in the tradition of the Objective-C runtime, my threading
+ support assumes that fast message dispatching is far more important
+ than *ANY* and *ALL* other operations. The message dispatching thus
+ uses *NO* locks on any kind. In fact, if you look in sarray.h, you
+ will notice that the message dispatching has not been modified.
+ Instead, I have modified the sarray management functions so that all
+ updates to the sarray data structure can be made in parallel will
+ message dispatching.
+
+ To support concurrent message dispatching, no dynamically allocated
+ sarray data structures are freed while more than one thread is
+ operational. Sarray data structures that are no longer in use are
+ kept in a linked list of garbage and are released whenever the program
+ is operating with a single thread. The programmer can also flush the
+ garbage list by calling sarray_remove_garbage when the programmer can
+ ensure that no message dispatching is taking place concurrently. The
+ amount of un-reclaimed sarray garbage should normally be extremely
+ small in a real program as sarray structures are freed only when using
+ the "poseAs" functionality and early in program initialization, which
+ normally occurs while the program is single threaded.
+
+ ******************************************************************************
+ * Static Variables:
+
+ The following variables are either statically or globally defined. This list
+ does not include variables which are internal to implementation dependent
+ versions of thread-*.c.
+
+ The following threading designations are used:
+ SAFE : Implicitly thread safe.
+ SINGLE : Must only be used in single thread mode.
+ MUTEX : Protected by single global mutex objc_runtime_mutex.
+ UNUSED : Not used in the runtime.
+
+ Variable Name: Usage: Defined: Also used in:
+ =========================== ====== ============ =====================
+ __objc_class_hash MUTEX class.c
+ __objc_class_links_resolved UNUSED class.c runtime.h
+ __objc_class_number MUTEX class.c
+ __objc_dangling_categories UNUSED init.c
+ __objc_module_list MUTEX init.c
+ __objc_selector_array MUTEX selector.c
+ __objc_selector_hash MUTEX selector.c
+ __objc_selector_max_index MUTEX selector.c sendmsg.c runtime.h
+ __objc_selector_names MUTEX selector.c
+ __objc_thread_exit_status SAFE thread.c
+ __objc_uninstalled_dtable MUTEX sendmsg.c selector.c
+ _objc_load_callback SAFE init.c objc-api.h
+ _objc_lookup_class SAFE class.c objc-api.h
+ _objc_object_alloc SINGLE objects.c objc-api.h
+ _objc_object_copy SINGLE objects.c objc-api.h
+ _objc_object_dispose SINGLE objects.c objc-api.h
+ frwd_sel SAFE2 sendmsg.c
+ idxsize MUTEX sarray.c sendmsg.c sarray.h
+ initialize_sel SAFE2 sendmsg.c
+ narrays MUTEX sarray.c sendmsg.c sarray.h
+ nbuckets MUTEX sarray.c sendmsg.c sarray.h
+ nindices MUTEX sarray.c sarray.h
+ previous_constructors SAFE1 init.c
+ proto_class SAFE1 init.c
+ unclaimed_categories MUTEX init.c
+ unclaimed_proto_list MUTEX init.c
+ uninitialized_statics MUTEX init.c
+
+ Notes:
+ 1) Initialized once in unithread mode.
+ 2) Initialized value will always be same, guaranteed by lock on selector
+ hash table.
+
+ ******************************************************************************
+ * Linking:
+
+ On Solaris, you must link with -lthread to include the system
+ thread library. We use its low level thread and mutex implementations.
+
+ On OSF/1, you must link with -lpthreads to include the pthreads library.
+
+ On WIN32, thread support is built-in to the WIN32 API; refer to your
+ compiler documentation for the appropriate library.
+
+ ******************************************************************************
+ * Threads:
+
+ The thread system attempts to create multiple threads using whatever
+ operating system or library thread support is available. It does
+ assume that all system functions are thread safe. Notably this means
+ that the system implementation of malloc and free must be thread safe.
+ If a system has multiple processors, the threads are configured for
+ full parallel processing.
+
+ __objc_init_thread_system(void), int
+ Initialize the thread subsystem. Call once by __objc_exec_class.
+
+ __objc_fini_thread_system(void), int
+ Closes the thread subsystem.
+
+ objc_thread_detach(SEL selector, id object, id argument), int
+ Creates and detaches a new thread. The new thread starts by
+ sending the given selector with a single argument to the
+ given object.
+
+ objc_thread_set_priority(int priority), int
+ Sets a threads relative priority within the program. Valid
+ options are:
+
+ OBJC_THREAD_INTERACTIVE_PRIORITY
+ OBJC_THREAD_BACKGROUND_PRIORITY
+ OBJC_THREAD_LOW_PRIORITY
+
+ objc_thread_get_priority(void), int
+ Query a threads priority.
+
+ objc_thread_yield(void), void
+ Yields processor to another thread with equal or higher
+ priority. It is up to the system scheduler to determine if
+ the processor is taken or not.
+
+ objc_thread_exit(void), int
+ Terminates a thread. If this is the last thread executing
+ then the program will terminate.
+
+ objc_thread_id(void), int
+ Returns the current thread's id.
+
+ objc_thread_set_data(void *value), int
+ Set a pointer to the thread's local storage. Local storage is
+ thread specific.
+
+ objc_thread_get_data(void), void *
+ Returns the pointer to the thread's local storage.
+
+ ******************************************************************************
+ * Mutexs:
+
+ Mutexs can be locked recursively. Each mutex locked mutex remembers
+ its owner (by thread id) and how many times it has been locked. The
+ last unlock on a mutex removes the system lock and allows other
+ threads to access the mutex.
+
+ objc_mutex_allocate(void), Mutex_t
+ Allocates a new mutex. Mutex is initially unlocked.
+
+ objc_mutex_deallocate(Mutex_t mutex), int
+ Free a mutex. Before freeing the mutex, makes sure that no
+ one else is using it.
+
+ objc_mutex_lock(Mutex_t mutex), int
+ Locks a mutex. As mentioned earlier, the same thread may call
+ this routine repeatedly.
+
+ objc_mutex_trylock(Mutex_t mutex), int
+ Attempts to lock a mutex. Returns -1 if failed. If lock on
+ mutex can be acquired then function operates exactly as
+ objc_mutex_lock.
+
+ objc_mutex_unlock(Mutex_t mutex), int
+ Unlocks the mutex by one level. Other threads may not acquire
+ the mutex until this thread has released all locks on it.
+
+ ******************************************************************************
+ * Sample run of thread-test/checks/test01.m
+
+ << program started >> -- Program started
+ __objc_exec_class(Object.m) -- Initialize once
+ __objc_init_mutex_system
+ __objc_init_thread_system
+ __objc_init_selector_tables()
+ __objc_init_class_tables()
+ __objc_init_dispatch_tables()
+ __objc_exec_class(Protocol.m) -- Called repeatedly
+ __objc_init_protocols(0x000746d4) -- Called repeatedly
+ class_add_method_list(0x74718, 0x74208) -- Called repeatedly
+ << main called >> -- Main called
+ __objc_init_install_dtable(0x6d980, 0x6d5c0) -- Called repeatedly
+ << delegatePool filled, count=10 >> -- Code in secondary function
+ __objc_init_install_dtable(0x76268, 0x70614) -- Called repeatedly
+ Array: count=1 -- More secondary code.
+ EltNodeCollector: count=1
+ << end of program >> -- End of program
+
diff -rc2P objc/class.c objc-threaded/class.c
*** objc/class.c Sat Jan 20 21:09:37 1996
--- objc-threaded/class.c Fri Jan 26 14:41:59 1996
***************
*** 28,41 ****
/* The table of classname->class. Used for objc_lookup_class and friends */
! static cache_ptr __objc_class_hash = 0;
/* This is a hook which is called by objc_get_class and
objc_lookup_class if the runtime is not able to find the class.
This may e.g. try to load in the class using dynamic loading */
! Class (*_objc_lookup_class)(const char* name) = 0;
/* True when class links has been resolved */
! BOOL __objc_class_links_resolved = NO;
--- 28,41 ----
/* The table of classname->class. Used for objc_lookup_class and friends */
! static cache_ptr __objc_class_hash = 0; /* !T:MUTEX */
/* This is a hook which is called by objc_get_class and
objc_lookup_class if the runtime is not able to find the class.
This may e.g. try to load in the class using dynamic loading */
! Class (*_objc_lookup_class)(const char* name) = 0; /* !T:SAFE */
/* True when class links has been resolved */
! BOOL __objc_class_links_resolved = NO; /* !T:UNUSED */
***************
*** 50,57 ****
--- 50,61 ----
return;
+ objc_mutex_lock(__objc_runtime_mutex);
+
__objc_class_hash
= hash_new (CLASS_HASH_SIZE,
(hash_func_type) hash_string,
(compare_func_type) compare_strings);
+
+ objc_mutex_unlock(__objc_runtime_mutex);
}
***************
*** 63,66 ****
--- 67,72 ----
Class h_class;
+ objc_mutex_lock(__objc_runtime_mutex);
+
/* make sure the table is there */
assert(__objc_class_hash);
***************
*** 83,86 ****
--- 89,94 ----
hash_add (&__objc_class_hash, class->name, class);
}
+
+ objc_mutex_unlock(__objc_runtime_mutex);
}
***************
*** 92,95 ****
--- 100,105 ----
Class class;
+ objc_mutex_lock(__objc_runtime_mutex);
+
/* Make sure the class hash table exists. */
assert (__objc_class_hash);
***************
*** 97,100 ****
--- 107,112 ----
class = hash_value_for_key (__objc_class_hash, name);
+ objc_mutex_unlock(__objc_runtime_mutex);
+
if (class)
return class;
***************
*** 114,117 ****
--- 126,131 ----
Class class;
+ objc_mutex_lock(__objc_runtime_mutex);
+
/* Make sure the class hash table exists. */
assert (__objc_class_hash);
***************
*** 119,122 ****
--- 133,138 ----
class = hash_value_for_key (__objc_class_hash, name);
+ objc_mutex_unlock(__objc_runtime_mutex);
+
if (class)
return class;
***************
*** 150,153 ****
--- 166,171 ----
objc_next_class(void **enum_state)
{
+ objc_mutex_lock(__objc_runtime_mutex);
+
/* make sure the table is there */
assert(__objc_class_hash);
***************
*** 155,158 ****
--- 173,179 ----
*(node_ptr*)enum_state =
hash_next(__objc_class_hash, *(node_ptr*)enum_state);
+
+ objc_mutex_unlock(__objc_runtime_mutex);
+
if (*(node_ptr*)enum_state)
return (*(node_ptr*)enum_state)->value;
***************
*** 170,173 ****
--- 191,196 ----
assert(object_class);
+ objc_mutex_lock(__objc_runtime_mutex);
+
/* Assign subclass links */
for (node = hash_next (__objc_class_hash, NULL); node;
***************
*** 235,238 ****
--- 258,263 ----
}
}
+
+ objc_mutex_unlock(__objc_runtime_mutex);
}
***************
*** 308,311 ****
--- 333,338 ----
superclass into impostor. */
+ objc_mutex_lock(__objc_runtime_mutex);
+
for (node = hash_next (__objc_class_hash, NULL); node;
node = hash_next (__objc_class_hash, node))
***************
*** 317,320 ****
--- 344,349 ----
}
}
+
+ objc_mutex_unlock(__objc_runtime_mutex);
/* next, we update the dispatch tables... */
diff -rc2P objc/init.c objc-threaded/init.c
*** objc/init.c Sat Jan 20 21:09:37 1996
--- objc-threaded/init.c Fri Jan 26 14:43:19 1996
***************
*** 32,42 ****
/* This list contains all modules currently loaded into the runtime */
! static struct objc_list* __objc_module_list = 0;
/* This list contains all proto_list's not yet assigned class links */
! static struct objc_list* unclaimed_proto_list = 0;
/* List of unresolved static instances. */
! static struct objc_list *uninitialized_statics;
/* Check compiler vs runtime version */
--- 32,48 ----
/* This list contains all modules currently loaded into the runtime */
! static struct objc_list* __objc_module_list = 0; /* !T:MUTEX */
/* This list contains all proto_list's not yet assigned class links */
! static struct objc_list* unclaimed_proto_list = 0; /* !T:MUTEX */
/* List of unresolved static instances. */
! static struct objc_list *uninitialized_statics = 0; /* !T:MUTEX */
!
! /* Global runtime "write" mutex. */
! _objc_mutex_t __objc_runtime_mutex;
!
! /* Number of threads that are alive. */
! int __objc_runtime_threads_alive = 1; /* !T:MUTEX */
/* Check compiler vs runtime version */
***************
*** 53,60 ****
dynamic loader determine the classes that have been loaded when
an object file is dynamically linked in */
! void (*_objc_load_callback)(Class class, Category* category) = 0;
/* Is all categories/classes resolved? */
! BOOL __objc_dangling_categories = NO;
extern SEL
--- 59,66 ----
dynamic loader determine the classes that have been loaded when
an object file is dynamically linked in */
! void (*_objc_load_callback)(Class class, Category* category) = 0; /* !T:SAFE */
/* Is all categories/classes resolved? */
! BOOL __objc_dangling_categories = NO; /* !T:UNUSED */
extern SEL
***************
*** 70,73 ****
--- 76,81 ----
struct objc_static_instances **statics_in_module;
+ objc_mutex_lock(__objc_runtime_mutex);
+
while (*cell)
{
***************
*** 115,118 ****
--- 123,128 ----
cell = &(*cell)->tail;
}
+
+ objc_mutex_unlock(__objc_runtime_mutex);
} /* objc_init_statics */
***************
*** 151,154 ****
--- 161,169 ----
if (!previous_constructors)
{
+ /* Initialize thread-safe system */
+ __objc_init_thread_system();
+ __objc_runtime_threads_alive = 1;
+ __objc_runtime_mutex = objc_mutex_allocate();
+
__objc_init_selector_tables();
__objc_init_class_tables();
***************
*** 158,161 ****
--- 173,177 ----
/* Save the module pointer for later processing. (not currently used) */
+ objc_mutex_lock(__objc_runtime_mutex);
__objc_module_list = list_cons(module, __objc_module_list);
***************
*** 288,291 ****
--- 304,308 ----
}
+ objc_mutex_unlock(__objc_runtime_mutex);
}
***************
*** 316,319 ****
--- 333,338 ----
return;
+ objc_mutex_lock(__objc_runtime_mutex);
+
if (!proto_class)
proto_class = objc_lookup_class("Protocol");
***************
*** 349,352 ****
--- 368,373 ----
}
}
+
+ objc_mutex_unlock(__objc_runtime_mutex);
}
Only in objc: list.h
diff -rc2P objc/makefile.dos objc-threaded/makefile.dos
*** objc/makefile.dos Sat Jan 20 21:09:38 1996
--- objc-threaded/makefile.dos Sat Jan 20 22:13:18 1996
***************
*** 38,42 ****
OBJC_O = hash.o sarray.o class.o sendmsg.o init.o archive.o \
! selector.o objects.o misc.o object.o protocol.o encoding.o
libobjc.a: $(OBJC_O)
--- 38,42 ----
OBJC_O = hash.o sarray.o class.o sendmsg.o init.o archive.o \
! selector.o objects.o misc.o object.o protocol.o encoding.o thread.o
libobjc.a: $(OBJC_O)
***************
*** 45,52 ****
ranlib libobjc.a
! OBJC_H = hash.h list.h sarray.h objc.h \
objc-api.h \
object.h protocol.h mutex.h \
! typedstream.h
mostlyclean:
--- 45,52 ----
ranlib libobjc.a
! OBJC_H = hash.h objc-list.h sarray.h objc.h \
objc-api.h \
object.h protocol.h mutex.h \
! typedstream.h thread.h
mostlyclean:
diff -rc2P objc/objc-api.h objc-threaded/objc-api.h
*** objc/objc-api.h Sat Jan 20 21:09:38 1996
--- objc-threaded/objc-api.h Fri Jan 26 14:44:31 1996
***************
*** 30,33 ****
--- 30,34 ----
#include "objc/objc.h"
#include "objc/hash.h"
+ #include "objc/thread.h"
#include <stdio.h>
diff -rc2P objc/objc-list.h objc-threaded/objc-list.h
*** objc/objc-list.h Wed Dec 31 19:00:00 1969
--- objc-threaded/objc-list.h Thu Jun 15 08:40:27 1995
***************
*** 0 ****
--- 1,150 ----
+ /* Generic single linked list to keep various information
+ Copyright (C) 1993, 1994 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 -rc2P objc/objects.c objc-threaded/objects.c
*** objc/objects.c Sat Jan 20 21:09:38 1996
--- objc-threaded/objects.c Sun Jan 21 16:46:14 1996
***************
*** 32,38 ****
id __objc_object_copy(id);
! id (*_objc_object_alloc)(Class) = __objc_object_alloc;
! id (*_objc_object_dispose)(id) = __objc_object_dispose;
! id (*_objc_object_copy)(id) = __objc_object_copy;
id
--- 32,38 ----
id __objc_object_copy(id);
! id (*_objc_object_alloc)(Class) = __objc_object_alloc; /* !T:SINGLE */
! id (*_objc_object_dispose)(id) = __objc_object_dispose; /* !T:SINGLE */
! id (*_objc_object_copy)(id) = __objc_object_copy; /* !T:SINGLE */
id
diff -rc2P objc/runtime.h objc-threaded/runtime.h
*** objc/runtime.h Sat Jan 20 21:09:38 1996
--- objc-threaded/runtime.h Fri Jan 26 14:46:27 1996
***************
*** 38,43 ****
#include "objc/objc-api.h" /* runtime api functions */
#include "objc/hash.h" /* hash structures */
! #include "objc/list.h" /* linear lists */
extern void __objc_add_class_to_hash(Class); /* (objc-class.c) */
--- 38,45 ----
#include "objc/objc-api.h" /* runtime api functions */
+ #include "objc/thread.h" /* thread and mutex support */
+
#include "objc/hash.h" /* hash structures */
! #include "objc/objc-list.h" /* linear lists */
extern void __objc_add_class_to_hash(Class); /* (objc-class.c) */
***************
*** 49,52 ****
--- 51,58 ----
extern void __objc_register_selectors_from_class(Class); /* (objc-sel.c) */
extern void __objc_update_dispatch_table_for_class (Class);/* (objc-msg.c) */
+
+ extern int __objc_init_thread_system(void); /* thread.c */
+ extern int __objc_fini_thread_system(void); /* thread.c */
+
extern void class_add_method_list(Class, MethodList_t);
***************
*** 59,62 ****
--- 65,74 ----
/* Number of selectors stored in each of the selector tables */
extern int __objc_selector_max_index;
+
+ /* Mutex locking __objc_selector_max_index and its arrays. */
+ extern _objc_mutex_t __objc_runtime_mutex;
+
+ /* Number of threads which are alive. */
+ extern int __objc_runtime_threads_alive;
#ifdef DEBUG
diff -rc2P objc/sarray.c objc-threaded/sarray.c
*** objc/sarray.c Sat Jan 20 21:09:38 1996
--- objc-threaded/sarray.c Fri Jan 26 14:52:16 1996
***************
*** 26,36 ****
#include "objc/sarray.h"
#include <stdio.h>
#include "assert.h"
! int nbuckets = 0;
! int nindices = 0;
! int narrays = 0;
! int idxsize = 0;
#ifdef OBJC_SPARSE2
--- 26,39 ----
#include "objc/sarray.h"
+ #include "objc/runtime.h"
#include <stdio.h>
#include "assert.h"
! int nbuckets = 0; /* !T:MUTEX */
! int nindices = 0; /* !T:MUTEX */
! int narrays = 0; /* !T:MUTEX */
! int idxsize = 0; /* !T:MUTEX */
!
! static void * first_free_data = NULL; /* !T:MUTEX */
#ifdef OBJC_SPARSE2
***************
*** 47,50 ****
--- 50,98 ----
#endif
+ /* This function removes any structures left over from free operations
+ that were not safe in a multi-threaded environment. */
+ void
+ sarray_remove_garbage(void)
+ {
+ void **vp;
+ void *np;
+
+ objc_mutex_lock(__objc_runtime_mutex);
+
+ vp = first_free_data;
+ first_free_data = NULL;
+
+ while (vp) {
+ np = *vp;
+ free(vp);
+ vp = np;
+ }
+
+ objc_mutex_unlock(__objc_runtime_mutex);
+ }
+
+ /* Free a block of dynamically allocated memory. If we are in multi-threaded
+ mode, it is ok to free it. If not, we add it to the garbage heap to be
+ freed later. */
+
+ static void
+ sarray_free_garbage(void *vp)
+ {
+ objc_mutex_lock(__objc_runtime_mutex);
+
+ if (__objc_runtime_threads_alive == 1) {
+ free(vp);
+ if (first_free_data)
+ sarray_remove_garbage();
+ }
+ else {
+ *(void **)vp = first_free_data;
+ first_free_data = vp;
+ }
+
+ objc_mutex_unlock(__objc_runtime_mutex);
+ }
+
+ /* sarray_at_put : copies data in such a way as to be thread reader safe. */
void
sarray_at_put(struct sarray* array, sidx index, void* element)
***************
*** 52,57 ****
--- 100,107 ----
#ifdef OBJC_SPARSE3
struct sindex** the_index;
+ struct sindex* new_index;
#endif
struct sbucket** the_bucket;
+ struct sbucket* new_bucket;
#ifdef OBJC_SPARSE3
size_t ioffset;
***************
*** 97,116 ****
/* The index was previously empty, allocate a new */
! *the_index = (struct sindex*)__objc_xmalloc(sizeof(struct sindex));
! memcpy(*the_index, array->empty_index, sizeof(struct sindex));
! (*the_index)->version = array->version;
the_bucket = &((*the_index)->buckets[boffset]);
- nindices += 1;
! } else if ((*the_index)->version != array->version) {
/* This index must be lazy copied */
struct sindex* old_index = *the_index;
! *the_index = (struct sindex*)__objc_xmalloc(sizeof(struct sindex));
! memcpy( *the_index,old_index, sizeof(struct sindex));
! (*the_index)->version = array->version;
the_bucket = &((*the_index)->buckets[boffset]);
- nindices += 1;
}
--- 147,168 ----
/* The index was previously empty, allocate a new */
! new_index = (struct sindex*)__objc_xmalloc(sizeof(struct sindex));
! memcpy(new_index, array->empty_index, sizeof(struct sindex));
! new_index->version.version = array->version.version;
! *the_index = new_index; /* Prepared for install. */
the_bucket = &((*the_index)->buckets[boffset]);
! nindices += 1;
! } else if ((*the_index)->version.version != array->version.version) {
/* This index must be lazy copied */
struct sindex* old_index = *the_index;
! new_index = (struct sindex*)__objc_xmalloc(sizeof(struct sindex));
! memcpy( new_index, old_index, sizeof(struct sindex));
! new_index->version.version = array->version.version;
! *the_index = new_index; /* Prepared for install. */
the_bucket = &((*the_index)->buckets[boffset]);
+ nindices += 1;
}
***************
*** 123,138 ****
/* The bucket was previously empty (or something like that), */
/* allocate a new. This is the effect of `lazy' allocation */
! *the_bucket = (struct sbucket*)__objc_xmalloc(sizeof(struct sbucket));
! memcpy((void *) *the_bucket, (const void*)array->empty_bucket, sizeof(struct sbucket));
! (*the_bucket)->version = array->version;
nbuckets += 1;
! } else if ((*the_bucket)->version != array->version) {
/* Perform lazy copy. */
struct sbucket* old_bucket = *the_bucket;
! *the_bucket = (struct sbucket*)__objc_xmalloc(sizeof(struct sbucket));
! memcpy( *the_bucket,old_bucket, sizeof(struct sbucket));
! (*the_bucket)->version = array->version;
nbuckets += 1;
--- 175,194 ----
/* The bucket was previously empty (or something like that), */
/* allocate a new. This is the effect of `lazy' allocation */
! new_bucket = (struct sbucket*)__objc_xmalloc(sizeof(struct sbucket));
! memcpy((void *) new_bucket, (const void*)array->empty_bucket, sizeof(struct sbucket));
! new_bucket->version.version = array->version.version;
! *the_bucket = new_bucket; /* Prepared for install. */
!
nbuckets += 1;
! } else if ((*the_bucket)->version.version != array->version.version) {
/* Perform lazy copy. */
struct sbucket* old_bucket = *the_bucket;
! new_bucket = (struct sbucket*)__objc_xmalloc(sizeof(struct sbucket));
! memcpy( new_bucket, old_bucket, sizeof(struct sbucket));
! new_bucket->version.version = array->version.version;
! *the_bucket = new_bucket; /* Prepared for install. */
!
nbuckets += 1;
***************
*** 152,162 ****
sarray_new (int size, void* default_element)
{
#ifdef OBJC_SPARSE3
size_t num_indices = ((size-1)/(INDEX_CAPACITY))+1;
#else /* OBJC_SPARSE2 */
size_t num_indices = ((size-1)/BUCKET_SIZE)+1;
#endif
int counter;
- struct sarray* arr;
assert(size > 0);
--- 208,220 ----
sarray_new (int size, void* default_element)
{
+ struct sarray* arr;
#ifdef OBJC_SPARSE3
size_t num_indices = ((size-1)/(INDEX_CAPACITY))+1;
+ struct sindex ** new_indices;
#else /* OBJC_SPARSE2 */
size_t num_indices = ((size-1)/BUCKET_SIZE)+1;
+ struct sbucket ** new_buckets;
#endif
int counter;
assert(size > 0);
***************
*** 164,185 ****
/* Allocate core array */
arr = (struct sarray*) __objc_xmalloc(sizeof(struct sarray));
! arr->version = 0;
! narrays += 1;
/* Initialize members */
#ifdef OBJC_SPARSE3
arr->capacity = num_indices*INDEX_CAPACITY;
! arr->indices = (struct sindex**)
__objc_xmalloc(sizeof(struct sindex*)*num_indices);
- idxsize += num_indices;
arr->empty_index = (struct sindex*) __objc_xmalloc(sizeof(struct sindex));
! arr->empty_index->version = 0;
nindices += 1;
#else /* OBJC_SPARSE2 */
arr->capacity = num_indices*BUCKET_SIZE;
! arr->buckets = (struct sbucket**)
__objc_xmalloc(sizeof(struct sbucket*)*num_indices);
idxsize += num_indices;
--- 222,246 ----
/* Allocate core array */
arr = (struct sarray*) __objc_xmalloc(sizeof(struct sarray));
! arr->version.version = 0;
/* Initialize members */
#ifdef OBJC_SPARSE3
arr->capacity = num_indices*INDEX_CAPACITY;
! new_indices = (struct sindex**)
__objc_xmalloc(sizeof(struct sindex*)*num_indices);
arr->empty_index = (struct sindex*) __objc_xmalloc(sizeof(struct sindex));
! arr->empty_index->version.version = 0;
!
! narrays += 1;
! idxsize += num_indices;
nindices += 1;
#else /* OBJC_SPARSE2 */
arr->capacity = num_indices*BUCKET_SIZE;
! new_buckets = (struct sbucket**)
__objc_xmalloc(sizeof(struct sbucket*)*num_indices);
+
+ narrays += 1;
idxsize += num_indices;
***************
*** 187,191 ****
arr->empty_bucket = (struct sbucket*) __objc_xmalloc(sizeof(struct sbucket));
! arr->empty_bucket->version = 0;
nbuckets += 1;
--- 248,253 ----
arr->empty_bucket = (struct sbucket*) __objc_xmalloc(sizeof(struct sbucket));
! arr->empty_bucket->version.version = 0;
!
nbuckets += 1;
***************
*** 201,218 ****
for (counter=0; counter<num_indices; counter++)
! arr->indices[counter] = arr->empty_index;
#else /* OBJC_SPARSE2 */
for (counter=0; counter<num_indices; counter++)
! arr->buckets[counter] = arr->empty_bucket;
#endif
!
return arr;
}
! /* Reallocate the sparse array to hold `newsize' entries */
void
--- 263,288 ----
for (counter=0; counter<num_indices; counter++)
! new_indices[counter] = arr->empty_index;
#else /* OBJC_SPARSE2 */
for (counter=0; counter<num_indices; counter++)
! new_buckets[counter] = arr->empty_bucket;
#endif
!
! #ifdef OBJC_SPARSE3
! arr->indices = new_indices;
! #else /* OBJC_SPARSE2 */
! arr->buckets = new_buckets;
! #endif
!
return arr;
}
! /* Reallocate the sparse array to hold `newsize' entries
! Note: We really allocate and then free. We have to do this to ensure that
! any concurrent readers notice the update. */
void
***************
*** 224,227 ****
--- 294,300 ----
size_t rounded_size = (new_max_index+1)*INDEX_CAPACITY;
+ struct sindex ** new_indices;
+ struct sindex ** old_indices;
+
#else /* OBJC_SPARSE2 */
size_t old_max_index = (array->capacity-1)/BUCKET_SIZE;
***************
*** 229,232 ****
--- 302,308 ----
size_t rounded_size = (new_max_index+1)*BUCKET_SIZE;
+ struct sbucket ** new_buckets;
+ struct sbucket ** old_buckets;
+
#endif
***************
*** 236,320 ****
/* The size is the same, just ignore the request */
! if(rounded_size == array->capacity)
return;
assert(array->ref_count == 1); /* stop if lazy copied... */
! if(rounded_size < array->capacity)
{
- /* update capacity */
- array->capacity = rounded_size;
- /* free buckets above new_max_index */
- for(counter = old_max_index; counter > new_max_index; counter-- ) {
#ifdef OBJC_SPARSE3
! struct sindex* idx = array->indices[counter];
! if((idx != array->empty_index) && (idx->version == array->version)) {
! int c2;
! for(c2=0; c2<INDEX_SIZE; c2++) {
! struct sbucket* bkt = idx->buckets[c2];
! if((bkt != array->empty_bucket) && (bkt->version == array->version))
! {
! free(bkt);
! nbuckets -= 1;
! }
! }
! free(idx);
! nindices -= 1;
! }
#else /* OBJC_SPARSE2 */
! struct sbucket* bkt = array->buckets[counter];
! if ((bkt != array->empty_bucket) && (bkt->version == array->version))
! {
! free(bkt);
! nbuckets -= 1;
! }
#endif
! }
!
! #ifdef OBJC_SPARSE3
! /* realloc to free the space above new_max_index */
! array->indices = (struct sindex**)
! __objc_xrealloc(array->indices,
! (new_max_index+1)*sizeof(struct sindex*));
! #else /* OBJC_SPARSE2 */
! array->buckets = (struct sbucket**)
! __objc_xrealloc(array->buckets,
! (new_max_index+1)*sizeof(struct sbucket*));
! #endif
! idxsize -= (old_max_index-new_max_index);
!
! return;
! }
!
! /* We are asked to extend the array -- reallocate the bucket table, */
! /* and insert empty_bucket in newly allocated places. */
! if(rounded_size > array->capacity)
! {
/* update capacity */
array->capacity = rounded_size;
#ifdef OBJC_SPARSE3
! /* realloc to make room in table above old_max_index */
! array->indices = (struct sindex**)
! __objc_xrealloc(array->indices,
! (new_max_index+1)*sizeof(struct sindex*));
/* reset entries above old_max_index to empty_bucket */
for(counter = old_max_index+1; counter <= new_max_index; counter++)
! array->indices[counter] = array->empty_index;
!
#else /* OBJC_SPARSE2 */
-
- /* realloc to make room in table above old_max_index */
- array->buckets = (struct sbucket**)
- __objc_xrealloc(array->buckets,
- (new_max_index+1)*sizeof(struct sbucket*));
-
/* reset entries above old_max_index to empty_bucket */
for(counter = old_max_index+1; counter <= new_max_index; counter++)
! array->buckets[counter] = array->empty_bucket;
#endif
idxsize += (new_max_index-old_max_index);
return;
--- 312,381 ----
/* The size is the same, just ignore the request */
! if(rounded_size <= array->capacity)
return;
assert(array->ref_count == 1); /* stop if lazy copied... */
! /* We are asked to extend the array -- allocate new bucket table, */
! /* and insert empty_bucket in newly allocated places. */
! if(rounded_size > array->capacity)
{
#ifdef OBJC_SPARSE3
! new_max_index += 4;
! rounded_size = (new_max_index+1)*INDEX_CAPACITY;
!
#else /* OBJC_SPARSE2 */
! new_max_index += 4;
! rounded_size = (new_max_index+1)*BUCKET_SIZE;
#endif
!
/* update capacity */
array->capacity = rounded_size;
#ifdef OBJC_SPARSE3
! /* alloc to force re-read by any concurrent readers. */
! old_indices = array->indices;
! new_indices = (struct sindex**)
! __objc_xmalloc((new_max_index+1)*sizeof(struct sindex*));
! #else /* OBJC_SPARSE2 */
! old_buckets = array->buckets;
! new_buckets = (struct sbucket**)
! __objc_xmalloc((new_max_index+1)*sizeof(struct sbucket*));
! #endif
+ /* copy buckets below old_max_index (they are still valid) */
+ for(counter = 0; counter <= old_max_index; counter++ ) {
+ #ifdef OBJC_SPARSE3
+ new_indices[counter] = old_indices[counter];
+ #else /* OBJC_SPARSE2 */
+ new_buckets[counter] = old_buckets[counter];
+ #endif
+ }
+
+ #ifdef OBJC_SPARSE3
/* reset entries above old_max_index to empty_bucket */
for(counter = old_max_index+1; counter <= new_max_index; counter++)
! new_indices[counter] = array->empty_index;
#else /* OBJC_SPARSE2 */
/* reset entries above old_max_index to empty_bucket */
for(counter = old_max_index+1; counter <= new_max_index; counter++)
! new_buckets[counter] = array->empty_bucket;
! #endif
!
! #ifdef OBJC_SPARSE3
! /* install the new indices */
! array->indices = new_indices;
! #else /* OBJC_SPARSE2 */
! array->buckets = new_buckets;
! #endif
+ #ifdef OBJC_SPARSE3
+ /* free the old indices */
+ sarray_free_garbage(old_indices);
+ #else /* OBJC_SPARSE2 */
+ sarray_free_garbage(old_buckets);
#endif
+
idxsize += (new_max_index-old_max_index);
return;
***************
*** 327,334 ****
--- 388,398 ----
void
sarray_free(struct sarray* array) {
+
#ifdef OBJC_SPARSE3
size_t old_max_index = (array->capacity-1)/INDEX_CAPACITY;
+ struct sindex ** old_indices;
#else
size_t old_max_index = (array->capacity-1)/BUCKET_SIZE;
+ struct sbucket ** old_buckets;
#endif
int counter = 0;
***************
*** 339,342 ****
--- 403,412 ----
return;
+ #ifdef OBJC_SPARSE3
+ old_indices = array->indices;
+ #else
+ old_buckets = array->buckets;
+ #endif
+
if((array->is_copy_of) && ((array->is_copy_of->ref_count - 1) == 0))
sarray_free(array->is_copy_of);
***************
*** 345,367 ****
for(counter = 0; counter <= old_max_index; counter++ ) {
#ifdef OBJC_SPARSE3
! struct sindex* idx = array->indices[counter];
! if((idx != array->empty_index) && (idx->version == array->version)) {
int c2;
for(c2=0; c2<INDEX_SIZE; c2++) {
struct sbucket* bkt = idx->buckets[c2];
! if((bkt != array->empty_bucket) && (bkt->version == array->version))
{
! free(bkt);
nbuckets -= 1;
}
}
! free(idx);
nindices -= 1;
}
#else /* OBJC_SPARSE2 */
struct sbucket* bkt = array->buckets[counter];
! if ((bkt != array->empty_bucket) && (bkt->version == array->version))
{
! free(bkt);
nbuckets -= 1;
}
--- 415,440 ----
for(counter = 0; counter <= old_max_index; counter++ ) {
#ifdef OBJC_SPARSE3
! struct sindex* idx = old_indices[counter];
! if((idx != array->empty_index) &&
! (idx->version.version == array->version.version)) {
int c2;
for(c2=0; c2<INDEX_SIZE; c2++) {
struct sbucket* bkt = idx->buckets[c2];
! if((bkt != array->empty_bucket) &&
! (bkt->version.version == array->version.version))
{
! sarray_free_garbage(bkt);
nbuckets -= 1;
}
}
! sarray_free_garbage(idx);
nindices -= 1;
}
#else /* OBJC_SPARSE2 */
struct sbucket* bkt = array->buckets[counter];
! if ((bkt != array->empty_bucket) &&
! (bkt->version.version == array->version.version))
{
! sarray_free_garbage(bkt);
nbuckets -= 1;
}
***************
*** 371,376 ****
#ifdef OBJC_SPARSE3
/* free empty_index */
! if(array->empty_index->version == array->version) {
! free(array->empty_index);
nindices -= 1;
}
--- 444,449 ----
#ifdef OBJC_SPARSE3
/* free empty_index */
! if(array->empty_index->version.version == array->version.version) {
! sarray_free_garbage(array->empty_index);
nindices -= 1;
}
***************
*** 378,401 ****
/* free empty_bucket */
! if(array->empty_bucket->version == array->version) {
! free(array->empty_bucket);
nbuckets -= 1;
}
#ifdef OBJC_SPARSE3
/* free bucket table */
! free(array->indices);
! idxsize -= (old_max_index+1);
#else
/* free bucket table */
! free(array->buckets);
! idxsize -= (old_max_index+1);
#endif
!
/* free array */
! free(array);
! narrays -= 1;
}
--- 451,473 ----
/* free empty_bucket */
! if(array->empty_bucket->version.version == array->version.version) {
! sarray_free_garbage(array->empty_bucket);
nbuckets -= 1;
}
+ idxsize -= (old_max_index+1);
+ narrays -= 1;
#ifdef OBJC_SPARSE3
/* free bucket table */
! sarray_free_garbage(array->indices);
#else
/* free bucket table */
! sarray_free_garbage(array->buckets);
#endif
!
/* free array */
! sarray_free_garbage(array);
}
***************
*** 406,441 ****
sarray_lazy_copy(struct sarray* oarr)
{
#ifdef OBJC_SPARSE3
size_t num_indices = ((oarr->capacity-1)/INDEX_CAPACITY)+1;
#else /* OBJC_SPARSE2 */
size_t num_indices = ((oarr->capacity-1)/BUCKET_SIZE)+1;
#endif
- struct sarray* arr;
/* Allocate core array */
! arr = (struct sarray*) __objc_xmalloc(sizeof(struct sarray));
! memcpy( arr,oarr, sizeof(struct sarray));
! arr->version = oarr->version + 1;
! arr->is_copy_of = oarr;
! oarr->ref_count += 1;
arr->ref_count = 1;
#ifdef OBJC_SPARSE3
/* Copy bucket table */
! arr->indices = (struct sindex**)
__objc_xmalloc(sizeof(struct sindex*)*num_indices);
! memcpy( arr->indices,oarr->indices,
sizeof(struct sindex*)*num_indices);
#else
/* Copy bucket table */
! arr->buckets = (struct sbucket**)
__objc_xmalloc(sizeof(struct sbucket*)*num_indices);
! memcpy( arr->buckets,oarr->buckets,
sizeof(struct sbucket*)*num_indices);
#endif
idxsize += num_indices;
narrays += 1;
!
return arr;
}
--- 478,522 ----
sarray_lazy_copy(struct sarray* oarr)
{
+ struct sarray* arr;
+
#ifdef OBJC_SPARSE3
size_t num_indices = ((oarr->capacity-1)/INDEX_CAPACITY)+1;
+ struct sindex ** new_indices;
#else /* OBJC_SPARSE2 */
size_t num_indices = ((oarr->capacity-1)/BUCKET_SIZE)+1;
+ struct sbucket ** new_buckets;
#endif
/* Allocate core array */
! arr = (struct sarray*) __objc_xmalloc(sizeof(struct sarray)); /* !!! */
! arr->version.version = oarr->version.version + 1;
! #ifdef OBJC_SPARSE3
! arr->empty_index = oarr->empty_index;
! #endif
! arr->empty_bucket = oarr->empty_bucket;
arr->ref_count = 1;
+ oarr->ref_count += 1;
+ arr->is_copy_of = oarr;
+ arr->capacity = oarr->capacity;
#ifdef OBJC_SPARSE3
/* Copy bucket table */
! new_indices = (struct sindex**)
__objc_xmalloc(sizeof(struct sindex*)*num_indices);
! memcpy( new_indices,oarr->indices,
sizeof(struct sindex*)*num_indices);
+ arr->indices = new_indices;
#else
/* Copy bucket table */
! new_buckets = (struct sbucket**)
__objc_xmalloc(sizeof(struct sbucket*)*num_indices);
! memcpy( new_buckets,oarr->buckets,
sizeof(struct sbucket*)*num_indices);
+ arr->buckets = new_buckets;
#endif
idxsize += num_indices;
narrays += 1;
!
return arr;
}
diff -rc2P objc/sarray.h objc-threaded/sarray.h
*** objc/sarray.h Sat Jan 20 21:09:38 1996
--- objc-threaded/sarray.h Fri Jan 26 14:50:39 1996
***************
*** 43,46 ****
--- 43,48 ----
#include <stddef.h>
+ #include "objc/thread.h"
+
extern int nbuckets; /* for stats */
extern int nindices;
***************
*** 112,118 ****
void * __objc_xmalloc (size_t size);
struct sbucket {
void* elems[BUCKET_SIZE]; /* elements stored in array */
! short version; /* used for copy-on-write */
};
--- 114,125 ----
void * __objc_xmalloc (size_t size);
+ union sversion {
+ int version;
+ void *next_free;
+ };
+
struct sbucket {
void* elems[BUCKET_SIZE]; /* elements stored in array */
! union sversion version; /* used for copy-on-write */
};
***************
*** 121,125 ****
struct sindex {
struct sbucket* buckets[INDEX_SIZE];
! short version;
};
--- 128,132 ----
struct sindex {
struct sbucket* buckets[INDEX_SIZE];
! union sversion version; /* used for copy-on-write */
};
***************
*** 134,138 ****
#endif /* OBJC_SPARSE2 */
struct sbucket* empty_bucket;
! short version;
short ref_count;
struct sarray* is_copy_of;
--- 141,145 ----
#endif /* OBJC_SPARSE2 */
struct sbucket* empty_bucket;
! union sversion version; /* used for copy-on-write */
short ref_count;
struct sarray* is_copy_of;
***************
*** 143,150 ****
void sarray_free(struct sarray*);
struct sarray* sarray_lazy_copy(struct sarray*);
- struct sarray* sarray_hard_copy(struct sarray*); /* ... like the name? */
void sarray_realloc(struct sarray*, int new_size);
void sarray_at_put(struct sarray*, sidx index, void* elem);
void sarray_at_put_safe(struct sarray*, sidx index, void* elem);
--- 150,159 ----
void sarray_free(struct sarray*);
struct sarray* sarray_lazy_copy(struct sarray*);
void sarray_realloc(struct sarray*, int new_size);
void sarray_at_put(struct sarray*, sidx index, void* elem);
void sarray_at_put_safe(struct sarray*, sidx index, void* elem);
+
+ struct sarray* sarray_hard_copy(struct sarray*); /* ... like the name? */
+ void sarray_remove_garbage(void);
diff -rc2P objc/selector.c objc-threaded/selector.c
*** objc/selector.c Sat Jan 20 21:09:38 1996
--- objc-threaded/selector.c Fri Jan 26 14:49:35 1996
***************
*** 32,43 ****
/* Tables mapping selector names to uid and opposite */
! static struct sarray* __objc_selector_array = 0; /* uid -> sel */
! static struct sarray* __objc_selector_names = 0; /* uid -> name */
! static cache_ptr __objc_selector_hash = 0; /* name -> uid */
static void register_selectors_from_list(MethodList_t);
/* Number of selectors stored in each of the above tables */
! int __objc_selector_max_index = 0;
void __objc_init_selector_tables()
--- 32,43 ----
/* Tables mapping selector names to uid and opposite */
! static struct sarray* __objc_selector_array = 0; /* uid -> sel !T:MUTEX */
! static struct sarray* __objc_selector_names = 0; /* uid -> name !T:MUTEX */
! static cache_ptr __objc_selector_hash = 0; /* name -> uid !T:MUTEX */
static void register_selectors_from_list(MethodList_t);
/* Number of selectors stored in each of the above tables */
! int __objc_selector_max_index = 0; /* !T:MUTEX */
void __objc_init_selector_tables()
***************
*** 123,129 ****
sidx i;
i = (sidx) hash_value_for_key (__objc_selector_hash, name);
if (i == 0)
! return 0;
for (l = (struct objc_list*)sarray_get (__objc_selector_array, i);
--- 123,134 ----
sidx i;
+ objc_mutex_lock(__objc_runtime_mutex);
+
i = (sidx) hash_value_for_key (__objc_selector_hash, name);
if (i == 0)
! {
! objc_mutex_unlock(__objc_runtime_mutex);
! return 0;
! }
for (l = (struct objc_list*)sarray_get (__objc_selector_array, i);
***************
*** 135,138 ****
--- 140,144 ----
if (s->sel_types == types)
{
+ objc_mutex_unlock(__objc_runtime_mutex);
return s;
}
***************
*** 140,147 ****
--- 146,155 ----
else if (sel_types_match (s->sel_types, types))
{
+ objc_mutex_unlock(__objc_runtime_mutex);
return s;
}
}
+ objc_mutex_unlock(__objc_runtime_mutex);
return 0;
}
***************
*** 155,161 ****
SEL s;
i = (sidx) hash_value_for_key (__objc_selector_hash, name);
if (i == 0)
! return 0;
for (l = (struct objc_list*)sarray_get (__objc_selector_array, i);
--- 163,174 ----
SEL s;
+ objc_mutex_lock(__objc_runtime_mutex);
+
i = (sidx) hash_value_for_key (__objc_selector_hash, name);
if (i == 0)
! {
! objc_mutex_unlock(__objc_runtime_mutex);
! return 0;
! }
for (l = (struct objc_list*)sarray_get (__objc_selector_array, i);
***************
*** 164,170 ****
s = (SEL) l->head;
if (s->sel_types)
! return s;
}
return s;
}
--- 177,187 ----
s = (SEL) l->head;
if (s->sel_types)
! {
! objc_mutex_unlock(__objc_runtime_mutex);
! return s;
! }
}
+ objc_mutex_unlock(__objc_runtime_mutex);
return s;
}
***************
*** 177,185 ****
sidx i;
i = (sidx) hash_value_for_key (__objc_selector_hash, name);
if (soffset_decode (i) == 0)
! return 0;
l = (struct objc_list*)sarray_get (__objc_selector_array, i);
if (l == 0)
return 0;
--- 194,209 ----
sidx i;
+ objc_mutex_lock(__objc_runtime_mutex);
+
i = (sidx) hash_value_for_key (__objc_selector_hash, name);
if (soffset_decode (i) == 0)
! {
! objc_mutex_unlock(__objc_runtime_mutex);
! return 0;
! }
l = (struct objc_list*)sarray_get (__objc_selector_array, i);
+ objc_mutex_unlock(__objc_runtime_mutex);
+
if (l == 0)
return 0;
***************
*** 200,208 ****
sel_get_name (SEL selector)
{
if ((soffset_decode((sidx)selector->sel_id) > 0)
&& (soffset_decode((sidx)selector->sel_id) <= __objc_selector_max_index))
! return sarray_get (__objc_selector_names, (sidx) selector->sel_id);
else
! return 0;
}
--- 224,237 ----
sel_get_name (SEL selector)
{
+ const char *ret;
+
+ objc_mutex_lock(__objc_runtime_mutex);
if ((soffset_decode((sidx)selector->sel_id) > 0)
&& (soffset_decode((sidx)selector->sel_id) <= __objc_selector_max_index))
! ret = sarray_get (__objc_selector_names, (sidx) selector->sel_id);
else
! ret = 0;
! objc_mutex_unlock(__objc_runtime_mutex);
! return ret;
}
***************
*** 228,232 ****
/* Store the passed selector name in the selector record and return its
! selector value (value returned by sel_get_uid). */
SEL
__sel_register_typed_name (const char *name, const char *types,
--- 257,262 ----
/* Store the passed selector name in the selector record and return its
! selector value (value returned by sel_get_uid).
! Assumes that the calling function has locked down __objc_runtime_mutex. */
SEL
__sel_register_typed_name (const char *name, const char *types,
***************
*** 311,315 ****
sel_register_name (const char *name)
{
! return __sel_register_typed_name (name, 0, 0);
}
--- 341,351 ----
sel_register_name (const char *name)
{
! SEL ret;
!
! objc_mutex_lock(__objc_runtime_mutex);
! ret = __sel_register_typed_name (name, 0, 0);
! objc_mutex_unlock(__objc_runtime_mutex);
!
! return ret;
}
***************
*** 317,321 ****
sel_register_typed_name (const char *name, const char *type)
{
! return __sel_register_typed_name (name, type, 0);
}
--- 353,363 ----
sel_register_typed_name (const char *name, const char *type)
{
! SEL ret;
!
! objc_mutex_lock(__objc_runtime_mutex);
! ret = __sel_register_typed_name (name, type, 0);
! objc_mutex_unlock(__objc_runtime_mutex);
!
! return ret;
}
diff -rc2P objc/sendmsg.c objc-threaded/sendmsg.c
*** objc/sendmsg.c Sat Jan 20 21:09:38 1996
--- objc-threaded/sendmsg.c Fri Jan 26 15:09:21 1996
***************
*** 41,45 ****
/* The uninstalled dispatch table */
! struct sarray* __objc_uninstalled_dtable = 0;
/* Send +initialize to class */
--- 41,45 ----
/* The uninstalled dispatch table */
! struct sarray* __objc_uninstalled_dtable = 0; /* !T:MUTEX */
/* Send +initialize to class */
***************
*** 77,81 ****
--- 77,83 ----
if(res == __objc_init_install_dtable)
{
+ objc_mutex_lock(__objc_runtime_mutex);
__objc_install_dispatch_table_for_class (class);
+ objc_mutex_unlock(__objc_runtime_mutex);
res = sarray_get (class->dtable, (size_t) sel->sel_id);
}
***************
*** 97,101 ****
--- 99,105 ----
if(res == __objc_init_install_dtable)
{
+ objc_mutex_lock(__objc_runtime_mutex);
__objc_install_dispatch_table_for_class (object->class_pointer);
+ objc_mutex_unlock(__objc_runtime_mutex);
res = sarray_get (object->class_pointer->dtable, (size_t) sel->sel_id);
}
***************
*** 173,176 ****
--- 177,182 ----
goto already_initialized;
+ objc_mutex_lock(__objc_runtime_mutex);
+
if(CLS_ISCLASS(receiver->class_pointer))
{
***************
*** 199,202 ****
--- 205,209 ----
CLS_SETINITIALIZED((Class)receiver);
}
+ objc_mutex_unlock(__objc_runtime_mutex);
already_initialized:
***************
*** 270,273 ****
--- 277,281 ----
}
+ /* Assumes that __objc_runtime_mutex is locked down. */
static void
__objc_install_dispatch_table_for_class (Class class)
***************
*** 290,294 ****
--- 298,304 ----
if (super == 0)
{
+ objc_mutex_lock(__objc_runtime_mutex);
class->dtable = sarray_new (__objc_selector_max_index, 0);
+ objc_mutex_unlock(__objc_runtime_mutex);
}
else
***************
*** 312,315 ****
--- 322,326 ----
{
Class next;
+ struct sarray *arr;
/* not yet installed -- skip it */
***************
*** 317,322 ****
return;
! sarray_free (class->dtable); /* release memory */
__objc_install_premature_dtable (class); /* someone might require it... */
__objc_install_dispatch_table_for_class (class); /* could have been lazy... */
--- 328,337 ----
return;
! objc_mutex_lock(__objc_runtime_mutex);
!
! arr = class->dtable;
__objc_install_premature_dtable (class); /* someone might require it... */
+ sarray_free (arr); /* release memory */
+
__objc_install_dispatch_table_for_class (class); /* could have been lazy... */
***************
*** 325,328 ****
--- 340,344 ----
__objc_update_dispatch_table_for_class (next);
+ objc_mutex_unlock(__objc_runtime_mutex);
}
***************
*** 330,334 ****
/* This function adds a method list to a class. This function is
typically called by another function specific to the run-time. As
! such this function does not worry about thread safe issued.
This one is only called for categories. Class objects have their
--- 346,350 ----
/* This function adds a method list to a class. This function is
typically called by another function specific to the run-time. As
! such this function does not worry about thread safe issues.
This one is only called for categories. Class objects have their
***************
*** 339,343 ****
{
int i;
! static SEL initialize_sel = 0;
if (!initialize_sel)
initialize_sel = sel_register_name ("initialize");
--- 355,360 ----
{
int i;
! static SEL initialize_sel = 0; /* !T:SAFE2 */
!
if (!initialize_sel)
initialize_sel = sel_register_name ("initialize");
***************
*** 483,487 ****
{
IMP imp;
! static SEL frwd_sel = 0;
SEL err_sel;
--- 500,504 ----
{
IMP imp;
! static SEL frwd_sel = 0; /* !T:SAFE2 */
SEL err_sel;
***************
*** 535,538 ****
--- 552,558 ----
{
int total = 0;
+
+ objc_mutex_lock(__objc_runtime_mutex);
+
printf("memory usage: (%s)\n",
#ifdef OBJC_SPARSE2
***************
*** 553,556 ****
--- 573,578 ----
printf("total: %d bytes\n", total);
printf("===================================\n");
+
+ objc_mutex_unlock(__objc_runtime_mutex);
}
diff -rc2P objc/thread-decosf1.c objc-threaded/thread-decosf1.c
*** objc/thread-decosf1.c Wed Dec 31 19:00:00 1969
--- objc-threaded/thread-decosf1.c Sun Jan 21 19:36:27 1996
***************
*** 0 ****
--- 1,325 ----
+ /* GNU Objective C Runtime Thread Interface
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Author: Galen C. Hunt (gchunt@cs.rochester.edu)
+
+ This file is included into thread.c
+
+ This file is part of GNU CC.
+
+ GNU CC is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2, or (at your option) any later version.
+
+ GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU CC; see the file COPYING. If not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, 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 -rc2P objc/thread-irix.c objc-threaded/thread-irix.c
*** objc/thread-irix.c Wed Dec 31 19:00:00 1969
--- objc-threaded/thread-irix.c Sun Jan 21 19:36:27 1996
***************
*** 0 ****
--- 1,314 ----
+ /* GNU Objective C Runtime Thread Interface - SGI IRIX Implementation
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Author: Galen C. Hunt (gchunt@cs.rochester.edu)
+
+ This file is included into thread.c
+
+ This file is part of GNU CC.
+
+ GNU CC is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2, or (at your option) any later version.
+
+ GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU CC; see the file COPYING. If not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, 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 -rc2P objc/thread-single.c objc-threaded/thread-single.c
*** objc/thread-single.c Wed Dec 31 19:00:00 1969
--- objc-threaded/thread-single.c Sun Jan 21 19:36:27 1996
***************
*** 0 ****
--- 1,239 ----
+ /* GNU Objective C Runtime Thread Implementation
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Author: Galen C. Hunt (gchunt@cs.rochester.edu)
+
+ This file is included into thread.c
+
+ This file is part of GNU CC.
+
+ GNU CC is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2, or (at your option) any later version.
+
+ GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU CC; see the file COPYING. If not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, 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 -rc2P objc/thread-solaris.c objc-threaded/thread-solaris.c
*** objc/thread-solaris.c Wed Dec 31 19:00:00 1969
--- objc-threaded/thread-solaris.c Sun Jan 21 19:36:27 1996
***************
*** 0 ****
--- 1,328 ----
+ /* GNU Objective C Runtime Thread Interface
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Author: Galen C. Hunt (gchunt@cs.rochester.edu)
+
+ This file is included into thread.c
+
+ This file is part of GNU CC.
+
+ GNU CC is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2, or (at your option) any later version.
+
+ GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU CC; see the file COPYING. If not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, 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 -rc2P objc/thread-test/Makefile objc-threaded/thread-test/Makefile
*** objc/thread-test/Makefile Wed Dec 31 19:00:00 1969
--- objc-threaded/thread-test/Makefile Sun Jan 21 20:06:00 1996
***************
*** 0 ****
--- 1,45 ----
+ ##############################################################################
+ #
+ #
+ #
+
+ all: test1
+
+ ########
+ # Solaris:
+ #
+ # test1 : test1.o ../libobjc-thread.a
+ # gcc -g -o test1 test1.o ../libobjc-thread.a -lthread
+
+ ########
+ # Linux:
+ #
+ # test1 : test1.o ../libobjc-thread.a
+ # gcc -g -o test1 test1.o ../libobjc-thread.a -lieee
+
+ ########
+ # Others:
+ #
+ test1 : test1.o ../libobjc-thread.a
+ gcc -g -o test1 test1.o ../libobjc-thread.a
+
+ test1.o : test1.m
+ gcc -DOBJC_THREAD_SAFE -g -I../.. -o test1.o -c test1.m
+
+ ########
+
+ clean:
+ rm -f *.o test1
+
+ test: test1
+ time test1
+ #
+
+
+
+
+
+
+
+
+
diff -rc2P objc/thread-test/test1.m objc-threaded/thread-test/test1.m
*** objc/thread-test/test1.m Wed Dec 31 19:00:00 1969
--- objc-threaded/thread-test/test1.m Sun Jan 21 19:46:28 1996
***************
*** 0 ****
--- 1,160 ----
+ //
+
+ #include <stdio.h>
+ #include <stdarg.h>
+ #include <objc/Object.h>
+ #include <objc/thread.h>
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ @interface NSLocking : Object
+ {
+ _objc_mutex_t mutex;
+ }
+
+ - init;
+ - free;
+ - (void)lock;
+ - (void)unlock;
+
+ @end
+
+ @implementation NSLocking
+
+ - init
+ {
+ [super init];
+
+ mutex = objc_mutex_allocate();
+ return self;
+ }
+
+ - free
+ {
+ objc_mutex_deallocate(mutex);
+ return [super free];
+ }
+
+ - (void)lock
+ {
+ objc_mutex_lock(mutex);
+ }
+
+ - (void)unlock
+ {
+ objc_mutex_lock(mutex);
+ }
+
+ @end
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ @interface Fruit : Object
+ {
+ int m_refs;
+ const char *m_name;
+ volatile int m_done;
+ }
+
+ /* Obtaining attributes intrinsic to the protocol */
+
+ - init;
+ - free;
+ - (const char *)name;
+ - set_name: (const char *)name;
+ - loop: (void *)arg;
+ - (int)bogus: (int)n;
+ - wait;
+
+
+ @end
+
+ @implementation Fruit
+
+ - init
+ {
+ [super init];
+ m_refs = 1;
+ m_name = "<no name>";
+ m_done = 0;
+ return self;
+ }
+
+ - free
+ {
+ printf("[%s free, refs: %d]\n", m_name, m_refs);
+ return [super free];
+ }
+
+ - (const char *)name
+ {
+ return m_name;
+ }
+
+ - set_name: (const char *)name
+ {
+ m_name = name;
+ return self;
+ }
+
+ - loop: (void *)arg
+ {
+ int i;
+
+ printf("%s loop start\n", m_name);
+ fflush(stdout);
+ for (i = 0; i < 100000;) {
+ i = [self bogus: i];
+ if (i % 10000 == 1)
+ printf("%s loop: %d\n", m_name, i);
+ }
+ printf("%s loop done\n", m_name);
+ m_done = 1;
+
+ return self;
+ }
+
+ - (int)bogus: (int)n
+ {
+ return n + 1;
+ }
+
+ - wait
+ {
+ while (!m_done)
+ ;
+
+ return self;
+ }
+
+ @end
+
+
+ int main(int argc, char **argv)
+ {
+ id f1, f2, f3;
+ id (*imp)(id,SEL,id);
+
+ printf("Main:\n");
+
+ f1 = [[Fruit new] set_name: "f1"];
+ f2 = [[Fruit new] set_name: "f2"];
+ f3 = [[Fruit new] set_name: "f3"];
+
+ printf("Inside the main body.\n");
+ objc_thread_detach(@selector(loop:), f1, NULL);
+ objc_thread_detach(@selector(loop:), f2, NULL);
+
+ [f3 loop: NULL];
+
+ [f1 wait];
+ [f2 wait];
+
+ [f1 free];
+ [f2 free];
+ [f3 free];
+
+ printf("Done:\n");
+
+ return 0;
+ }
diff -rc2P objc/thread-win32.c objc-threaded/thread-win32.c
*** objc/thread-win32.c Wed Dec 31 19:00:00 1969
--- objc-threaded/thread-win32.c Mon Jan 22 11:55:50 1996
***************
*** 0 ****
--- 1,333 ----
+ /* GNU Objective C Runtime Thread Interface - Win32 Implementation
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Author: Galen C. Hunt (gchunt@cs.rochester.edu)
+
+ This file is included into thread.c
+
+ This file is part of GNU CC.
+
+ GNU CC is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2, or (at your option) any later version.
+
+ GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU CC; see the file COPYING. If not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, 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 -rc2P objc/thread.c objc-threaded/thread.c
*** objc/thread.c Wed Dec 31 19:00:00 1969
--- objc-threaded/thread.c Fri Jan 26 14:40:09 1996
***************
*** 0 ****
--- 1,132 ----
+ /* GNU Objective C Runtime Thread Interface
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Author: 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, 675 Mass Ave, Cambridge, MA 02139, 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 -rc2P objc/thread.h objc-threaded/thread.h
*** objc/thread.h Wed Dec 31 19:00:00 1969
--- objc-threaded/thread.h Sun Jan 21 19:37:01 1996
***************
*** 0 ****
--- 1,68 ----
+ /* Thread and mutex controls for Objective C.
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+ AUTHOR: 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, 675 Mass Ave, Cambridge, MA 02139, 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 */