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#pragma once 14 15/* An unmanaged semaphore; i.e. the caller stores the state related to the 16 * semaphore itself. This can be useful in scenarios such as CAmkES, where 17 * immediate concurrency means we have a race on initialising a managed 18 * semaphore. 19 */ 20 21#include <autoconf.h> 22#include <assert.h> 23#include <limits.h> 24#include <sel4/sel4.h> 25#ifdef CONFIG_DEBUG_BUILD 26#include <sel4debug/debug.h> 27#endif 28#include <stddef.h> 29#include <platsupport/sync/atomic.h> 30 31static inline int sync_sem_bare_wait(seL4_CPtr ep, volatile int *value) 32{ 33#ifdef CONFIG_DEBUG_BUILD 34 /* Check the cap actually is an EP. */ 35 assert(debug_cap_is_endpoint(ep)); 36#endif 37 assert(value != NULL); 38 int oldval; 39 int result = sync_atomic_decrement_safe(value, &oldval, __ATOMIC_ACQUIRE); 40 if (result != 0) { 41 /* Failed decrement; too many outstanding lock holders. */ 42 return -1; 43 } 44 if (oldval <= 0) { 45#ifdef CONFIG_ARCH_IA32 46#ifdef CONFIG_KERNEL_MCS 47 seL4_WaitWithMRs(ep, NULL, NULL); 48#else 49 seL4_RecvWithMRs(ep, NULL, NULL, NULL); 50#endif /* CONFIG_KERNEL_MCS */ 51#else // all other platforms have 4 mrs 52#ifdef CONFIG_KERNEL_MCS 53 seL4_WaitWithMRs(ep, NULL, NULL, NULL, NULL, NULL); 54#else 55 seL4_RecvWithMRs(ep, NULL, NULL, NULL, NULL, NULL); 56#endif 57 58#endif 59 /* Even though we performed an acquire barrier during the atomic 60 * decrement we did not actually have the lock yet, so we have 61 * to do another one now */ 62 __atomic_thread_fence(__ATOMIC_ACQUIRE); 63 } 64 return 0; 65} 66 67static inline int sync_sem_bare_trywait(UNUSED seL4_CPtr ep, volatile int *value) 68{ 69 int val = *value; 70 while (val > 0) { 71 if (__atomic_compare_exchange_n(value, &val, val - 1, 1, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) { 72 /* We got it! */ 73 return 0; 74 } 75 /* We didn't get it. */ 76 val = *value; 77 } 78 /* The semaphore is empty. */ 79 return -1; 80} 81 82static inline int sync_sem_bare_post(seL4_CPtr ep, volatile int *value) 83{ 84#ifdef CONFIG_DEBUG_BUILD 85 /* Check the cap actually is an EP. */ 86 assert(debug_cap_is_endpoint(ep)); 87#endif 88 assert(value != NULL); 89 /* We can do an "unsafe" increment here because we know the lock cannot be 90 * full due to ourselves having been able to acquire it. 91 */ 92 assert(*value < INT_MAX); 93 int v = sync_atomic_increment(value, __ATOMIC_RELEASE); 94 if (v <= 0) { 95 seL4_Signal(ep); 96 } 97 return 0; 98} 99 100