diff options
-rw-r--r-- | winsup/cygwin/ChangeLog | 89 | ||||
-rw-r--r-- | winsup/cygwin/pthread.cc | 26 | ||||
-rw-r--r-- | winsup/cygwin/thread.cc | 359 | ||||
-rw-r--r-- | winsup/cygwin/thread.h | 157 |
4 files changed, 365 insertions, 266 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index cbd07744088..66dc9c07f84 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,5 +1,94 @@ 2002-09-21 Robert Collins <rbtcollins@hotmail.com> + * pthread.cc: Use class::call for converted pthread and semaphore + calls. + * thread.cc: Convert various __pthread_call and __sem_call to + pthread::call and sem::call throughout. + * pthread.h (__pthread_cancel): Convert to pthread::cancel. + (__pthread_join): Convert to pthread::join. + (__pthread_detach): Convert to pthread::detach. + (__pthread_create): Convert to pthread::create. + (__pthread_once): Convert to pthread::once. + (__pthread_atfork): Convert to pthread::atfork. + (__pthread_suspend): Convert to pthread::suspend. + (__pthread_continue): Convert to pthread::resume. + (__sem_init): Convert to semaphore::init. + (__sem_destroy): Convert to semaphore::destroy. + (__sem_wait): Convert to semaphore::wait. + (__sem_trywait): Convert to semaphore::trywait. + (__sem_post): Convert to semaphore::post. + +2002-09-21 Robert Collins <rbtcollins@hotmail.com> + + * thread.cc: Finish the removal of the separate pthread_key + destructor list. + Remove all pthread_key_destructor and pthread_key_destructor_list + references throughout. + (pthread::exit): Call the new pthread_key interface to activate + destructors. + (pthread_key::keys): Change into a list. + (pthread_key::saveAKey): New method, used via forEach. + (pthread_key::restoreAKey): Ditto. + (pthread_key::destroyAKey): Ditto. + (pthread_key::fixup_before_fork): Use the List::forEach functionality. + (pthread_key::fixup_after_fork): Ditto. + (pthread_key::runAllDestructors): New method implementation. + (pthread_key::pthread_key): Use List::Insert rather than custom list + code. + (pthread_key::~pthread_key): Use List::Remove for the same reason. + * thread.h: Remove all pthread_key_destructor and + pthread_key_destructor_list references throughout. + (List): Move the interface above pthread_key in the header. + Use atomic operations during insert and delete. + (List::forEach): A generic interface for doing something on each node. + (pthread_key::runAllDestructors): New method, run all destructors. + (pthread_key::fork_buf): Make private. + (pthread_key::run_destructor): Ditto. + (pthread_key::saveAKey): New method for clearer source. + (pthread_key::restoreAKey): Ditto. + (pthread_key::destroyAKey): Ditto. + (MTinterface::destructors): Remove. + +2002-09-21 Robert Collins <rbtcollins@hotmail.com> + + * thread.cc: Partial refactoring of pthread_key destructor + handling. Loosely based on Thomas Pfaff's work. + (pthread_key_destructor_list::Insert): Remove. + (pthread_key_destructor_list::Pop): Remove. + (pthread_key_destructor_list::IterateNull): Call the key's + run_destructor method. + (pthread_key::pthread_key): Initialize new member. + (pthread_key::get): Mark as const for correctness. + (pthread_key::run_destructor): Implement. + * thread.h (pthread_key::get): Mark as const for correctness. + (pthread_key::run_destructor): Declare. + (List): New template class that implements a generic list. + (pthread_key_destructor_list): Inherit from List, and remove + now duplicate functions. + +2002-09-21 Robert Collins <rbtcollins@hotmail.com> + + * thread.cc: Change verifyable_object_isvalid calls with + PTHREAD_CONDATTR_MAGIC, PTHREAD_MUTEXATTR_MAGIC, PTHREAD_COND_MAGIC, + SEM_MAGIC to objecttype::isGoodObject() calls throughout. + (pthread_condattr::isGoodObject): Implement. + (pthread_mutex::isGoodInitializer): Implement. + (pthread_mutex::isGoodInitializerOrObject): Minor bugfix in the + check for verifyable_object_isvalid result. + (pthread_mutexattr::isGoodObject): Implement. + (pthread_cond::isGoodObject): Ditto. + (pthread_cond::isGoodInitializer): Ditto. + (pthread_cond::isGoodInitializerOrObject): Ditto. + (semaphore::isGoodObject): Ditto. + * thread.h (pthread_mutex::isGoodInitializer): Declare. + (pthread_condattr::isGoodObject): Ditto. + (pthread_cond::isGoodObject): Const correctness. + (pthread_cond::isGoodInitializer): Declare. + (pthread_cond::isGoodInitializerOrObject): Ditto. + (semaphore::isGoodObject): Const correctness. + +2002-09-21 Robert Collins <rbtcollins@hotmail.com> + * thread.cc: Change verifyable_object_isvalid calls with PTHREAD_MUTEX_MAGIC and PTHREAD_KEY_MAGIC and PTHREAD_ATTR_MAGIC to ::isGoodObject() calls throughout. diff --git a/winsup/cygwin/pthread.cc b/winsup/cygwin/pthread.cc index 90eb20f2573..810fd1f2005 100644 --- a/winsup/cygwin/pthread.cc +++ b/winsup/cygwin/pthread.cc @@ -21,19 +21,19 @@ int pthread_create (pthread_t * thread, const pthread_attr_t * attr, void *(*start_routine) (void *), void *arg) { - return __pthread_create (thread, attr, start_routine, arg); + return pthread::create (thread, attr, start_routine, arg); } int pthread_once (pthread_once_t * once_control, void (*init_routine) (void)) { - return __pthread_once (once_control, init_routine); + return pthread::once (once_control, init_routine); } int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) { - return __pthread_atfork(prepare, parent, child); + return pthread::atfork(prepare, parent, child); } int @@ -147,13 +147,13 @@ pthread_exit (void *value_ptr) int pthread_join (pthread_t thread, void **return_val) { - return __pthread_join (&thread, (void **) return_val); + return pthread::join (&thread, (void **) return_val); } int pthread_detach (pthread_t thread) { - return __pthread_detach (&thread); + return pthread::detach (&thread); } @@ -161,14 +161,14 @@ pthread_detach (pthread_t thread) int pthread_suspend (pthread_t thread) { - return __pthread_suspend (&thread); + return pthread::suspend (&thread); } /* same */ int pthread_continue (pthread_t thread) { - return __pthread_continue (&thread); + return pthread::resume (&thread); } unsigned long @@ -425,7 +425,7 @@ pthread_setschedparam (pthread_t thread, int policy, int pthread_cancel (pthread_t thread) { - return __pthread_cancel (thread); + return pthread::cancel (thread); } int @@ -462,31 +462,31 @@ _pthread_cleanup_pop (int execute) int sem_init (sem_t * sem, int pshared, unsigned int value) { - return __sem_init (sem, pshared, value); + return semaphore::init (sem, pshared, value); } int sem_destroy (sem_t * sem) { - return __sem_destroy (sem); + return semaphore::destroy (sem); } int sem_wait (sem_t * sem) { - return __sem_wait (sem); + return semaphore::wait (sem); } int sem_trywait (sem_t * sem) { - return __sem_trywait (sem); + return semaphore::trywait (sem); } int sem_post (sem_t * sem) { - return __sem_post (sem); + return semaphore::post (sem); } } diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc index d54cc689b0d..e5e313044aa 100644 --- a/winsup/cygwin/thread.cc +++ b/winsup/cygwin/thread.cc @@ -46,92 +46,6 @@ details. */ extern int threadsafe; -/*pthread_key_destructor_list class: to-be threadsafe single linked list - *FIXME: Put me in a dedicated file, or a least a tools area ! - */ - -pthread_key_destructor * -pthread_key_destructor::InsertAfter (pthread_key_destructor *node) -{ - pthread_key_destructor *temp = next; - next = node; - return temp; -} - -pthread_key_destructor * -pthread_key_destructor::UnlinkNext () -{ - pthread_key_destructor *temp = next; - if (next) - next = next->Next (); - return temp; -} - -pthread_key_destructor * -pthread_key_destructor::Next () -{ - return next; -} - -void -pthread_key_destructor_list::Insert (pthread_key_destructor *node) -{ - if (!node) - return; - head = node->InsertAfter (head); - if (!head) - head = node; /*first node special case */ -} - - /*remove a given dataitem, wherever in the list it is */ -pthread_key_destructor * -pthread_key_destructor_list::Remove (pthread_key *key) -{ - if (!key) - return NULL; - if (!head) - return NULL; - if (key == head->key) - return Pop (); - pthread_key_destructor *temp = head; - while (temp && temp->Next () && !(key == temp->Next ()->key)) - { - temp = temp->Next (); - } - if (temp) - return temp->UnlinkNext (); - return NULL; -} - - /*get the first item and remove at the same time */ -pthread_key_destructor * -pthread_key_destructor_list::Pop () -{ - pthread_key_destructor *temp = head; - head = head->Next (); - return temp; -} - -pthread_key_destructor:: -pthread_key_destructor (void (*thedestructor) (void *), pthread_key *key) -{ - destructor = thedestructor; - next = NULL; - this->key = key; -} - -void -pthread_key_destructor_list::IterateNull () -{ - pthread_key_destructor *temp = head; - while (temp) - { - temp->destructor ((temp->key)->get ()); - temp = temp->Next (); - } -} - - #define MT_INTERFACE user_data->threadinterface struct _reent * @@ -457,7 +371,7 @@ pthread::exit (void *value_ptr) // run cleanup handlers pop_all_cleanup_handlers (); - MT_INTERFACE->destructors.IterateNull (); + pthread_key::runAllDestructors (); mutex.Lock (); // cleanup if thread is in detached state and not joined @@ -822,6 +736,14 @@ pthread_attr::~pthread_attr () { } +bool +pthread_condattr::isGoodObject (pthread_condattr_t const *attr) +{ + if (verifyable_object_isvalid (attr, PTHREAD_CONDATTR_MAGIC) != VALID_OBJECT) + return false; + return true; +} + pthread_condattr::pthread_condattr ():verifyable_object (PTHREAD_CONDATTR_MAGIC), shared (PTHREAD_PROCESS_PRIVATE) { @@ -1012,30 +934,42 @@ pthread_cond::fixup_after_fork () /* pthread_key */ /* static members */ -pthread_key *pthread_key::keys = NULL; +List<pthread_key> pthread_key::keys; + +void +pthread_key::saveAKey (pthread_key *key) +{ + key->saveKeyToBuffer (); +} void pthread_key::fixup_before_fork () { - pthread_key *key = keys; - debug_printf ("keys is %x",keys); - while (key) - { - key->saveKeyToBuffer (); - key = key->next; - } + keys.forEach (saveAKey); +} + +void +pthread_key::restoreAKey (pthread_key *key) +{ + key->recreateKeyFromBuffer (); } void pthread_key::fixup_after_fork () { - pthread_key *key = keys; - debug_printf ("keys is %x",keys); - while (key) - { - key->recreateKeyFromBuffer (); - key = key->next; - } + keys.forEach (restoreAKey); +} + +void +pthread_key::destroyAKey (pthread_key *key) +{ + key->run_destructor (); +} + +void +pthread_key::runAllDestructors () +{ + keys.forEach (destroyAKey); } bool @@ -1048,36 +982,23 @@ pthread_key::isGoodObject (pthread_key_t const *key) /* non-static members */ -pthread_key::pthread_key (void (*destructor) (void *)):verifyable_object (PTHREAD_KEY_MAGIC) +pthread_key::pthread_key (void (*aDestructor) (void *)):verifyable_object (PTHREAD_KEY_MAGIC), destructor (aDestructor) { dwTlsIndex = TlsAlloc (); if (dwTlsIndex == TLS_OUT_OF_INDEXES) magic = 0; - else if (destructor) - { - MT_INTERFACE->destructors. - Insert (new pthread_key_destructor (destructor, this)); - } - /* threadsafe addition is easy */ - next = (pthread_key *) InterlockedExchangePointer (&keys, this); + else + keys.Insert (this); } pthread_key::~pthread_key () { - if (pthread_key_destructor *dest = MT_INTERFACE->destructors.Remove (this)) - delete dest; - TlsFree (dwTlsIndex); - - /* I'm not 100% sure the next bit is threadsafe. I think it is... */ - if (keys == this) - InterlockedExchangePointer (keys, this->next); - else + /* We may need to make the list code lock the list during operations + */ + if (magic != 0) { - pthread_key *tempkey = keys; - while (tempkey->next && tempkey->next != this) - tempkey = tempkey->next; - /* but there may be a race between the loop above and this statement */ - InterlockedExchangePointer (&tempkey->next, this->next); + keys.Remove (this); + TlsFree (dwTlsIndex); } } @@ -1090,7 +1011,7 @@ pthread_key::set (const void *value) } void * -pthread_key::get () +pthread_key::get () const { int savedError = ::GetLastError(); void *result = TlsGetValue (dwTlsIndex); @@ -1113,6 +1034,13 @@ pthread_key::recreateKeyFromBuffer () set (fork_buf); } +void +pthread_key::run_destructor () const +{ + if (destructor) + destructor (get()); +} + /*pshared mutexs: * REMOVED FROM CURRENT. These can be reinstated with the daemon, when all the @@ -1139,17 +1067,25 @@ pthread_key::recreateKeyFromBuffer () /* static members */ bool -pthread_mutex::isGoodObject (pthread_mutex_t const *thread) +pthread_mutex::isGoodObject (pthread_mutex_t const *mutex) { - if (verifyable_object_isvalid (thread, PTHREAD_MUTEX_MAGIC) != VALID_OBJECT) + if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC) != VALID_OBJECT) return false; return true; } bool -pthread_mutex::isGoodInitializerOrObject (pthread_mutex_t const *thread) +pthread_mutex::isGoodInitializer (pthread_mutex_t const *mutex) { - if (verifyable_object_isvalid (thread, PTHREAD_MUTEX_MAGIC, PTHREAD_MUTEX_INITIALIZER) != VALID_OBJECT) + if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC, PTHREAD_MUTEX_INITIALIZER) != VALID_STATIC_OBJECT) + return false; + return true; +} + +bool +pthread_mutex::isGoodInitializerOrObject (pthread_mutex_t const *mutex) +{ + if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC, PTHREAD_MUTEX_INITIALIZER) == INVALID_OBJECT) return false; return true; } @@ -1257,6 +1193,14 @@ pthread_mutex::fixup_after_fork () #endif } +bool +pthread_mutexattr::isGoodObject (pthread_mutexattr_t const * attr) +{ + if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT) + return false; + return true; +} + pthread_mutexattr::pthread_mutexattr ():verifyable_object (PTHREAD_MUTEXATTR_MAGIC), pshared (PTHREAD_PROCESS_PRIVATE), mutextype (PTHREAD_MUTEX_DEFAULT) { @@ -1454,7 +1398,7 @@ pthread::getsequence_np () } int -__pthread_create (pthread_t *thread, const pthread_attr_t *attr, +pthread::create (pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg) { DECLARE_TLS_STORAGE; @@ -1463,7 +1407,7 @@ __pthread_create (pthread_t *thread, const pthread_attr_t *attr, *thread = new pthread (); (*thread)->create (start_routine, attr ? *attr : NULL, arg); - if (!pthread::isGoodObject (thread)) + if (!isGoodObject (thread)) { delete (*thread); *thread = NULL; @@ -1474,7 +1418,7 @@ __pthread_create (pthread_t *thread, const pthread_attr_t *attr, } int -__pthread_once (pthread_once_t *once_control, void (*init_routine) (void)) +pthread::once (pthread_once_t *once_control, void (*init_routine) (void)) { // already done ? if (once_control->state) @@ -1498,9 +1442,9 @@ __pthread_once (pthread_once_t *once_control, void (*init_routine) (void)) } int -__pthread_cancel (pthread_t thread) +pthread::cancel (pthread_t thread) { - if (!pthread::isGoodObject (&thread)) + if (!isGoodObject (&thread)) return ESRCH; return thread->cancel (); @@ -1566,7 +1510,7 @@ pthread::atforkchild (void) *parent and child calls are called in FI-FC order. */ int -__pthread_atfork (void (*prepare)(void), void (*parent)(void), void (*child)(void)) +pthread::atfork (void (*prepare)(void), void (*parent)(void), void (*child)(void)) { callback *prepcb = NULL, *parentcb = NULL, *childcb = NULL; if (prepare) @@ -1782,16 +1726,16 @@ __pthread_attr_destroy (pthread_attr_t *attr) } int -__pthread_join (pthread_t *thread, void **return_val) +pthread::join (pthread_t *thread, void **return_val) { - pthread_t joiner = pthread::self (); + pthread_t joiner = self (); // Initialize return val with NULL if (return_val) *return_val = NULL; /*FIXME: wait on the thread cancellation event as well - we are a cancellation point*/ - if (!pthread::isGoodObject (thread)) + if (!isGoodObject (thread)) return ESRCH; if (__pthread_equal (thread,&joiner)) @@ -1822,9 +1766,9 @@ __pthread_join (pthread_t *thread, void **return_val) } int -__pthread_detach (pthread_t *thread) +pthread::detach (pthread_t *thread) { - if (!pthread::isGoodObject (thread)) + if (!isGoodObject (thread)) return ESRCH; (*thread)->mutex.Lock (); @@ -1853,9 +1797,9 @@ __pthread_detach (pthread_t *thread) } int -__pthread_suspend (pthread_t *thread) +pthread::suspend (pthread_t *thread) { - if (!pthread::isGoodObject (thread)) + if (!isGoodObject (thread)) return ESRCH; if ((*thread)->suspended == false) @@ -1869,9 +1813,9 @@ __pthread_suspend (pthread_t *thread) int -__pthread_continue (pthread_t *thread) +pthread::resume (pthread_t *thread) { - if (!pthread::isGoodObject (thread)) + if (!isGoodObject (thread)) return ESRCH; if ((*thread)->suspended == true) @@ -1986,13 +1930,36 @@ __pthread_getspecific (pthread_key_t key) } /*Thread synchronisation */ +bool +pthread_cond::isGoodObject (pthread_cond_t const *cond) +{ + if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC) != VALID_OBJECT) + return false; + return true; +} + +bool +pthread_cond::isGoodInitializer (pthread_cond_t const *cond) +{ + if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC, PTHREAD_COND_INITIALIZER) != VALID_STATIC_OBJECT) + return false; + return true; +} + +bool +pthread_cond::isGoodInitializerOrObject (pthread_cond_t const *cond) +{ + if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC, PTHREAD_COND_INITIALIZER) == INVALID_OBJECT) + return false; + return true; +} int __pthread_cond_destroy (pthread_cond_t *cond) { - if (check_valid_pointer (cond) && (*cond == PTHREAD_COND_INITIALIZER)) + if (pthread_cond::isGoodInitializer (cond)) return 0; - if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC) != VALID_OBJECT) + if (!pthread_cond::isGoodObject (cond)) return EINVAL; /*reads are atomic */ @@ -2008,15 +1975,15 @@ __pthread_cond_destroy (pthread_cond_t *cond) int __pthread_cond_init (pthread_cond_t *cond, const pthread_condattr_t *attr) { - if (attr && verifyable_object_isvalid (attr, PTHREAD_CONDATTR_MAGIC) != VALID_OBJECT) + if (attr && !pthread_condattr::isGoodObject (attr)) return EINVAL; - if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC, PTHREAD_COND_INITIALIZER) == VALID_OBJECT) + if (pthread_cond::isGoodObject (cond)) return EBUSY; *cond = new pthread_cond (attr ? (*attr) : NULL); - if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC) != VALID_OBJECT) + if (!pthread_cond::isGoodObject (cond)) { delete (*cond); *cond = NULL; @@ -2029,9 +1996,9 @@ __pthread_cond_init (pthread_cond_t *cond, const pthread_condattr_t *attr) int __pthread_cond_broadcast (pthread_cond_t *cond) { - if (*cond == PTHREAD_COND_INITIALIZER) + if (pthread_cond::isGoodInitializer (cond)) __pthread_cond_init (cond, NULL); - if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC) != VALID_OBJECT) + if (!pthread_cond::isGoodObject (cond)) return EINVAL; (*cond)->BroadCast (); @@ -2042,9 +2009,9 @@ __pthread_cond_broadcast (pthread_cond_t *cond) int __pthread_cond_signal (pthread_cond_t *cond) { - if (*cond == PTHREAD_COND_INITIALIZER) + if (pthread_cond::isGoodInitializer (cond)) __pthread_cond_init (cond, NULL); - if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC) != VALID_OBJECT) + if (!pthread_cond::isGoodObject (cond)) return EINVAL; (*cond)->Signal (); @@ -2063,12 +2030,12 @@ __pthread_cond_dowait (pthread_cond_t *cond, pthread_mutex_t *mutex, if (*mutex == PTHREAD_MUTEX_INITIALIZER) __pthread_mutex_init (mutex, NULL); themutex = mutex; - if (*cond == PTHREAD_COND_INITIALIZER) + if (pthread_cond::isGoodInitializer (cond)) __pthread_cond_init (cond, NULL); if (!pthread_mutex::isGoodObject (themutex)) return EINVAL; - if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC) != VALID_OBJECT) + if (!pthread_cond::isGoodObject (cond)) return EINVAL; /*if the cond variable is blocked, then the above timer test maybe wrong. *shrug**/ @@ -2135,8 +2102,9 @@ pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) int __pthread_condattr_init (pthread_condattr_t *condattr) { + /* FIXME: we dereference blindly! */ *condattr = new pthread_condattr; - if (verifyable_object_isvalid (condattr, PTHREAD_CONDATTR_MAGIC) != VALID_OBJECT) + if (!pthread_condattr::isGoodObject (condattr)) { delete (*condattr); *condattr = NULL; @@ -2148,7 +2116,7 @@ __pthread_condattr_init (pthread_condattr_t *condattr) int __pthread_condattr_getpshared (const pthread_condattr_t *attr, int *pshared) { - if (verifyable_object_isvalid (attr, PTHREAD_CONDATTR_MAGIC) != VALID_OBJECT) + if (!pthread_condattr::isGoodObject (attr)) return EINVAL; *pshared = (*attr)->shared; return 0; @@ -2157,7 +2125,7 @@ __pthread_condattr_getpshared (const pthread_condattr_t *attr, int *pshared) int __pthread_condattr_setpshared (pthread_condattr_t *attr, int pshared) { - if (verifyable_object_isvalid (attr, PTHREAD_CONDATTR_MAGIC) != VALID_OBJECT) + if (!pthread_condattr::isGoodObject (attr)) return EINVAL; if ((pshared < 0) || (pshared > 1)) return EINVAL; @@ -2171,7 +2139,7 @@ __pthread_condattr_setpshared (pthread_condattr_t *attr, int pshared) int __pthread_condattr_destroy (pthread_condattr_t *condattr) { - if (verifyable_object_isvalid (condattr, PTHREAD_CONDATTR_MAGIC) != VALID_OBJECT) + if (!pthread_condattr::isGoodObject (condattr)) return EINVAL; delete (*condattr); *condattr = NULL; @@ -2238,10 +2206,11 @@ int __pthread_mutex_init (pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) { - if (attr && verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT || check_valid_pointer (mutex)) + if (attr && !pthread_mutexattr::isGoodObject (attr) || check_valid_pointer (mutex)) return EINVAL; - if (pthread_mutex::isGoodInitializerOrObject (mutex)) + /* FIXME: bugfix: we should check *mutex being a valid address */ + if (pthread_mutex::isGoodObject (mutex)) return EBUSY; *mutex = new pthread_mutex (attr ? (*attr) : NULL); @@ -2259,7 +2228,7 @@ __pthread_mutex_getprioceiling (const pthread_mutex_t *mutex, int *prioceiling) { pthread_mutex_t *themutex = (pthread_mutex_t *) mutex; - if (*mutex == PTHREAD_MUTEX_INITIALIZER) + if (pthread_mutex::isGoodInitializer (mutex)) __pthread_mutex_init ((pthread_mutex_t *) mutex, NULL); if (!pthread_mutex::isGoodObject (themutex)) return EINVAL; @@ -2278,13 +2247,17 @@ int __pthread_mutex_lock (pthread_mutex_t *mutex) { pthread_mutex_t *themutex = mutex; + /* This could be simplified via isGoodInitializerOrObject + and isGoodInitializer, but in a performance critical call like this.... + no. + */ switch (verifyable_object_isvalid (themutex, PTHREAD_MUTEX_MAGIC, PTHREAD_MUTEX_INITIALIZER)) { case INVALID_OBJECT: return EINVAL; break; case VALID_STATIC_OBJECT: - if (*mutex == PTHREAD_MUTEX_INITIALIZER) + if (pthread_mutex::isGoodInitializer (mutex)) { int rv = __pthread_mutex_init (mutex, NULL); if (rv) @@ -2302,7 +2275,7 @@ int __pthread_mutex_trylock (pthread_mutex_t *mutex) { pthread_mutex_t *themutex = mutex; - if (*mutex == PTHREAD_MUTEX_INITIALIZER) + if (pthread_mutex::isGoodInitializer (mutex)) __pthread_mutex_init (mutex, NULL); if (!pthread_mutex::isGoodObject (themutex)) return EINVAL; @@ -2314,7 +2287,7 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) int __pthread_mutex_unlock (pthread_mutex_t *mutex) { - if (*mutex == PTHREAD_MUTEX_INITIALIZER) + if (pthread_mutex::isGoodInitializer (mutex)) __pthread_mutex_init (mutex, NULL); if (!pthread_mutex::isGoodObject (mutex)) return EINVAL; @@ -2325,7 +2298,7 @@ __pthread_mutex_unlock (pthread_mutex_t *mutex) int __pthread_mutex_destroy (pthread_mutex_t *mutex) { - if (check_valid_pointer (mutex) && (*mutex == PTHREAD_MUTEX_INITIALIZER)) + if (pthread_mutex::isGoodInitializer (mutex)) return 0; if (!pthread_mutex::isGoodObject (mutex)) return EINVAL; @@ -2344,7 +2317,7 @@ __pthread_mutex_setprioceiling (pthread_mutex_t *mutex, int prioceiling, int *old_ceiling) { pthread_mutex_t *themutex = mutex; - if (*mutex == PTHREAD_MUTEX_INITIALIZER) + if (pthread_mutex::isGoodInitializer (mutex)) __pthread_mutex_init (mutex, NULL); if (!pthread_mutex::isGoodObject (themutex)) return EINVAL; @@ -2357,7 +2330,7 @@ int __pthread_mutexattr_getprotocol (const pthread_mutexattr_t *attr, int *protocol) { - if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT) + if (!pthread_mutexattr::isGoodObject (attr)) return EINVAL; return ENOSYS; } @@ -2366,7 +2339,7 @@ int __pthread_mutexattr_getpshared (const pthread_mutexattr_t *attr, int *pshared) { - if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT) + if (!pthread_mutexattr::isGoodObject (attr)) return EINVAL; *pshared = (*attr)->pshared; return 0; @@ -2379,7 +2352,7 @@ __pthread_mutexattr_getpshared (const pthread_mutexattr_t *attr, int __pthread_mutexattr_gettype (const pthread_mutexattr_t *attr, int *type) { - if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT) + if (!pthread_mutexattr::isGoodObject (attr)) return EINVAL; *type = (*attr)->mutextype; return 0; @@ -2393,11 +2366,11 @@ __pthread_mutexattr_gettype (const pthread_mutexattr_t *attr, int *type) int __pthread_mutexattr_init (pthread_mutexattr_t *attr) { - if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != INVALID_OBJECT) + if (pthread_mutexattr::isGoodObject (attr)) return EBUSY; *attr = new pthread_mutexattr (); - if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT) + if (!pthread_mutexattr::isGoodObject (attr)) { delete (*attr); *attr = NULL; @@ -2409,7 +2382,7 @@ __pthread_mutexattr_init (pthread_mutexattr_t *attr) int __pthread_mutexattr_destroy (pthread_mutexattr_t *attr) { - if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT) + if (!pthread_mutexattr::isGoodObject (attr)) return EINVAL; delete (*attr); *attr = NULL; @@ -2421,7 +2394,7 @@ __pthread_mutexattr_destroy (pthread_mutexattr_t *attr) int __pthread_mutexattr_setprotocol (pthread_mutexattr_t *attr, int protocol) { - if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT) + if (!pthread_mutexattr::isGoodObject (attr)) return EINVAL; return ENOSYS; } @@ -2431,7 +2404,7 @@ int __pthread_mutexattr_setprioceiling (pthread_mutexattr_t *attr, int prioceiling) { - if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT) + if (!pthread_mutexattr::isGoodObject (attr)) return EINVAL; return ENOSYS; } @@ -2440,7 +2413,7 @@ int __pthread_mutexattr_getprioceiling (const pthread_mutexattr_t *attr, int *prioceiling) { - if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT) + if (!pthread_mutexattr::isGoodObject (attr)) return EINVAL; return ENOSYS; } @@ -2448,7 +2421,7 @@ __pthread_mutexattr_getprioceiling (const pthread_mutexattr_t *attr, int __pthread_mutexattr_setpshared (pthread_mutexattr_t *attr, int pshared) { - if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT) + if (!pthread_mutexattr::isGoodObject (attr)) return EINVAL; /*we don't use pshared for anything as yet. We need to test PROCESS_SHARED *functionality @@ -2463,7 +2436,7 @@ __pthread_mutexattr_setpshared (pthread_mutexattr_t *attr, int pshared) int __pthread_mutexattr_settype (pthread_mutexattr_t *attr, int type) { - if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT) + if (!pthread_mutexattr::isGoodObject (attr)) return EINVAL; if (type != PTHREAD_MUTEX_RECURSIVE) return EINVAL; @@ -2472,11 +2445,21 @@ __pthread_mutexattr_settype (pthread_mutexattr_t *attr, int type) } /*Semaphores */ + +/* static members */ +bool +semaphore::isGoodObject (sem_t const * sem) +{ + if (verifyable_object_isvalid (sem, SEM_MAGIC) != VALID_OBJECT) + return false; + return true; +} + int -__sem_init (sem_t *sem, int pshared, unsigned int value) +semaphore::init (sem_t *sem, int pshared, unsigned int value) { /*opengroup calls this undefined */ - if (verifyable_object_isvalid (sem, SEM_MAGIC) != INVALID_OBJECT) + if (isGoodObject (sem)) return EBUSY; if (value > SEM_VALUE_MAX) @@ -2484,7 +2467,7 @@ __sem_init (sem_t *sem, int pshared, unsigned int value) *sem = new semaphore (pshared, value); - if (verifyable_object_isvalid (sem, SEM_MAGIC) != VALID_OBJECT) + if (!isGoodObject (sem)) { delete (*sem); *sem = NULL; @@ -2494,9 +2477,9 @@ __sem_init (sem_t *sem, int pshared, unsigned int value) } int -__sem_destroy (sem_t *sem) +semaphore::destroy (sem_t *sem) { - if (verifyable_object_isvalid (sem, SEM_MAGIC) != VALID_OBJECT) + if (!isGoodObject (sem)) return EINVAL; /*FIXME - new feature - test for busy against threads... */ @@ -2507,9 +2490,9 @@ __sem_destroy (sem_t *sem) } int -__sem_wait (sem_t *sem) +semaphore::wait (sem_t *sem) { - if (verifyable_object_isvalid (sem, SEM_MAGIC) != VALID_OBJECT) + if (!isGoodObject (sem)) { set_errno (EINVAL); return -1; @@ -2520,9 +2503,9 @@ __sem_wait (sem_t *sem) } int -__sem_trywait (sem_t *sem) +semaphore::trywait (sem_t *sem) { - if (verifyable_object_isvalid (sem, SEM_MAGIC) != VALID_OBJECT) + if (!isGoodObject (sem)) { set_errno (EINVAL); return -1; @@ -2532,9 +2515,9 @@ __sem_trywait (sem_t *sem) } int -__sem_post (sem_t *sem) +semaphore::post (sem_t *sem) { - if (verifyable_object_isvalid (sem, SEM_MAGIC) != VALID_OBJECT) + if (!isGoodObject (sem)) return EINVAL; (*sem)->Post (); diff --git a/winsup/cygwin/thread.h b/winsup/cygwin/thread.h index 9238153ea53..c36466020a3 100644 --- a/winsup/cygwin/thread.h +++ b/winsup/cygwin/thread.h @@ -173,58 +173,93 @@ typedef enum verifyable_object_state verifyable_object_isvalid (void const *, long); verifyable_object_state verifyable_object_isvalid (void const *, long, void *); +/* interface */ +template <class ListNode> class List { +public: + List(); + void Insert (ListNode *aNode); + ListNode *Remove ( ListNode *aNode); + ListNode *Pop (); + void forEach (void (*)(ListNode *aNode)); +protected: + ListNode *head; +}; + class pthread_key:public verifyable_object { public: static bool isGoodObject (pthread_key_t const *); + static void runAllDestructors (); DWORD dwTlsIndex; - void *fork_buf; - class pthread_key *next; int set (const void *); - void *get (); + void *get () const; - pthread_key (void (*)(void *)); + pthread_key (void (*)(void *)); ~pthread_key (); static void fixup_before_fork(); static void fixup_after_fork(); + + /* List support calls */ + class pthread_key *next; private: // lists of objects. USE THREADSAFE INSERTS AND DELETES. - static pthread_key * keys; + static List<pthread_key> keys; + static void saveAKey (pthread_key *); + static void restoreAKey (pthread_key *); + static void destroyAKey (pthread_key *); void saveKeyToBuffer (); void recreateKeyFromBuffer (); -}; - -/* FIXME: test using multiple inheritance and merging key_destructor into pthread_key - * for efficiency */ -class pthread_key_destructor -{ -public: void (*destructor) (void *); - pthread_key_destructor *InsertAfter (pthread_key_destructor * node); - pthread_key_destructor *UnlinkNext (); - pthread_key_destructor *Next (); - - pthread_key_destructor (void (*thedestructor) (void *), pthread_key * key); - pthread_key_destructor *next; - pthread_key *key; + void run_destructor () const; + void *fork_buf; }; -class pthread_key_destructor_list +/* implementation */ +template <class ListNode> +List<ListNode>::List<ListNode> () : head(NULL) { -public: - void Insert (pthread_key_destructor * node); -/* remove a given dataitem, wherever in the list it is */ - pthread_key_destructor *Remove (pthread_key_destructor * item); -/* get the first item and remove at the same time */ - pthread_key_destructor *Pop (); - pthread_key_destructor *Remove (pthread_key * key); - void IterateNull (); -private: - pthread_key_destructor * head; -}; - +} +template <class ListNode> void +List<ListNode>::Insert (ListNode *aNode) +{ + if (!aNode) + return; + aNode->next = (ListNode *) InterlockedExchangePointer (&head, aNode); +} +template <class ListNode> ListNode * +List<ListNode>::Remove ( ListNode *aNode) +{ + if (!aNode) + return NULL; + if (!head) + return NULL; + if (aNode == head) + return Pop (); + ListNode *resultPrev = head; + while (resultPrev && resultPrev->next && !(aNode == resultPrev->next)) + resultPrev = resultPrev->next; + if (resultPrev) + return (ListNode *)InterlockedExchangePointer (&resultPrev->next, resultPrev->next->next); + return NULL; +} +template <class ListNode> ListNode * +List<ListNode>::Pop () +{ + return (ListNode *) InterlockedExchangePointer (&head, head->next); +} +/* poor mans generic programming. */ +template <class ListNode> void +List<ListNode>::forEach (void (*callback)(ListNode *)) +{ + ListNode *aNode = head; + while (aNode) + { + callback (aNode); + aNode = aNode->next; + } +} class pthread_attr:public verifyable_object { @@ -254,6 +289,7 @@ class pthread_mutex:public verifyable_object { public: static bool isGoodObject(pthread_mutex_t const *); + static bool isGoodInitializer(pthread_mutex_t const *); static bool isGoodInitializerOrObject(pthread_mutex_t const *); CRITICAL_SECTION criticalsection; HANDLE win32_obj_id; @@ -300,9 +336,21 @@ public: static void atforkparent(); static void atforkchild(); + /* API calls */ + static int cancel (pthread_t); + static int join (pthread_t * thread, void **return_val); + static int detach (pthread_t * thread); + static int create (pthread_t * thread, const pthread_attr_t * attr, + void *(*start_routine) (void *), void *arg); + static int once (pthread_once_t *, void (*)(void)); + static int atfork(void (*)(void), void (*)(void), void (*)(void)); + static int suspend (pthread_t * thread); + static int resume (pthread_t * thread); + virtual void exit (void *value_ptr); virtual int cancel (); + virtual void testcancel (); static void static_cancel_self (); @@ -322,9 +370,6 @@ private: __pthread_cleanup_handler *cleanup_stack; pthread_mutex mutex; - friend int __pthread_join (pthread_t * thread, void **return_val); - friend int __pthread_detach (pthread_t * thread); - void pop_all_cleanup_handlers (void); void precreate (pthread_attr *); void postcreate (); @@ -361,7 +406,7 @@ class pthreadNull : public pthread class pthread_condattr:public verifyable_object { public: - static bool isGoodObject(pthread_condattr_t *); + static bool isGoodObject(pthread_condattr_t const *); int shared; pthread_condattr (); @@ -371,7 +416,9 @@ public: class pthread_cond:public verifyable_object { public: - static bool isGoodObject(pthread_cond_t *); + static bool isGoodObject(pthread_cond_t const *); + static bool isGoodInitializer(pthread_cond_t const *); + static bool isGoodInitializerOrObject(pthread_cond_t const *); int shared; LONG waiting; LONG ExitingWait; @@ -400,7 +447,14 @@ public: class semaphore:public verifyable_object { public: - static bool isGoodObject(semaphore **); + static bool isGoodObject(sem_t const *); + /* API calls */ + static int init (sem_t * sem, int pshared, unsigned int value); + static int destroy (sem_t * sem); + static int wait (sem_t * sem); + static int trywait (sem_t * sem); + static int post (sem_t * sem); + HANDLE win32_obj_id; class semaphore * next; int shared; @@ -437,7 +491,6 @@ public: struct _winsup_t winsup_reent; pthread mainthread; - pthread_key_destructor_list destructors; callback *pthread_prepare; callback *pthread_child; callback *pthread_parent; @@ -459,21 +512,8 @@ public: } }; -/* Cancellation */ -int __pthread_cancel (pthread_t thread); - -/* Thread Exit */ -int __pthread_join (pthread_t * thread, void **return_val); -int __pthread_detach (pthread_t * thread); - extern "C" { -/* ThreadCreation */ -int __pthread_create (pthread_t * thread, const pthread_attr_t * attr, - void *(*start_routine) (void *), void *arg); -int __pthread_once (pthread_once_t *, void (*)(void)); -int __pthread_atfork(void (*)(void), void (*)(void), void (*)(void)); - int __pthread_attr_init (pthread_attr_t * attr); int __pthread_attr_destroy (pthread_attr_t * attr); int __pthread_attr_setdetachstate (pthread_attr_t *, int); @@ -494,10 +534,6 @@ int __pthread_attr_setschedpolicy (pthread_attr_t *, int); int __pthread_attr_setscope (pthread_attr_t *, int); int __pthread_attr_setstackaddr (pthread_attr_t *, void *); -/* Thread suspend */ -int __pthread_suspend (pthread_t * thread); -int __pthread_continue (pthread_t * thread); - /* Thread SpecificData */ int __pthread_key_create (pthread_key_t * key, void (*destructor) (void *)); int __pthread_key_delete (pthread_key_t key); @@ -556,16 +592,7 @@ int __pthread_getschedparam (pthread_t thread, int *policy, int __pthread_setschedparam (pthread_t thread, int policy, const struct sched_param *param); -/* cancelability states */ - -/* Semaphores */ -int __sem_init (sem_t * sem, int pshared, unsigned int value); -int __sem_destroy (sem_t * sem); -int __sem_wait (sem_t * sem); -int __sem_trywait (sem_t * sem); -int __sem_post (sem_t * sem); }; - #endif // MT_SAFE #endif // _CYGNUS_THREADS_ |