From 07a485defae1ef578c5b3ce0d4373201948a7345 Mon Sep 17 00:00:00 2001 From: "\"Steven J. Hill\"" Date: Tue, 13 Sep 2005 02:28:34 +0000 Subject: Merge with trunk. "So do that funky merge whiiite boy..." --- libpthread/linuxthreads/cancel.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'libpthread/linuxthreads/cancel.c') diff --git a/libpthread/linuxthreads/cancel.c b/libpthread/linuxthreads/cancel.c index 1356348a7..dbba7eef4 100644 --- a/libpthread/linuxthreads/cancel.c +++ b/libpthread/linuxthreads/cancel.c @@ -26,6 +26,14 @@ extern void __rpc_thread_destroy(void); #endif +#ifdef _STACK_GROWS_DOWN +# define FRAME_LEFT(frame, other) ((char *) frame >= (char *) other) +#elif _STACK_GROWS_UP +# define FRAME_LEFT(frame, other) ((char *) frame <= (char *) other) +#else +# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP" +#endif + int pthread_setcancelstate(int state, int * oldstate) { @@ -62,28 +70,31 @@ int pthread_cancel(pthread_t thread) int dorestart = 0; pthread_descr th; pthread_extricate_if *pextricate; + int already_canceled; __pthread_lock(&handle->h_lock, NULL); - if (invalid_handle(handle, thread)) { + if (nonexisting_handle(handle, thread)) { __pthread_unlock(&handle->h_lock); return ESRCH; } th = handle->h_descr; - if (th->p_canceled) { + already_canceled = th->p_canceled; + th->p_canceled = 1; + + if (th->p_cancelstate == PTHREAD_CANCEL_DISABLE || already_canceled) { __pthread_unlock(&handle->h_lock); return 0; } pextricate = th->p_extricate; - th->p_canceled = 1; pid = th->p_pid; /* If the thread has registered an extrication interface, then invoke the interface. If it returns 1, then we succeeded in dequeuing the thread from whatever waiting object it was enqueued - with. In that case, it is our responsibility to wake it up. + with. In that case, it is our responsibility to wake it up. And also to set the p_woken_by_cancel flag so the woken thread can tell that it was woken by cancellation. */ @@ -125,6 +136,8 @@ void _pthread_cleanup_push(struct _pthread_cleanup_buffer * buffer, buffer->__routine = routine; buffer->__arg = arg; buffer->__prev = THREAD_GETMEM(self, p_cleanup); + if (buffer->__prev != NULL && FRAME_LEFT (buffer, buffer->__prev)) + buffer->__prev = NULL; THREAD_SETMEM(self, p_cleanup, buffer); } @@ -144,6 +157,8 @@ void _pthread_cleanup_push_defer(struct _pthread_cleanup_buffer * buffer, buffer->__arg = arg; buffer->__canceltype = THREAD_GETMEM(self, p_canceltype); buffer->__prev = THREAD_GETMEM(self, p_cleanup); + if (buffer->__prev != NULL && FRAME_LEFT (buffer, buffer->__prev)) + buffer->__prev = NULL; THREAD_SETMEM(self, p_canceltype, PTHREAD_CANCEL_DEFERRED); THREAD_SETMEM(self, p_cleanup, buffer); } -- cgit v1.2.3