14fee23f9SmrgThis file describes in little detail the modifications to the 24fee23f9SmrgObjective-C runtime needed to make it thread safe. 34fee23f9Smrg 44fee23f9SmrgFirst off, kudos to Galen Hunt who is the author of this great work. 54fee23f9Smrg 64fee23f9SmrgIf you have an comments or just want to know where to 74fee23f9Smrgsend me money to express your undying gratitude for threading the 84fee23f9SmrgObjective-C runtime you can reach Galen at: 94fee23f9Smrg 104fee23f9Smrg gchunt@cs.rochester.edu 114fee23f9Smrg 124fee23f9SmrgAny questions, comments, bug reports, etc. should send email either to the 134fee23f9SmrgGCC bug account or to: 144fee23f9Smrg 154fee23f9Smrg Scott Christley <scottc@net-community.com> 164fee23f9Smrg 174fee23f9Smrg* Sarray Threading: 184fee23f9Smrg 194fee23f9SmrgThe most critical component of the Objective-C runtime is the sparse array 204fee23f9Smrgstructure (sarray). Sarrays store object selectors and implementations. 214fee23f9SmrgFollowing in the tradition of the Objective-C runtime, my threading 224fee23f9Smrgsupport assumes that fast message dispatching is far more important 234fee23f9Smrgthan *ANY* and *ALL* other operations. The message dispatching thus 244fee23f9Smrguses *NO* locks on any kind. In fact, if you look in sarray.h, you 254fee23f9Smrgwill notice that the message dispatching has not been modified. 264fee23f9SmrgInstead, I have modified the sarray management functions so that all 274fee23f9Smrgupdates to the sarray data structure can be made in parallel will 284fee23f9Smrgmessage dispatching. 294fee23f9Smrg 304fee23f9SmrgTo support concurrent message dispatching, no dynamically allocated 314fee23f9Smrgsarray data structures are freed while more than one thread is 324fee23f9Smrgoperational. Sarray data structures that are no longer in use are 334fee23f9Smrgkept in a linked list of garbage and are released whenever the program 344fee23f9Smrgis operating with a single thread. The programmer can also flush the 354fee23f9Smrggarbage list by calling sarray_remove_garbage when the programmer can 364fee23f9Smrgensure that no message dispatching is taking place concurrently. The 374fee23f9Smrgamount of un-reclaimed sarray garbage should normally be extremely 384fee23f9Smrgsmall in a real program as sarray structures are freed only when using 394fee23f9Smrgthe "poseAs" functionality and early in program initialization, which 404fee23f9Smrgnormally occurs while the program is single threaded. 414fee23f9Smrg 424fee23f9Smrg****************************************************************************** 434fee23f9Smrg* Static Variables: 444fee23f9Smrg 454fee23f9SmrgThe following variables are either statically or globally defined. This list 464fee23f9Smrgdoes not include variables which are internal to implementation dependent 474fee23f9Smrgversions of thread-*.c. 484fee23f9Smrg 494fee23f9SmrgThe following threading designations are used: 504fee23f9Smrg SAFE : Implicitly thread safe. 514fee23f9Smrg SINGLE : Must only be used in single thread mode. 524fee23f9Smrg MUTEX : Protected by single global mutex objc_runtime_mutex. 534fee23f9Smrg UNUSED : Not used in the runtime. 544fee23f9Smrg 554fee23f9SmrgVariable Name: Usage: Defined: Also used in: 564fee23f9Smrg=========================== ====== ============ ===================== 574fee23f9Smrg__objc_class_hash MUTEX class.c 584fee23f9Smrg__objc_class_links_resolved UNUSED class.c runtime.h 594fee23f9Smrg__objc_class_number MUTEX class.c 604fee23f9Smrg__objc_dangling_categories UNUSED init.c 614fee23f9Smrg__objc_module_list MUTEX init.c 624fee23f9Smrg__objc_selector_array MUTEX selector.c 634fee23f9Smrg__objc_selector_hash MUTEX selector.c 644fee23f9Smrg__objc_selector_max_index MUTEX selector.c sendmsg.c runtime.h 654fee23f9Smrg__objc_selector_names MUTEX selector.c 664fee23f9Smrg__objc_thread_exit_status SAFE thread.c 674fee23f9Smrg__objc_uninstalled_dtable MUTEX sendmsg.c selector.c 684fee23f9Smrg_objc_load_callback SAFE init.c objc-api.h 694fee23f9Smrg_objc_lookup_class SAFE class.c objc-api.h 704fee23f9Smrg_objc_object_alloc SINGLE objects.c objc-api.h 714fee23f9Smrg_objc_object_copy SINGLE objects.c objc-api.h 724fee23f9Smrg_objc_object_dispose SINGLE objects.c objc-api.h 734fee23f9Smrgfrwd_sel SAFE2 sendmsg.c 744fee23f9Smrgidxsize MUTEX sarray.c sendmsg.c sarray.h 754fee23f9Smrginitialize_sel SAFE2 sendmsg.c 764fee23f9Smrgnarrays MUTEX sarray.c sendmsg.c sarray.h 774fee23f9Smrgnbuckets MUTEX sarray.c sendmsg.c sarray.h 784fee23f9Smrgnindices MUTEX sarray.c sarray.h 794fee23f9Smrgprevious_constructors SAFE1 init.c 804fee23f9Smrgproto_class SAFE1 init.c 814fee23f9Smrgunclaimed_categories MUTEX init.c 824fee23f9Smrgunclaimed_proto_list MUTEX init.c 834fee23f9Smrguninitialized_statics MUTEX init.c 844fee23f9Smrg 854fee23f9SmrgNotes: 864fee23f9Smrg1) Initialized once in unithread mode. 874fee23f9Smrg2) Initialized value will always be same, guaranteed by lock on selector 884fee23f9Smrg hash table. 894fee23f9Smrg 904fee23f9Smrg 914fee23f9Smrg****************************************************************************** 924fee23f9Smrg* Frontend/Backend design: 934fee23f9Smrg 944fee23f9SmrgThe design of the Objective-C runtime thread and mutex functions utilizes a 954fee23f9Smrgfrontend/backend implementation. 964fee23f9Smrg 974fee23f9SmrgThe frontend, as characterized by the files thr.h and thr.c, is a set 984fee23f9Smrgof platform independent structures and functions which represent the 9948fb7bfaSmrguser interface. For example, objc_mutex_lock(). Objective-C programs 10048fb7bfaSmrgshould use these structures and functions for their thread and mutex 10148fb7bfaSmrgwork if they wish to maintain a high degree of portability across 10248fb7bfaSmrgplatforms. 1034fee23f9Smrg 10448fb7bfaSmrgThe backend is currently GCC's gthread code (gthr.h and related). For 10548fb7bfaSmrgexample, __gthread_objc_mutex_lock(). The thread system is 10648fb7bfaSmrgautomatically configured when GCC is configured. On most platforms 10748fb7bfaSmrgthis thread backend is able to automatically switch to non-multi-threaded 10848fb7bfaSmrgmode if the threading library is not linked in. 1094fee23f9Smrg 11048fb7bfaSmrgIf you want to compile libobjc standalone, then you would need to modify 111*f9a78e0eSmrgthe configure.ac and makefiles for it and you need to import the 11248fb7bfaSmrggthread code from GCC. 1134fee23f9Smrg 1144fee23f9Smrg****************************************************************************** 1154fee23f9Smrg* Threads: 1164fee23f9Smrg 1174fee23f9SmrgThe thread system attempts to create multiple threads using whatever 1184fee23f9Smrgoperating system or library thread support is available. It does 1194fee23f9Smrgassume that all system functions are thread safe. Notably this means 1204fee23f9Smrgthat the system implementation of malloc and free must be thread safe. 1214fee23f9SmrgIf a system has multiple processors, the threads are configured for 1224fee23f9Smrgfull parallel processing. 1234fee23f9Smrg 1244fee23f9Smrg* Backend initialization functions 1254fee23f9Smrg 1264fee23f9Smrg__objc_init_thread_system(void), int 1274fee23f9Smrg Initialize the thread subsystem. Called once by __objc_exec_class. 1284fee23f9Smrg Return -1 if error otherwise return 0. 1294fee23f9Smrg 1304fee23f9Smrg__objc_close_thread_system(void), int 1314fee23f9Smrg Closes the thread subsystem, not currently guaranteed to be called. 1324fee23f9Smrg Return -1 if error otherwise return 0. 1334fee23f9Smrg 1344fee23f9Smrg***** 1354fee23f9Smrg* Frontend thread functions 1364fee23f9Smrg* User programs should use these functions. 1374fee23f9Smrg 1384fee23f9Smrgobjc_thread_detach(SEL selector, id object, id argument), objc_thread_t 1394fee23f9Smrg Creates and detaches a new thread. The new thread starts by 1404fee23f9Smrg sending the given selector with a single argument to the 1414fee23f9Smrg given object. 1424fee23f9Smrg 1434fee23f9Smrgobjc_thread_set_priority(int priority), int 1444fee23f9Smrg Sets a thread's relative priority within the program. Valid 1454fee23f9Smrg options are: 1464fee23f9Smrg 1474fee23f9Smrg OBJC_THREAD_INTERACTIVE_PRIORITY 1484fee23f9Smrg OBJC_THREAD_BACKGROUND_PRIORITY 1494fee23f9Smrg OBJC_THREAD_LOW_PRIORITY 1504fee23f9Smrg 1514fee23f9Smrgobjc_thread_get_priority(void), int 1524fee23f9Smrg Query a thread's priority. 1534fee23f9Smrg 1544fee23f9Smrgobjc_thread_yield(void), void 1554fee23f9Smrg Yields processor to another thread with equal or higher 1564fee23f9Smrg priority. It is up to the system scheduler to determine if 1574fee23f9Smrg the processor is taken or not. 1584fee23f9Smrg 1594fee23f9Smrgobjc_thread_exit(void), int 1604fee23f9Smrg Terminates a thread. If this is the last thread executing 1614fee23f9Smrg then the program will terminate. 1624fee23f9Smrg 1634fee23f9Smrgobjc_thread_id(void), int 1644fee23f9Smrg Returns the current thread's id. 1654fee23f9Smrg 1664fee23f9Smrgobjc_thread_set_data(void *value), int 1674fee23f9Smrg Set a pointer to the thread's local storage. Local storage is 1684fee23f9Smrg thread specific. 1694fee23f9Smrg 1704fee23f9Smrgobjc_thread_get_data(void), void * 1714fee23f9Smrg Returns the pointer to the thread's local storage. 1724fee23f9Smrg 1734fee23f9Smrg***** 1744fee23f9Smrg* Backend thread functions 1754fee23f9Smrg* User programs should *NOT* directly call these functions. 1764fee23f9Smrg 17748fb7bfaSmrg__gthr_objc_thread_detach(void (*func)(void *arg), void *arg), objc_thread_t 1784fee23f9Smrg Spawns a new thread executing func, called by objc_thread_detach. 1794fee23f9Smrg Return NULL if error otherwise return thread id. 1804fee23f9Smrg 18148fb7bfaSmrg__gthr_objc_thread_set_priority(int priority), int 1824fee23f9Smrg Set the thread's priority, called by objc_thread_set_priority. 1834fee23f9Smrg Return -1 if error otherwise return 0. 1844fee23f9Smrg 18548fb7bfaSmrg__gthr_objc_thread_get_priority(void), int 1864fee23f9Smrg Query a thread's priority, called by objc_thread_get_priority. 1874fee23f9Smrg Return -1 if error otherwise return the priority. 1884fee23f9Smrg 18948fb7bfaSmrg__gthr_objc_thread_yield(void), void 1904fee23f9Smrg Yields the processor, called by objc_thread_yield. 1914fee23f9Smrg 19248fb7bfaSmrg__gthr_objc_thread_exit(void), int 1934fee23f9Smrg Terminates the thread, called by objc_thread_exit. 1944fee23f9Smrg Return -1 if error otherwise function does not return. 1954fee23f9Smrg 19648fb7bfaSmrg__gthr_objc_thread_id(void), objc_thread_t 1974fee23f9Smrg Returns the current thread's id, called by objc_thread_id. 1984fee23f9Smrg Return -1 if error otherwise return thread id. 1994fee23f9Smrg 20048fb7bfaSmrg__gthr_objc_thread_set_data(void *value), int 2014fee23f9Smrg Set pointer for thread local storage, called by objc_thread_set_data. 2024fee23f9Smrg Returns -1 if error otherwise return 0. 2034fee23f9Smrg 20448fb7bfaSmrg__gthr_objc_thread_get_data(void), void * 2054fee23f9Smrg Returns the pointer to the thread's local storage. 2064fee23f9Smrg Returns NULL if error, called by objc_thread_get_data. 2074fee23f9Smrg 2084fee23f9Smrg 2094fee23f9Smrg****************************************************************************** 2104fee23f9Smrg* Mutexes: 2114fee23f9Smrg 2124fee23f9SmrgMutexes can be locked recursively. Each locked mutex remembers 2134fee23f9Smrgits owner (by thread id) and how many times it has been locked. The 2144fee23f9Smrglast unlock on a mutex removes the system lock and allows other 2154fee23f9Smrgthreads to access the mutex. 2164fee23f9Smrg 2174fee23f9Smrg***** 2184fee23f9Smrg* Frontend mutex functions 2194fee23f9Smrg* User programs should use these functions. 2204fee23f9Smrg 2214fee23f9Smrgobjc_mutex_allocate(void), objc_mutex_t 2224fee23f9Smrg Allocates a new mutex. Mutex is initially unlocked. 2234fee23f9Smrg Return NULL if error otherwise return mutex pointer. 2244fee23f9Smrg 2254fee23f9Smrgobjc_mutex_deallocate(objc_mutex_t mutex), int 2264fee23f9Smrg Free a mutex. Before freeing the mutex, makes sure that no 2274fee23f9Smrg one else is using it. 2284fee23f9Smrg Return -1 if error otherwise return 0. 2294fee23f9Smrg 2304fee23f9Smrgobjc_mutex_lock(objc_mutex_t mutex), int 2314fee23f9Smrg Locks a mutex. As mentioned earlier, the same thread may call 2324fee23f9Smrg this routine repeatedly. 2334fee23f9Smrg Return -1 if error otherwise return 0. 2344fee23f9Smrg 2354fee23f9Smrgobjc_mutex_trylock(objc_mutex_t mutex), int 2364fee23f9Smrg Attempts to lock a mutex. If lock on mutex can be acquired 2374fee23f9Smrg then function operates exactly as objc_mutex_lock. 2384fee23f9Smrg Return -1 if failed to acquire lock otherwise return 0. 2394fee23f9Smrg 2404fee23f9Smrgobjc_mutex_unlock(objc_mutex_t mutex), int 2414fee23f9Smrg Unlocks the mutex by one level. Other threads may not acquire 2424fee23f9Smrg the mutex until this thread has released all locks on it. 2434fee23f9Smrg Return -1 if error otherwise return 0. 2444fee23f9Smrg 2454fee23f9Smrg***** 2464fee23f9Smrg* Backend mutex functions 2474fee23f9Smrg* User programs should *NOT* directly call these functions. 2484fee23f9Smrg 24948fb7bfaSmrg__gthr_objc_mutex_allocate(objc_mutex_t mutex), int 2504fee23f9Smrg Allocates a new mutex, called by objc_mutex_allocate. 2514fee23f9Smrg Return -1 if error otherwise return 0. 2524fee23f9Smrg 25348fb7bfaSmrg__gthr_objc_mutex_deallocate(objc_mutex_t mutex), int 2544fee23f9Smrg Free a mutex, called by objc_mutex_deallocate. 2554fee23f9Smrg Return -1 if error otherwise return 0. 2564fee23f9Smrg 25748fb7bfaSmrg__gthr_objc_mutex_lock(objc_mutex_t mutex), int 2584fee23f9Smrg Locks a mutex, called by objc_mutex_lock. 2594fee23f9Smrg Return -1 if error otherwise return 0. 2604fee23f9Smrg 26148fb7bfaSmrg__gthr_objc_mutex_trylock(objc_mutex_t mutex), int 2624fee23f9Smrg Attempts to lock a mutex, called by objc_mutex_trylock. 2634fee23f9Smrg Return -1 if failed to acquire lock or error otherwise return 0. 2644fee23f9Smrg 26548fb7bfaSmrg__gthr_objc_mutex_unlock(objc_mutex_t mutex), int 2664fee23f9Smrg Unlocks the mutex, called by objc_mutex_unlock. 2674fee23f9Smrg Return -1 if error otherwise return 0. 2684fee23f9Smrg 2694fee23f9Smrg****************************************************************************** 2704fee23f9Smrg* Condition Mutexes: 2714fee23f9Smrg 2724fee23f9SmrgMutexes can be locked recursively. Each locked mutex remembers 2734fee23f9Smrgits owner (by thread id) and how many times it has been locked. The 2744fee23f9Smrglast unlock on a mutex removes the system lock and allows other 2754fee23f9Smrgthreads to access the mutex. 2764fee23f9Smrg 2774fee23f9Smrg* 2784fee23f9Smrg* Frontend condition mutex functions 2794fee23f9Smrg* User programs should use these functions. 2804fee23f9Smrg* 2814fee23f9Smrg 2824fee23f9Smrgobjc_condition_allocate(void), objc_condition_t 2834fee23f9Smrg Allocate a condition mutex. 2844fee23f9Smrg Return NULL if error otherwise return condition pointer. 2854fee23f9Smrg 2864fee23f9Smrgobjc_condition_deallocate(objc_condition_t condition), int 2874fee23f9Smrg Deallocate a condition. Note that this includes an implicit 2884fee23f9Smrg condition_broadcast to insure that waiting threads have the 2894fee23f9Smrg opportunity to wake. It is legal to dealloc a condition only 2904fee23f9Smrg if no other thread is/will be using it. Does NOT check for 2914fee23f9Smrg other threads waiting but just wakes them up. 2924fee23f9Smrg Return -1 if error otherwise return 0. 2934fee23f9Smrg 2944fee23f9Smrgobjc_condition_wait(objc_condition_t condition, objc_mutex_t mutex), int 2954fee23f9Smrg Wait on the condition unlocking the mutex until objc_condition_signal() 2964fee23f9Smrg or objc_condition_broadcast() are called for the same condition. The 2974fee23f9Smrg given mutex *must* have the depth 1 so that it can be unlocked 2984fee23f9Smrg here, for someone else can lock it and signal/broadcast the condition. 2994fee23f9Smrg The mutex is used to lock access to the shared data that make up the 3004fee23f9Smrg "condition" predicate. 3014fee23f9Smrg Return -1 if error otherwise return 0. 3024fee23f9Smrg 3034fee23f9Smrgobjc_condition_broadcast(objc_condition_t condition), int 3044fee23f9Smrg Wake up all threads waiting on this condition. It is recommended that 3054fee23f9Smrg the called would lock the same mutex as the threads in 3064fee23f9Smrg objc_condition_wait before changing the "condition predicate" 3074fee23f9Smrg and make this call and unlock it right away after this call. 3084fee23f9Smrg Return -1 if error otherwise return 0. 3094fee23f9Smrg 3104fee23f9Smrgobjc_condition_signal(objc_condition_t condition), int 3114fee23f9Smrg Wake up one thread waiting on this condition. 3124fee23f9Smrg Return -1 if error otherwise return 0. 3134fee23f9Smrg 3144fee23f9Smrg* 3154fee23f9Smrg* Backend condition mutex functions 3164fee23f9Smrg* User programs should *NOT* directly call these functions. 3174fee23f9Smrg* 3184fee23f9Smrg 31948fb7bfaSmrg__gthr_objc_condition_allocate(objc_condition_t condition), int 3204fee23f9Smrg Allocate a condition mutex, called by objc_condition_allocate. 3214fee23f9Smrg Return -1 if error otherwise return 0. 3224fee23f9Smrg 32348fb7bfaSmrg__gthr_objc_condition_deallocate(objc_condition_t condition), int 3244fee23f9Smrg Deallocate a condition, called by objc_condition_deallocate. 3254fee23f9Smrg Return -1 if error otherwise return 0. 3264fee23f9Smrg 32748fb7bfaSmrg__gthr_objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex), int 3284fee23f9Smrg Wait on the condition, called by objc_condition_wait. 3294fee23f9Smrg Return -1 if error otherwise return 0 when condition is met. 3304fee23f9Smrg 33148fb7bfaSmrg__gthr_objc_condition_broadcast(objc_condition_t condition), int 3324fee23f9Smrg Wake up all threads waiting on this condition. 3334fee23f9Smrg Called by objc_condition_broadcast. 3344fee23f9Smrg Return -1 if error otherwise return 0. 3354fee23f9Smrg 33648fb7bfaSmrg__gthr_objc_condition_signal(objc_condition_t condition), int 3374fee23f9Smrg Wake up one thread waiting on this condition. 3384fee23f9Smrg Called by objc_condition_signal. 3394fee23f9Smrg Return -1 if error otherwise return 0. 340