diff options
Diffstat (limited to 'libpthread/linuxthreads/cancel.c')
| -rw-r--r-- | libpthread/linuxthreads/cancel.c | 18 | 
1 files changed, 17 insertions, 1 deletions
| diff --git a/libpthread/linuxthreads/cancel.c b/libpthread/linuxthreads/cancel.c index 1356348a7..c6b5f94f9 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,6 +70,7 @@ 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)) { @@ -71,7 +80,10 @@ int pthread_cancel(pthread_t thread)    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;    } @@ -125,6 +137,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 +158,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);  } | 
