mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-25 09:41:15 +00:00
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@1475 72102866-910b-0410-8b05-ffd578937521
4040 lines
127 KiB
Diff
4040 lines
127 KiB
Diff
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 */
|