* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2008, Axel DΓΆrfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "pthread_private.h"
#include <syscalls.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);
}
Has the simple signal handler signature, since it is invoked just like a
signal handler.
*/
static void
asynchronous_cancel_thread(int)
{
pthread_t thread = pthread_self();
if ((atomic_get(&thread->flags) & THREAD_CANCEL_ASYNCHRONOUS) != 0)
pthread_exit(PTHREAD_CANCELED);
}
int
pthread_cancel(pthread_t thread)
{
int32 oldFlags = atomic_or(&thread->flags, THREAD_CANCELED);
if ((oldFlags & THREAD_CANCELED) != 0)
return 0;
if ((oldFlags & THREAD_CANCEL_ENABLED) != 0) {
int result = _kern_cancel_thread(thread->id, &asynchronous_cancel_thread);
if (result == B_BAD_THREAD_ID)
return ESRCH;
return result;
}
return 0;
}
int
pthread_setcancelstate(int state, int *_oldState)
{
pthread_thread* thread = pthread_self();
if (thread == NULL)
return EINVAL;
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;
if (_oldState != NULL) {
*_oldState = (oldFlags & THREAD_CANCEL_ENABLED) != 0
? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE;
}
return 0;
}
int
pthread_setcanceltype(int type, int *_oldType)
{
pthread_thread* thread = pthread_self();
if (thread == NULL)
return EINVAL;
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;
if (_oldType != NULL) {
*_oldType = (oldFlags & THREAD_CANCEL_ASYNCHRONOUS) != 0
? PTHREAD_CANCEL_ASYNCHRONOUS : PTHREAD_CANCEL_DEFERRED;
}
return 0;
}
void
pthread_testcancel(void)
{
pthread_thread* thread = pthread_self();
if (thread == NULL)
return;
static const int32 kFlags = THREAD_CANCELED | THREAD_CANCEL_ENABLED;
if ((~atomic_get(&thread->flags) & kFlags) == 0)
pthread_exit(PTHREAD_CANCELED);
}