diff -urp src.old/winsup/cygwin/thread.cc src/winsup/cygwin/thread.cc --- src.old/winsup/cygwin/thread.cc 2002-12-11 11:10:28.000000000 +0100 +++ src/winsup/cygwin/thread.cc 2002-12-20 09:37:11.000000000 +0100 @@ -471,7 +471,7 @@ pwrite () read () readv () select () -sem_wait () +*sem_wait () sigpause () sigsuspend () sigtimedwait () @@ -632,6 +632,27 @@ 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, + // that means WaitForMultipleObjects signales the smallest index + 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 +1411,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 +1878,15 @@ pthread::join (pthread_t *thread, void * { 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 +1905,26 @@ pthread::join (pthread_t *thread, void * (*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 +2670,8 @@ semaphore::destroy (sem_t *sem) int semaphore::wait (sem_t *sem) { + pthread::self ()->testcancel (); + if (!isGoodObject (sem)) { set_errno (EINVAL); diff -urp src.old/winsup/cygwin/thread.h src/winsup/cygwin/thread.h --- src.old/winsup/cygwin/thread.h 2002-12-10 14:38:23.000000000 +0100 +++ src/winsup/cygwin/thread.h 2002-12-20 09:37:13.000000000 +0100 @@ -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);