Author: bonefish Date: 2011-06-06 20:45:44 +0200 (Mon, 06 Jun 2011) New Revision: 41980 Changeset: https://dev.haiku-os.org/changeset/41980 Modified: haiku/branches/developer/bonefish/signals/headers/private/libroot/pthread_private.h haiku/branches/developer/bonefish/signals/src/system/libroot/posix/pthread/pthread.cpp haiku/branches/developer/bonefish/signals/src/system/libroot/posix/pthread/pthread_cancel.cpp Log: * Reimplemented the pthread cancellation functions. The _pthread_thread::cancel* fields have been removed. Instead three more flags are used. * Partially implemented pthread_cancel(). The syscall for asynchronous cancellation is still missing, though. Modified: haiku/branches/developer/bonefish/signals/headers/private/libroot/pthread_private.h =================================================================== --- haiku/branches/developer/bonefish/signals/headers/private/libroot/pthread_private.h 2011-06-06 18:20:38 UTC (rev 41979) +++ haiku/branches/developer/bonefish/signals/headers/private/libroot/pthread_private.h 2011-06-06 18:45:44 UTC (rev 41980) @@ -12,8 +12,12 @@ #include <OS.h> -#define THREAD_DETACHED 0x01 -#define THREAD_DEAD 0x02 +// _pthread_thread::flags values +#define THREAD_DETACHED 0x01 +#define THREAD_DEAD 0x02 +#define THREAD_CANCELED 0x04 +#define THREAD_CANCEL_ENABLED 0x08 +#define THREAD_CANCEL_ASYNCHRONOUS 0x10 struct thread_creation_attributes; @@ -62,9 +66,6 @@ void *(*entry)(void*); void *entry_argument; void *exit_value; - int cancel_state; - int cancel_type; - bool cancelled; struct pthread_key_data specific[PTHREAD_KEYS_MAX]; struct __pthread_cleanup_handler *cleanup_handlers; } pthread_thread; Modified: haiku/branches/developer/bonefish/signals/src/system/libroot/posix/pthread/pthread.cpp =================================================================== --- haiku/branches/developer/bonefish/signals/src/system/libroot/posix/pthread/pthread.cpp 2011-06-06 18:20:38 UTC (rev 41979) +++ haiku/branches/developer/bonefish/signals/src/system/libroot/posix/pthread/pthread.cpp 2011-06-06 18:45:44 UTC (rev 41980) @@ -85,11 +85,9 @@ thread->entry = entry; thread->entry_argument = data; thread->exit_value = NULL; - thread->cancel_state = PTHREAD_CANCEL_ENABLE; - thread->cancel_type = PTHREAD_CANCEL_DEFERRED; - thread->cancelled = false; thread->cleanup_handlers = NULL; - thread->flags = 0; + thread->flags = THREAD_CANCEL_ENABLED; + // thread cancellation enabled, but deferred memset(thread->specific, 0, sizeof(thread->specific)); } Modified: haiku/branches/developer/bonefish/signals/src/system/libroot/posix/pthread/pthread_cancel.cpp =================================================================== --- haiku/branches/developer/bonefish/signals/src/system/libroot/posix/pthread/pthread_cancel.cpp 2011-06-06 18:20:38 UTC (rev 41979) +++ haiku/branches/developer/bonefish/signals/src/system/libroot/posix/pthread/pthread_cancel.cpp 2011-06-06 18:45:44 UTC (rev 41980) @@ -1,4 +1,5 @@ /* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@xxxxxxx * Copyright 2008, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx All rights reserved. * Distributed under the terms of the MIT License. */ @@ -6,32 +7,67 @@ #include "pthread_private.h" -#include <stdio.h> +static inline void +test_asynchronous_cancel(int32 flags) +{ + static const int32 kFlags = THREAD_CANCELED | THREAD_CANCEL_ENABLED + | THREAD_CANCEL_ASYNCHRONOUS; + if ((~flags & kFlags) == 0) + pthread_exit(PTHREAD_CANCELED); +} + + +// #pragma mark - public API + + int pthread_cancel(pthread_t thread) { - // TODO: notify thread of being cancelled. - fprintf(stderr, "pthread_cancel() is not yet implemented!\n"); - return EINVAL; + // set the canceled flag + int32 oldFlags = atomic_or(&thread->flags, THREAD_CANCELED); + + // If the flag was already set, we're done. + if ((oldFlags & THREAD_CANCELED) != 0) + return 0; + + // check whether the thread is supposed to be canceled asynchronously + static const int32 kFlags = THREAD_CANCEL_ENABLED + | THREAD_CANCEL_ASYNCHRONOUS; + + if ((~oldFlags & kFlags) == 0) { + // TODO: Cancel asynchronously! + } + + return 0; } int pthread_setcancelstate(int state, int *_oldState) { - if (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE) - return EINVAL; - pthread_thread* thread = pthread_self(); if (thread == NULL) return EINVAL; - if (_oldState != NULL) - *_oldState = thread->cancel_state; + // set the new flags + int32 oldFlags; + if (state == PTHREAD_CANCEL_ENABLE) { + oldFlags = atomic_or(&thread->flags, THREAD_CANCEL_ENABLED); + test_asynchronous_cancel(oldFlags | THREAD_CANCEL_ENABLED); + } else if (state == PTHREAD_CANCEL_DISABLE) { + oldFlags = atomic_and(&thread->flags, ~(int32)THREAD_CANCEL_ENABLED); + test_asynchronous_cancel(oldFlags); + } else + return EINVAL; - thread->cancel_state = state; + // return the old state + if (_oldState != NULL) { + *_oldState = (oldFlags & PTHREAD_CANCEL_ENABLE) != 0 + ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE; + } + return 0; } @@ -39,17 +75,28 @@ int pthread_setcanceltype(int type, int *_oldType) { - if (type != PTHREAD_CANCEL_DEFERRED && type != PTHREAD_CANCEL_ASYNCHRONOUS) - return EINVAL; - pthread_thread* thread = pthread_self(); if (thread == NULL) return EINVAL; - if (_oldType != NULL) - *_oldType = thread->cancel_type; + // set the new type + int32 oldFlags; + if (type == PTHREAD_CANCEL_DEFERRED) { + oldFlags = atomic_and(&thread->flags, + ~(int32)THREAD_CANCEL_ASYNCHRONOUS); + test_asynchronous_cancel(oldFlags); + } else if (type == PTHREAD_CANCEL_ASYNCHRONOUS) { + oldFlags = atomic_or(&thread->flags, THREAD_CANCEL_ASYNCHRONOUS); + test_asynchronous_cancel(oldFlags | THREAD_CANCEL_ASYNCHRONOUS); + } else + return EINVAL; - thread->cancel_type = type; + // return the old type + if (_oldType != NULL) { + *_oldType = (oldFlags & THREAD_CANCEL_ASYNCHRONOUS) != 0 + ? PTHREAD_CANCEL_ASYNCHRONOUS : PTHREAD_CANCEL_DEFERRED; + } + return 0; } @@ -61,7 +108,8 @@ if (thread == NULL) return; - if (thread->cancelled && thread->cancel_state == PTHREAD_CANCEL_ENABLE) + static const int32 kFlags = THREAD_CANCELED | THREAD_CANCEL_ENABLED; + + if ((~atomic_get(&thread->flags) & kFlags) == 0) pthread_exit(NULL); } -