diff -urp src.old/winsup/cygwin/include/pthread.h src/winsup/cygwin/include/pthread.h --- src.old/winsup/cygwin/include/pthread.h Thu Apr 25 10:11:30 2002 +++ src/winsup/cygwin/include/pthread.h Thu Apr 25 17:33:27 2002 @@ -42,7 +42,7 @@ extern "C" #define PTHREAD_CANCEL_ENABLE 0 #define PTHREAD_CANCEL_DEFERRED 0 #define PTHREAD_CANCEL_DISABLE 1 -#define PTHREAD_CANCELED +#define PTHREAD_CANCELED ((void *)-1) /* this should be a value that can never be a valid address */ #define PTHREAD_COND_INITIALIZER (void *)21 #define PTHREAD_CREATE_DETACHED 1 diff -urp src.old/winsup/cygwin/thread.cc src/winsup/cygwin/thread.cc --- src.old/winsup/cygwin/thread.cc Fri Apr 26 08:22:57 2002 +++ src/winsup/cygwin/thread.cc Fri Apr 26 09:42:36 2002 @@ -48,6 +48,26 @@ details. */ extern int threadsafe; +#if defined(_M_IX86) || defined(_X86_) +#define PROGCTR(Context) ((Context).Eip) +#endif + +#if defined(_MIPS_) +#define PROGCTR(Context) ((Context).Fir) +#endif + +#if defined(_ALPHA_) +#define PROGCTR(Context) ((Context).Fir) +#endif + +#if defined(_PPC_) +#define PROGCTR(Context) ((Context).Iar) +#endif + +#if !defined(PROGCTR) +#error Module contains CPU-specific code; modify and recompile. +#endif + /*pthread_key_destructor_list class: to-be threadsafe single linked list *FIXME: Put me in a dedicated file, or a least a tools area ! */ @@ -346,13 +366,16 @@ MTinterface::fixup_after_fork (void) } pthread::pthread ():verifyable_object (PTHREAD_MAGIC), win32_obj_id (0), - cancelstate (0), canceltype (0), mutex(NULL), + cancelstate (0), canceltype (0), cancel_event (0), + mutex ((pthread_mutex *)PTHREAD_MUTEX_INITIALIZER), cleanup_handlers(NULL), joiner(NULL) { } pthread::~pthread () { + if (cancel_event) + CloseHandle (cancel_event); if (win32_obj_id) CloseHandle (win32_obj_id); __pthread_mutex_destroy(&mutex); @@ -387,6 +410,16 @@ pthread::create (void *(*func) (void *), return; } + cancel_event = ::CreateEvent (NULL,TRUE,FALSE,NULL); + if (!cancel_event) + { + system_printf ("couldn't create cancel event, this %p LastError %d", this, GetLastError () ); + /*we need the event for correct behaviour */ + magic = 0; + return; + } + + win32_obj_id = ::CreateThread (&sec_none_nih, attr.stacksize, (LPTHREAD_START_ROUTINE) thread_init_wrapper, this, CREATE_SUSPENDED, &thread_id); @@ -1000,33 +1033,44 @@ __pthread_cleanup (pthread_t thread) int __pthread_cancel (pthread_t thread) { + pthread_t self = __pthread_self (); + if (verifyable_object_isvalid (&thread, PTHREAD_MAGIC) != VALID_OBJECT) return ESRCH; - if (thread->cancelstate == PTHREAD_CANCEL_ENABLE) + + if( __pthread_equal(&thread, &self ) ) { -#if 0 - /*once all the functions call testcancel (), we will do this */ - if (thread->canceltype == PTHREAD_CANCEL_DEFERRED) - { - } - else + __pthread_cancel_self (); + } + + __pthread_mutex_lock (&thread->mutex); + + if (thread->canceltype == PTHREAD_CANCEL_DEFERRED || + thread->cancelstate == PTHREAD_CANCEL_DISABLE) { - /*possible FIXME: this function is meant to return asynchronously - *from the cancellation routine actually firing. So we may need some sort - *of signal to be sent that is immediately recieved and acted on. - */ - __pthread_cleanup (thread); + // cancel deferred + SetEvent (thread->cancel_event); + __pthread_mutex_unlock (&thread->mutex); + return 0; } -#endif + + // cancel asynchronous + SuspendThread (thread->win32_obj_id); + if (WaitForSingleObject (thread->win32_obj_id, 0) == WAIT_TIMEOUT) + { + CONTEXT context; + context.ContextFlags = CONTEXT_CONTROL; + GetThreadContext (thread->win32_obj_id, &context); + PROGCTR(context) = (DWORD) __pthread_cancel_self; + SetThreadContext (thread->win32_obj_id, &context); } -/* return 0; -*/ + ResumeThread (thread->win32_obj_id); - return ESRCH; -/* - we return ESRCH until all the required functions call testcancel (); - this will give applications predictable behaviour. + __pthread_mutex_unlock (&thread->mutex); + return 0; +/* + TODO: insert pthread_testcancel into the required functions the required function list is: *indicates done, X indicates not present in cygwin. aio_suspend () *close () @@ -1200,27 +1244,54 @@ opengroup specs. */ } -/*no races in these three functions: they are all current-thread-only */ +void +__pthread_cancel_self (void) +{ + __pthread_exit (PTHREAD_CANCELED); +} + int __pthread_setcancelstate (int state, int *oldstate) { + int result = 0; class pthread *thread = __pthread_self (); + + __pthread_mutex_lock(&thread->mutex); + if (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE) - return EINVAL; - *oldstate = thread->cancelstate; - thread->cancelstate = state; - return 0; + result = EINVAL; + else + { + if (oldstate) + *oldstate = thread->cancelstate; + thread->cancelstate = state; + } + + __pthread_mutex_unlock(&thread->mutex); + + return result; } int __pthread_setcanceltype (int type, int *oldtype) { + int result = 0; class pthread *thread = __pthread_self (); + + __pthread_mutex_lock(&thread->mutex); + if (type != PTHREAD_CANCEL_DEFERRED && type != PTHREAD_CANCEL_ASYNCHRONOUS) - return EINVAL; - *oldtype = thread->canceltype; - thread->canceltype = type; - return 0; + result = EINVAL; + else + { + if (oldtype) + *oldtype = thread->canceltype; + thread->canceltype = type; + } + + __pthread_mutex_unlock(&thread->mutex); + + return result; } /*deferred cancellation request handler */ @@ -1230,8 +1301,9 @@ __pthread_testcancel (void) class pthread *thread = __pthread_self (); if (thread->cancelstate == PTHREAD_CANCEL_DISABLE) return; - /*check the cancellation event object here - not neededuntil pthread_cancel actually - *does something*/ + + if( WAIT_OBJECT_0 == WaitForSingleObject (thread->cancel_event, 0 ) ) + __pthread_cancel_self (); } void @@ -1557,6 +1629,7 @@ __pthread_exit (void *value_ptr) MT_INTERFACE->destructors.IterateNull (); __pthread_mutex_lock(&thread->mutex); + if( __pthread_equal(&thread->joiner, &thread ) ) // cleanup if thread is in detached state and not joined delete thread; @@ -1589,6 +1662,7 @@ __pthread_join (pthread_t *thread, void } __pthread_mutex_lock(&(*thread)->mutex); + if ((*thread)->attr.joinable == PTHREAD_CREATE_DETACHED) { __pthread_mutex_unlock(&(*thread)->mutex); @@ -1621,6 +1695,7 @@ __pthread_detach (pthread_t *thread) return ESRCH; __pthread_mutex_lock(&(*thread)->mutex); + if ((*thread)->attr.joinable == PTHREAD_CREATE_DETACHED) { __pthread_mutex_unlock(&(*thread)->mutex); diff -urp src.old/winsup/cygwin/thread.h src/winsup/cygwin/thread.h --- src.old/winsup/cygwin/thread.h Thu Apr 25 09:15:17 2002 +++ src/winsup/cygwin/thread.h Thu Apr 25 17:33:29 2002 @@ -239,6 +239,7 @@ public: void *return_ptr; bool suspended; int cancelstate, canceltype; + HANDLE cancel_event; pthread_mutex *mutex; __pthread_cleanup_handler *cleanup_handlers; pthread_t joiner; @@ -502,6 +503,7 @@ int __pthread_setschedparam (pthread_t t /* cancelability states */ int __pthread_cancel (pthread_t thread); +void __pthread_cancel_self (void); int __pthread_setcancelstate (int state, int *oldstate); int __pthread_setcanceltype (int type, int *oldtype); void __pthread_testcancel (void);