* thread.cc (pthread::cancel): Re-allow asynchronous cancellation from

Cygwin code since it looks like the problem is Windows only.
This commit is contained in:
Corinna Vinschen 2012-05-23 17:39:39 +00:00
parent bff08077a6
commit 2b165a453e
2 changed files with 17 additions and 26 deletions

View File

@ -1,3 +1,8 @@
2012-05-23 Corinna Vinschen <corinna@vinschen.de>
* thread.cc (pthread::cancel): Re-allow asynchronous cancellation from
Cygwin code since it looks like the problem is Windows only.
2012-05-23 Corinna Vinschen <corinna@vinschen.de> 2012-05-23 Corinna Vinschen <corinna@vinschen.de>
* thread.cc: Add a temporary workaround to help Cygwin along while * thread.cc: Add a temporary workaround to help Cygwin along while

View File

@ -631,42 +631,28 @@ pthread::cancel ()
SuspendThread (win32_obj_id); SuspendThread (win32_obj_id);
if (WaitForSingleObject (win32_obj_id, 0) == WAIT_TIMEOUT) if (WaitForSingleObject (win32_obj_id, 0) == WAIT_TIMEOUT)
{ {
static uintptr_t cyg_addr;
CONTEXT context; CONTEXT context;
context.ContextFlags = CONTEXT_CONTROL; context.ContextFlags = CONTEXT_CONTROL;
GetThreadContext (win32_obj_id, &context); GetThreadContext (win32_obj_id, &context);
/* FIXME: /* The OS is not foolproof in terms of asynchronous thread cancellation
and tends to hang infinitely if we change the instruction pointer.
File access (and probably more) in Cygwin is not foolproof in terms of So just don't cancel asynchronously if the thread is currently
asynchronous thread cancellation. For instance, the cleanup of the executing Windows code. Rely on deferred cancellation in this case. */
tmp_buf pointers needs to be changed to use pthread_cleanup_push/pop, if (!cygtls->inside_kernel (&context))
rather than being hidden in the myfault class. We have to inspect
all Cygwin functions so that none of them is left in a wrong or
undefined state on thread cancellation.
For the time being, just disable asynchronous cancellation if the
thread is currently executing Cygwin or Windows code. Rely on
deferred cancellation in this case. */
if (!cyg_addr)
cyg_addr = (uintptr_t) GetModuleHandle ("cygwin1.dll");
if ((context.Eip < cyg_addr || context.Eip >= (uintptr_t) cygheap)
&& !cygtls->inside_kernel (&context))
{ {
context.Eip = (DWORD) pthread::static_cancel_self; context.Eip = (DWORD) pthread::static_cancel_self;
SetThreadContext (win32_obj_id, &context); SetThreadContext (win32_obj_id, &context);
} }
} }
mutex.unlock (); mutex.unlock ();
/* Setting the context to another function does not work if the thread is /* See above. For instance, a thread which waits for a semaphore in sem_wait
waiting in WFMO. For instance, a thread which waits for a semaphore in will call cancelable_wait which in turn calls WFMO. While this WFMO call
sem_wait will call cancelable_wait which in turn calls WFMO. While this is cancelable by setting the thread's cancel_event object, the OS
WFMO call is cancelable by setting the thread's cancel_event object, the apparently refuses to set the thread's context and continues to wait for
OS apparently refuses to set the thread's context and continues to wait the WFMO conditions. This is *not* reflected in the return value of
for the WFMO conditions. This is *not* reflected in the return value of
SetThreadContext or ResumeThread, btw. SetThreadContext or ResumeThread, btw.
So, what we do here is to set the cancel_event as well. This allows the So, what we do here is to set the cancel_event as well to allow at least
WFMO call in cancelable_wait and elsewhere to return and to handle the a deferred cancel. */
cancel request by itself. */
canceled = true; canceled = true;
SetEvent (cancel_event); SetEvent (cancel_event);
ResumeThread (win32_obj_id); ResumeThread (win32_obj_id);