1/* 2 * Copyright 2017, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12 13#include <autoconf.h> 14#include <sync/recursive_mutex.h> 15#include <stddef.h> 16#include <assert.h> 17#include <limits.h> 18 19#include <sel4/sel4.h> 20#ifdef CONFIG_DEBUG_BUILD 21#include <sel4debug/debug.h> 22#endif 23 24static void *thread_id(void) 25{ 26 return (void *)seL4_GetIPCBuffer(); 27} 28 29int sync_recursive_mutex_init(sync_recursive_mutex_t *mutex, seL4_CPtr notification) 30{ 31 if (mutex == NULL) { 32 ZF_LOGE("Mutex passed to sync_recursive_mutex_init is NULL"); 33 return -1; 34 } 35#ifdef CONFIG_DEBUG_BUILD 36 /* Check the cap actually is a notification. */ 37 assert(debug_cap_is_notification(notification)); 38#endif 39 40 mutex->notification.cptr = notification; 41 mutex->owner = NULL; 42 mutex->held = 0; 43 44 /* Prime the endpoint. */ 45 seL4_Signal(mutex->notification.cptr); 46 return 0; 47} 48 49int sync_recursive_mutex_lock(sync_recursive_mutex_t *mutex) 50{ 51 if (mutex == NULL) { 52 ZF_LOGE("Mutex passed to sync_recursive_mutex_lock is NULL"); 53 return -1; 54 } 55 if (thread_id() != mutex->owner) { 56 /* We don't already have the mutex. */ 57 seL4_Wait(mutex->notification.cptr, NULL); 58 __atomic_thread_fence(__ATOMIC_ACQUIRE); 59 assert(mutex->owner == NULL); 60 mutex->owner = thread_id(); 61 assert(mutex->held == 0); 62 } 63 if (mutex->held == UINT_MAX) { 64 /* We would overflow if we re-acquired the mutex. Note that we can only 65 * be in this branch if we already held the mutex before entering this 66 * function, so we don't need to release the mutex here. 67 */ 68 return -1; 69 } 70 mutex->held++; 71 return 0; 72} 73 74int sync_recursive_mutex_unlock(sync_recursive_mutex_t *mutex) 75{ 76 if (mutex == NULL) { 77 ZF_LOGE("Mutex passed to sync_recursive_mutex_lock is NULL"); 78 return -1; 79 } 80 assert(mutex->owner == thread_id()); 81 assert(mutex->held > 0); 82 mutex->held--; 83 if (mutex->held == 0) { 84 /* This was the outermost lock we held. Wake the next person up. */ 85 __atomic_store_n(&mutex->owner, NULL, __ATOMIC_RELEASE); 86 seL4_Signal(mutex->notification.cptr); 87 } 88 return 0; 89} 90 91int sync_recursive_mutex_new(vka_t *vka, sync_recursive_mutex_t *mutex) 92{ 93 int error = vka_alloc_notification(vka, &(mutex->notification)); 94 95 if (error != 0) { 96 return error; 97 } else { 98 return sync_recursive_mutex_init(mutex, mutex->notification.cptr); 99 } 100} 101 102int sync_recursive_mutex_destroy(vka_t *vka, sync_recursive_mutex_t *mutex) 103{ 104 vka_free_object(vka, &(mutex->notification)); 105 return 0; 106} 107