1 /* 2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #ifndef _PICO_SEM_H 8 #define _PICO_SEM_H 9 10 #include "pico/lock_core.h" 11 12 /** \file sem.h 13 * \defgroup sem sem 14 * \ingroup pico_sync 15 * \brief Semaphore API for restricting access to a resource 16 * 17 * A semaphore holds a number of available permits. `sem_acquire` methods will acquire a permit if available 18 * (reducing the available count by 1) or block if the number of available permits is 0. 19 * \ref sem_release() increases the number of available permits by one potentially unblocking a `sem_acquire` method. 20 * 21 * Note that \ref sem_release() may be called an arbitrary number of times, however the number of available 22 * permits is capped to the max_permit value specified during semaphore initialization. 23 * 24 * Although these semaphore related functions can be used from IRQ handlers, it is obviously preferable to only 25 * release semaphores from within an IRQ handler (i.e. avoid blocking) 26 */ 27 28 #ifdef __cplusplus 29 extern "C" { 30 #endif 31 typedef struct semaphore { 32 struct lock_core core; 33 int16_t permits; 34 int16_t max_permits; 35 } semaphore_t; 36 37 38 /*! \brief Initialise a semaphore structure 39 * \ingroup sem 40 * 41 * \param sem Pointer to semaphore structure 42 * \param initial_permits How many permits are initially acquired 43 * \param max_permits Total number of permits allowed for this semaphore 44 */ 45 void sem_init(semaphore_t *sem, int16_t initial_permits, int16_t max_permits); 46 47 /*! \brief Return number of available permits on the semaphore 48 * \ingroup sem 49 * 50 * \param sem Pointer to semaphore structure 51 * \return The number of permits available on the semaphore. 52 */ 53 int sem_available(semaphore_t *sem); 54 55 /*! \brief Release a permit on a semaphore 56 * \ingroup sem 57 * 58 * Increases the number of permits by one (unless the number of permits is already at the maximum). 59 * A blocked `sem_acquire` will be released if the number of permits is increased. 60 * 61 * \param sem Pointer to semaphore structure 62 * \return true if the number of permits available was increased. 63 */ 64 bool sem_release(semaphore_t *sem); 65 66 /*! \brief Reset semaphore to a specific number of available permits 67 * \ingroup sem 68 * 69 * Reset value should be from 0 to the max_permits specified in the init function 70 * 71 * \param sem Pointer to semaphore structure 72 * \param permits the new number of available permits 73 */ 74 void sem_reset(semaphore_t *sem, int16_t permits); 75 76 /*! \brief Acquire a permit from the semaphore 77 * \ingroup sem 78 * 79 * This function will block and wait if no permits are available. 80 * 81 * \param sem Pointer to semaphore structure 82 */ 83 void sem_acquire_blocking(semaphore_t *sem); 84 85 /*! \brief Acquire a permit from a semaphore, with timeout 86 * \ingroup sem 87 * 88 * This function will block and wait if no permits are available, until the 89 * defined timeout has been reached. If the timeout is reached the function will 90 * return false, otherwise it will return true. 91 * 92 * \param sem Pointer to semaphore structure 93 * \param timeout_ms Time to wait to acquire the semaphore, in milliseconds. 94 * \return false if timeout reached, true if permit was acquired. 95 */ 96 bool sem_acquire_timeout_ms(semaphore_t *sem, uint32_t timeout_ms); 97 98 /*! \brief Acquire a permit from a semaphore, with timeout 99 * \ingroup sem 100 * 101 * This function will block and wait if no permits are available, until the 102 * defined timeout has been reached. If the timeout is reached the function will 103 * return false, otherwise it will return true. 104 * 105 * \param sem Pointer to semaphore structure 106 * \param timeout_us Time to wait to acquire the semaphore, in microseconds. 107 * \return false if timeout reached, true if permit was acquired. 108 */ 109 bool sem_acquire_timeout_us(semaphore_t *sem, uint32_t timeout_us); 110 111 /*! \brief Wait to acquire a permit from a semaphore until a specific time 112 * \ingroup sem 113 * 114 * This function will block and wait if no permits are available, until the 115 * specified timeout time. If the timeout is reached the function will 116 * return false, otherwise it will return true. 117 * 118 * \param sem Pointer to semaphore structure 119 * \param until The time after which to return if the sem is not available. 120 * \return true if permit was acquired, false if the until time was reached before 121 * acquiring. 122 */ 123 bool sem_acquire_block_until(semaphore_t *sem, absolute_time_t until); 124 125 /*! \brief Attempt to acquire a permit from a semaphore without blocking 126 * \ingroup sem 127 * 128 * This function will return false without blocking if no permits are 129 * available, otherwise it will acquire a permit and return true. 130 * 131 * \param sem Pointer to semaphore structure 132 * \return true if permit was acquired. 133 */ 134 bool sem_try_acquire(semaphore_t *sem); 135 136 #ifdef __cplusplus 137 } 138 #endif 139 #endif 140