1/*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ 2// ==== Semaphore Management ==== 3/** 4\addtogroup CMSIS_RTOS_SemaphoreMgmt Semaphores 5\ingroup CMSIS_RTOS 6\brief Access shared resources simultaneously from different threads. 7\details 8Semaphores are used to manage and protect access to shared resources. Semaphores are very similar to 9\ref CMSIS_RTOS_MutexMgmt "Mutexes". Whereas a Mutex permits just one thread to access a shared resource at a 10time, a semaphore can be used to permit a fixed number of threads/ISRs to access a pool of shared resources. Using 11semaphores, access to a group of identical peripherals can be managed (for example multiple DMA channels). 12 13\image html "Semaphore.png" "CMSIS-RTOS Semaphore" 14 15A semaphore object should be initialized to the maximum number of available tokens. This number of available resources is 16specified as parameter of the \ref osSemaphoreNew function. Each time a semaphore token is obtained with \ref osSemaphoreAcquire 17(in \em available state), the semaphore count is decremented. When the semaphore count is 0 (i.e. \em depleted state), no 18more semaphore tokens can be obtained. The thread/ISR that tries to obtain the semaphore token needs to wait until the next 19token is free. Semaphores are released with \ref osSemaphoreRelease incrementing the semaphore count. 20 21\image html "semaphore_states.png" "CMSIS-RTOS Semaphore States" 22 23\note The functions \ref osSemaphoreAcquire, \ref osSemaphoreGetCount, and \ref osSemaphoreRelease can be called from 24\ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routines". 25 26Semaphore Use Cases 27------------------- 28Due to their flexibility, semaphores cover a wide range of synchronizing applications. At the same time, they are perhaps the 29most challenging RTOS object to understand. The following explains a use case for semaphores, taken from the book 30<a href="https://greenteapress.com/wp/semaphores/" target="_blank">The Little Book Of Semaphores</a> by Allen B. Downey which 31is available for free download. 32 33<b>Non-binary Semaphore (Multiplex)</b> 34 35A multiplex limits the number of threads that can access a critical section of code. For example, this could be a function 36accessing DMA resources which can only support a limited number of calls. 37 38To allow multiple threads to run the function, initialize a semaphore to the maximum number of threads that can be allowed. 39The number of tokens in the semaphore represents the number of additional threads that may enter. If this number is zero, 40then the next thread trying to access the function will have to wait until one of the other threads exits and releases its 41token. When all threads have exited the token number is back to n. The following example shows the code for one of the 42threads that might access the resource: 43 44\code 45osSemaphoreId_t multiplex_id; 46 47void thread_n (void) { 48 49 multiplex_id = osSemaphoreNew(3U, 3U, NULL); 50 while(1) { 51 osSemaphoreAcquire(multiplex_id, osWaitForever); 52 // do something 53 osSemaphoreRelease(multiplex_id); 54 } 55} 56\endcode 57 58<b>Producer/Consumer Semaphore</b> 59 60The producer-consumer problem can be solved using two semaphores. 61 62A first semaphore (\token{empty_id}) counts down the available (empty) buffers, i.e. 63the producer thread can wait for available buffer slots by acquiring from this one. 64 65A second semaphore (\token{filled_id}) counts up the used (filled) buffers, i.e. 66the consumer thread can wait for available data by acquiring from this one. 67 68It is crucial for the correct behaviour that the threads acquire and release on both 69semaphores in the given sequence. According to this example one can have multiple 70producer and/or consumer threads running concurrently. 71 72\code 73#define BUFFER_SIZE 10U 74 75osSemaphoreId_t empty_id = osSemaphoreNew(BUFFER_SIZE, BUFFER_SIZE, NULL); 76osSemaphoreId_t filled_id = osSemaphoreNew(BUFFER_SIZE, 0U, NULL); 77 78void producer_thread (void) { 79 while(1) { 80 osSemaphoreAcquire(empty_id, osWaitForever); 81 // produce data 82 osSemaphoreRelease(filled_id); 83 } 84} 85 86void consumer_thread (void) { 87 88 while(1){ 89 osSemaphoreAcquire(filled_id, osWaitForever); 90 // consume data 91 osSemaphoreRelease(empty_id); 92 } 93} 94\endcode 95 96@{ 97*/ 98 99/*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ 100/** 101\typedef osSemaphoreId_t 102\details 103Returned by: 104- \ref osSemaphoreNew 105*/ 106 107/** 108\struct osSemaphoreAttr_t 109\details 110Specifies the following attributes for the \ref osSemaphoreNew function. 111*/ 112 113/*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ 114/** 115\fn osSemaphoreId_t osSemaphoreNew (uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr) 116\details 117The function \b osSemaphoreNew creates and initializes a semaphore object that is used to manage access to shared resources 118and returns the pointer to the semaphore object identifier or \token{NULL} in case of an error. It can be safely called 119before the RTOS is started (call to \ref osKernelStart), but not before it is initialized (call to \ref osKernelInitialize). 120 121The parameter \em max_count specifies the maximum number of available tokens. A \em max_count value of 1 creates a binary 122semaphore. 123 124The parameter \em initial_count sets the initial number of available tokens. 125 126The parameter \em attr specifies additional semaphore attributes. Default attributes will be used if set to \token{NULL}. 127 128\note This function \b cannot be called from \ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routines". 129 130<b>Code Example</b> 131\code 132#include "cmsis_os2.h" // CMSIS RTOS header file 133 134osSemaphoreId_t sid_Semaphore; // semaphore id 135 136osThreadId_t tid_Thread_Semaphore; // thread id 137 138void Thread_Semaphore (void *argument); // thread function 139 140int Init_Semaphore (void) { 141 142 sid_Semaphore = osSemaphoreNew(2U, 2U, NULL); 143 if (sid_Semaphore == NULL) { 144 ; // Semaphore object not created, handle failure 145 } 146 147 tid_Thread_Semaphore = osThreadNew(Thread_Semaphore, NULL, NULL); 148 if (tid_Thread_Semaphore == NULL) { 149 return(-1); 150 } 151 152 return(0); 153} 154 155void Thread_Semaphore (void *argument) { 156 osStatus_t val; 157 158 while (1) { 159 ; // Insert thread code here... 160 161 val = osSemaphoreAcquire(sid_Semaphore, 10U); // wait for max. 10 ticks for semaphore token to get available 162 switch (val) { 163 case osOK: 164 ; // Use protected code here... 165 osSemaphoreRelease(sid_Semaphore); // return a token back to a semaphore 166 break; 167 case osErrorResource: 168 break; 169 case osErrorParameter: 170 break; 171 default: 172 break; 173 } 174 175 osThreadYield(); // suspend thread 176 } 177} 178\endcode 179*/ 180 181/*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ 182/** 183\fn const char *osSemaphoreGetName (osSemaphoreId_t semaphore_id) 184\details 185The function \b osSemaphoreGetName returns the pointer to the name string of the semaphore identified by parameter \a 186semaphore_id or \token{NULL} in case of an error. 187 188\note This function may be called from \ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routines". 189*/ 190 191/*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ 192/** 193\fn osStatus_t osSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout) 194\details 195The blocking function \b osSemaphoreAcquire waits until a token of the semaphore object specified by parameter 196\a semaphore_id becomes available. If a token is available, the function instantly returns and decrements the token count. 197 198The parameter \a timeout specifies how long the system waits to acquire the token. While the system waits, the thread 199that is calling this function is put into the \ref ThreadStates "BLOCKED" state. The parameter \ref CMSIS_RTOS_TimeOutValue 200"timeout" can have the following values: 201 - when \a timeout is \token{0}, the function returns instantly (i.e. try semantics). 202 - when \a timeout is set to \b osWaitForever the function will wait for an infinite time until the semaphore becomes 203 available (i.e. wait semantics). 204 - all other values specify a time in kernel ticks for a timeout (i.e. timed-wait semantics). 205 206Possible \ref osStatus_t return values: 207 - \em osOK: the token has been obtained and the token count decremented. 208 - \em osErrorTimeout: the token could not be obtained in the given time. 209 - \em osErrorResource: the token could not be obtained when no \a timeout was specified. 210 - \em osErrorParameter: the parameter \a semaphore_id is \token{NULL} or invalid. 211 - \em osErrorSafetyClass: the calling thread safety class is lower than the safety class of the specified semaphore. 212 213\note May be called from \ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routines" if the parameter \a timeout is set to 214\token{0}. 215 216<b>Code Example</b> 217 218Refer to \ref osSemaphoreNew. 219*/ 220 221/*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ 222/** 223\fn osStatus_t osSemaphoreRelease (osSemaphoreId_t semaphore_id) 224\details 225The function \b osSemaphoreRelease releases a token of the semaphore object specified by parameter \a semaphore_id. Tokens 226can only be released up to the maximum count specified at creation time, see \ref osSemaphoreNew. Other threads that 227currently wait for a token of this semaphore object will be put into the \ref ThreadStates "READY" state. 228 229Possible \ref osStatus_t return values: 230 - \em osOK: the token has been released and the count incremented. 231 - \em osErrorResource: the token could not be released (maximum token count has been reached). 232 - \em osErrorParameter: the parameter \a semaphore_id is \token{NULL} or invalid. 233 - \em osErrorSafetyClass: the calling thread safety class is lower than the safety class of the specified semaphore. 234 235\note This function may be called from \ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routines". 236 237<b>Code Example</b> 238 239Refer to \ref osSemaphoreNew. 240*/ 241 242/*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ 243/** 244\fn uint32_t osSemaphoreGetCount (osSemaphoreId_t semaphore_id) 245\details 246The function \b osSemaphoreGetCount returns the number of available tokens of the semaphore object specified by parameter 247\a semaphore_id. In case of an error it returns \token{0}. 248 249\note This function may be called from \ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routines". 250*/ 251 252/*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/ 253/** 254\fn osStatus_t osSemaphoreDelete (osSemaphoreId_t semaphore_id) 255\details 256The function \b osSemaphoreDelete deletes a semaphore object specified by parameter \a semaphore_id. It releases internal 257memory obtained for semaphore handling. After this call, the \a semaphore_id is no longer valid and cannot be used. The 258semaphore may be created again using the function \ref osSemaphoreNew. 259 260Possible \ref osStatus_t return values: 261 - \em osOK: the semaphore object has been deleted. 262 - \em osErrorParameter: the parameter \a semaphore_id is \token{NULL} or invalid. 263 - \em osErrorResource: the semaphore is in an invalid state. 264 - \em osErrorISR: \b osSemaphoreDelete cannot be called from interrupt service routines. 265 - \em osErrorSafetyClass: the calling thread safety class is lower than the safety class of the specified semaphore. 266 267\note This function \b cannot be called from \ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routines". 268*/ 269/// @} 270 271// these struct members must stay outside the group to avoid double entries in documentation 272/** 273\var osSemaphoreAttr_t::attr_bits 274\details 275Reserved for future use (must be set to '0' for future compatibility). 276 277\var osSemaphoreAttr_t::cb_mem 278\details 279Pointer to a memory for the semaphore control block object. Refer to \ref CMSIS_RTOS_MemoryMgmt_Manual for more information. 280 281Default: \token{NULL} to use \ref CMSIS_RTOS_MemoryMgmt_Automatic for the semaphore control block. 282 283\var osSemaphoreAttr_t::cb_size 284\details 285The size (in bytes) of memory block passed with \ref cb_mem. Required value depends on the underlying kernel implementation. 286 287Default: \token{0} as the default is no memory provided with \ref cb_mem. 288 289\var osSemaphoreAttr_t::name 290\details 291Pointer to a constant string with a human readable name (displayed during debugging) of the semaphore object. 292 293Default: \token{NULL} no name specified. 294*/ 295