blob: c654ec24815d219bdad883f3c89d8f7ee43ab0e3 [file] [log] [blame]
/*
* Copyright 2014, NICTA
*
* This software may be distributed and modified according to the terms of
* the BSD 2-Clause license. Note that NO WARRANTY is provided.
* See "LICENSE_BSD2.txt" for details.
*
* @TAG(NICTA_BSD)
*/
#include <sync/recursive_mutex.h>
#include <stddef.h>
#include <assert.h>
#include <limits.h>
#include <sel4/sel4.h>
static void *thread_id(void) {
return (void*)seL4_GetIPCBuffer();
}
int sync_recursive_mutex_init(sync_recursive_mutex_t *mutex, seL4_CPtr notification) {
assert(mutex != NULL);
#ifdef SEL4_DEBUG_KERNEL
/* Check the cap actually is a notification. */
assert(seL4_DebugCapIdentify(notification) == 3);
#endif
mutex->notification = notification;
mutex->owner = NULL;
mutex->held = 0;
/* Prime the endpoint. */
seL4_Signal(mutex->notification);
return 0;
}
int sync_recursive_mutex_lock(sync_recursive_mutex_t *mutex) {
assert(mutex != NULL);
if (thread_id() != mutex->owner) {
/* We don't already have the mutex. */
(void)seL4_Wait(mutex->notification, NULL);
__atomic_thread_fence(__ATOMIC_ACQUIRE);
assert(mutex->owner == NULL);
mutex->owner = thread_id();
assert(mutex->held == 0);
}
if (mutex->held == UINT_MAX) {
/* We would overflow if we re-acquired the mutex. Note that we can only
* be in this branch if we already held the mutex before entering this
* function, so we don't need to release the mutex here.
*/
return -1;
}
mutex->held++;
return 0;
}
int sync_recursive_mutex_unlock(sync_recursive_mutex_t *mutex) {
assert(mutex != NULL);
assert(mutex->owner == thread_id());
assert(mutex->held > 0);
mutex->held--;
if (mutex->held == 0) {
/* This was the outermost lock we held. Wake the next person up. */
__atomic_store_n(&mutex->owner, NULL, __ATOMIC_RELEASE);
seL4_Signal(mutex->notification);
}
return 0;
}
int sync_recursive_mutex_destroy(sync_recursive_mutex_t *mutex) {
/* Nothing to be done. */
return 0;
}