diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 8d6890288..a6a0d1daa 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,13 @@ +2003-01-09 Thomas Pfaff + + * thread.h (WAIT_CANCELED): New define. + (pthread::cancelable_wait): New static method. + * thread.cc (pthread::cancelable_wait): Implement. + (semaphore::Wait): Wait on semaphore and thread cancellation. + (pthread::join): Wait on joined thread and thread cancellation. + (semaphore::wait): Add testcancel to check for thread + cancellation even if the semaphore is available. + 2003-01-09 Thomas Pfaff * include/pthread.h: Add define for errorchecking mutexes. diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc index 2aac4b3b3..dee6eb05a 100644 --- a/winsup/cygwin/thread.cc +++ b/winsup/cygwin/thread.cc @@ -471,7 +471,7 @@ pwrite () read () readv () select () -sem_wait () +*sem_wait () sigpause () sigsuspend () sigtimedwait () @@ -632,6 +632,28 @@ pthread::static_cancel_self (void) } +DWORD pthread::cancelable_wait (HANDLE object, DWORD timeout, const bool do_cancel) +{ + DWORD res; + HANDLE wait_objects[2]; + pthread_t thread = self (); + + if (!isGoodObject (&thread) || thread->cancelstate == PTHREAD_CANCEL_DISABLE) + return WaitForSingleObject (object, timeout); + + // Do not change the wait order + // The object must have higher priority than the cancel event, + // because WaitForMultipleObjects will return the smallest index + // if both objects are signaled + wait_objects[0] = object; + wait_objects[1] = thread->cancel_event; + + res = WaitForMultipleObjects (2, wait_objects, FALSE, timeout); + if (do_cancel && res == WAIT_CANCELED) + pthread::static_cancel_self (); + return res; +} + int pthread::setcancelstate (int state, int *oldstate) { @@ -1390,8 +1412,15 @@ semaphore::TryWait () void semaphore::Wait () { - WaitForSingleObject (win32_obj_id, INFINITE); - currentvalue--; + switch (pthread::cancelable_wait (win32_obj_id, INFINITE)) + { + case WAIT_OBJECT_0: + currentvalue--; + break; + default: + debug_printf ("cancelable_wait failed. %E"); + return; + } } void @@ -1850,14 +1879,15 @@ pthread::join (pthread_t *thread, void **return_val) { pthread_t joiner = self (); - if (!isGoodObject (&joiner)) - return EINVAL; + joiner->testcancel (); // 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 (!isGoodObject (&joiner)) + return EINVAL; + if (!isGoodObject (thread)) return ESRCH; @@ -1876,14 +1906,26 @@ pthread::join (pthread_t *thread, void **return_val) (*thread)->joiner = joiner; (*thread)->attr.joinable = PTHREAD_CREATE_DETACHED; (*thread)->mutex.UnLock (); - WaitForSingleObject ((*thread)->win32_obj_id, INFINITE); - if (return_val) - *return_val = (*thread)->return_ptr; - // cleanup - delete (*thread); - } /* End if */ - pthread_testcancel (); + switch (cancelable_wait ((*thread)->win32_obj_id, INFINITE, false)) + { + case WAIT_OBJECT_0: + if (return_val) + *return_val = (*thread)->return_ptr; + delete (*thread); + break; + case WAIT_CANCELED: + // set joined thread back to joinable since we got canceled + (*thread)->joiner = NULL; + (*thread)->attr.joinable = PTHREAD_CREATE_JOINABLE; + joiner->cancel_self (); + // never reached + break; + default: + // should never happen + return EINVAL; + } + } return 0; } @@ -2629,6 +2671,8 @@ semaphore::destroy (sem_t *sem) int semaphore::wait (sem_t *sem) { + pthread_testcancel (); + if (!isGoodObject (sem)) { set_errno (EINVAL); diff --git a/winsup/cygwin/thread.h b/winsup/cygwin/thread.h index cf08a7630..fad85e557 100644 --- a/winsup/cygwin/thread.h +++ b/winsup/cygwin/thread.h @@ -332,6 +332,8 @@ private: static nativeMutex mutexInitializationLock; }; +#define WAIT_CANCELED (WAIT_OBJECT_0 + 1) + class pthread:public verifyable_object { public: @@ -379,6 +381,8 @@ public: virtual void testcancel (); static void static_cancel_self (); + static DWORD cancelable_wait (HANDLE object, DWORD timeout, const bool do_cancel = true); + virtual int setcancelstate (int state, int *oldstate); virtual int setcanceltype (int type, int *oldtype);