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