1 /**
2  * Copyright (c) 2015, Realtek Semiconductor Corporation. All rights reserved.
3  */
4 
5 #ifndef _OS_SYNC_H_
6 #define _OS_SYNC_H_
7 
8 #include <stdint.h>
9 #include <stdbool.h>
10 
11 #ifdef __cplusplus
12 extern "C" {
13 #endif
14 
15 /**
16  * \addtogroup  OS                  OSIF
17  * \defgroup    Synchronization     Inter-Task Communication
18  *
19  * \brief   Manage Inter-task communication functions.
20  * \details Tasks need to communicate with each other or access shared resources together.
21  *          There are many ways to exchange data between tasks, for example using shared
22  *          data, polling loops and message passing.\n
23  *          Many resources can be considered as serially-reusable. This means that they
24  *          can be used repeatedly by different tasks, but only by one task at a time.\n
25  *          The following mechanisms are available to the user:\n
26  * \arg <b>Lock</b>
27  * \arg <b>Semaphore</b>
28  * \arg <b>Mutex</b>
29  *
30  * \ingroup     OS
31  */
32 
33 
34 /**
35  * os_sync.h
36  *
37  * \brief   Enter the critical region. Disable preemptive context switch and interrupts.
38  *
39  * \param   None
40  *
41  * \return      Interrupt mask flag.
42  *
43  * <b>Example usage</b>
44  * \code{.c}
45  * int test(void)
46  * {
47  *     uint32_t s;
48  *
49  *     // Enter the critical section.
50  *     s = os_lock();
51  *     // Allow only one task or ISR to operate the list.
52  *     list_add(p_list, &item);
53  *     // Exit the critical section and restore ISR mask flag.
54  *     os_unlock(s);
55  * }
56  * \endcode
57  *
58  * \ingroup  Synchronization
59  */
60 uint32_t os_lock(void);
61 
62 /**
63  * os_sync.h
64  *
65  * \brief   Exit the critical region. Enable preemptive context switch and interrupts.
66  *
67  * \param[in]   s   Interrupt mask flag to be restored.
68  *
69  * \return      None.
70  *
71  * <b>Example usage</b>
72  * \code{.c}
73  * int test(void)
74  * {
75  *     uint32_t s;
76  *
77  *     // Enter the critical section.
78  *     s = os_lock();
79  *     // Allow only one task or ISR to operate the list.
80  *     list_add(p_list, &item);
81  *     // Exit the critical section and restore ISR mask flag.
82  *     os_unlock(s);
83  * }
84  * \endcode
85  *
86  * \ingroup  Synchronization
87  */
88 void os_unlock(uint32_t s);
89 
90 /**
91  * os_sync.h
92  *
93  * \brief   Create a counting semaphore.
94  *
95  * \details Semaphores are used to manage and protect access to shared resources. A semaphore
96  *          can be used to permit a fixed number of task to access a pool of shared resources.
97  *          Using semaphores.\n
98  *          A semaphore object should be initialized to the maximum number of available tokens.
99  *          This number of available resources is specified as parameter of the os_sem_create()
100  *          function. Each time a semaphore token is obtained with os_sem_take(), the semaphore
101  *          count is decremented. When the semaphore count is 0, no semaphore token can be obtained.
102  *          The task that tries to obtain the semaphore token needs to wait until the next token
103  *          is free. Semaphores are released with os_sem_give() incrementing the semaphore count.
104  *
105  * \image html OS-semaphore-overview.jpg "Semaphore Overview" width=496px height=346px
106  *
107  * \param[out]  pp_handle   Used to pass back the created semaphore handle.
108  *
109  * \param[in]   init_count  The count value assigned to the semaphore when created.
110  *
111  * \param[in]   max_count   The maximum count value that can be reached. If the max_count is 1,
112  *                          a binary semaphore is being created.
113  *
114  * \return           The status of the semaphore creation.
115  * \retval true      Semaphore was created successfully.
116  * \retval false     Semaphore was failed to create.
117  *
118  * <b>Example usage</b>
119  * \code{.c}
120  * int test(void)
121  * {
122  *     void *p_handle;
123  *
124  *     // Create a semaphore with initial value 0 and maximum value 10.
125  *     if (os_sem_create(&p_handle, 0, 10) == true)
126  *     {
127  *         // Semaphore created successfully.
128  *     }
129  *     else
130  *     {
131  *         // Semaphore failed to create.
132  *         return -1;
133  *     }
134  *
135  *     return 0;
136  * }
137  * \endcode
138  *
139  * \ingroup  Synchronization
140  */
141 bool os_sem_create(void **pp_handle, uint32_t init_count, uint32_t max_count);
142 
143 /**
144  * os_sync.h
145  *
146  * \brief   Delete a semaphore.
147  *
148  * \param[in]   p_handle    The handle of the semaphore to be deleted.
149  *
150  * \return           The status of the semaphore deletion.
151  * \retval true      Semaphore was deleted successfully.
152  * \retval false     Semaphore was failed to delete.
153  *
154  * <b>Example usage</b>
155  * \code{.c}
156  * int test(void)
157  * {
158  *     void *p_handle;
159  *
160  *     // Create a semaphore with initial value 0 and maximum value 10.
161  *     if (os_sem_create(&p_handle, 0, 10) == true)
162  *     {
163  *         // Semaphore created successfully.
164  *     }
165  *     else
166  *     {
167  *         // Semaphore failed to create.
168  *         return -1;
169  *     }
170  *
171  *     // Delete the created semaphore.
172  *     os_sem_delete(p_handle);
173  *
174  *     return 0;
175  * }
176  * \endcode
177  *
178  * \ingroup  Synchronization
179  */
180 bool os_sem_delete(void *p_handle);
181 
182 /**
183  * os_sync.h
184  *
185  * \brief   Take a semaphore.
186  *
187  * \param[in]   p_handle    The handle of the semaphore to be taken.
188  *
189  * \param[in]   wait_ms     The time in milliseconds to wait for the semaphore to become
190  *                          available.
191  * \arg \c 0           No blocking and return immediately.
192  * \arg \c 0xFFFFFFFF  Block infinitely until the semaphore taken.
193  * \arg \c others      The timeout value in milliseconds.
194  *
195  * \return           The status of the semaphore taking.
196  * \retval true      Semaphore was taken successfully.
197  * \retval false     Semaphore was failed to take.
198  *
199  * <b>Example usage</b>
200  * \code{.c}
201  * void *p_handle = NULL;
202  *
203  * // One task creates a semaphore.
204  * void task1(void *p_param)
205  * {
206  *     // Create a full binary semaphore.
207  *     os_sem_create(&p_handle, 1, 1);
208  * }
209  *
210  * // Anohter task uses the semaphore.
211  * void task2(void *p_param)
212  * {
213  *     // See if we can obtain the semaphore. If the semaphore is
214  *     // not available, wait for 100ms.
215  *     if (os_sem_take(p_handle, 100) == true)
216  *     {
217  *         // Access the share resource.
218  *
219  *         // Finish accessing the share resource, then release the semaphore.
220  *         os_sem_give(p_handle);
221  *     }
222  *     else
223  *     {
224  *         // Could not access the share resource.
225  *     }
226  * }
227  * \endcode
228  *
229  * \ingroup  Synchronization
230  */
231 bool os_sem_take(void *p_handle, uint32_t wait_ms);
232 
233 /**
234  * os_sync.h
235  *
236  * \brief   Give a semaphore.
237  *
238  * \param[in]   p_handle    The handle of the semaphore to be given.
239  *
240  * \return           The status of the semaphore giving.
241  * \retval true      Semaphore was given successfully.
242  * \retval false     Semaphore was failed to give.
243  *
244  * <b>Example usage</b>
245  * \code{.c}
246  * int test(void)
247  * {
248  *     void *p_handle = NULL;
249  *
250  *     // Create an empty binary semaphore.
251  *     os_sem_create(&p_handle, 0, 1);
252  *
253  *     // Obtaining the empty semaphore immediately will be failed.
254  *     if (os_sem_take(p_handle, 0) == false)
255  *     {
256  *         // Failed.
257  *     }
258  *
259  *     // Give the sempahore
260  *     if (os_sem_give(p_hanel) == true)
261  *     {
262  *         // Now we can take the semaphore.
263  *         os_sem_take(p_handle, 0);
264  *
265  *         // Again taking the binary semaphore will be failed.
266  *         os_sem_take(p_handle, 0);
267  *     }
268  * }
269  * \endcode
270  *
271  * \ingroup  Synchronization
272  */
273 bool os_sem_give(void *p_handle);
274 
275 /**
276  * os_sync.h
277  *
278  * \brief   Create a mutex.
279  *
280  * \details Mutex (Mutual Exclusion) is used to protect a shared resource that can be accessed
281  *          only by one task at a time.\n
282  *          A mutex is a special version of a binary empty semaphore. The advantage of a mutex
283  *          is that it introduces task ownership. When a task acquires a mutex and becomes its
284  *          owner, subsequent mutex acquires from that task will succeed immediately. Thus, mutex
285  *          acquires/releases can be nested.\n
286  *
287  * \image html OS-mutex-overview.jpg "Mutex Overview" width=451px height=196px
288  *
289  * \param[out]  pp_handle   Used to pass back the created mutex handle.
290  *
291  * \return           The status of the mutex creation.
292  * \retval true      Mutex was created successfully.
293  * \retval false     Mutex was failed to create.
294  *
295  * <b>Example usage</b>
296  * \code{.c}
297  * int test(void)
298  * {
299  *     void *p_handle = NULL;
300  *
301  *     // Create a mutex.
302  *     if (os_mutex_create(&p_handle) == true)
303  *     {
304  *         // The mutex created successfully.
305  *         // Now it can be used.
306  *     }
307  * }
308  * \endcode
309  *
310  * \ingroup  Synchronization
311  */
312 bool os_mutex_create(void **pp_handle);
313 
314 /**
315  * os_sync.h
316  *
317  * \brief   Delete a mutex.
318  *
319  * \param[in]   p_handle    The handle of the mutex to be deleted.
320  *
321  * \return           The status of the Mutex deletion.
322  * \retval true      Mutex was deleted successfully.
323  * \retval false     Mutex was failed to delete.
324  *
325  * <b>Example usage</b>
326  * \code{.c}
327  * int test(void)
328  * {
329  *     void *p_handle;
330  *
331  *     // Create a mutex.
332  *     if (os_mutex_create(&p_handle) == true)
333  *     {
334  *         // Mutex created successfully.
335  *     }
336  *     else
337  *     {
338  *         // Mutex failed to create.
339  *         return -1;
340  *     }
341  *
342  *     // Delete the created mutex.
343  *     os_mutex_delete(p_handle);
344  *
345  *     return 0;
346  * }
347  * \endcode
348  *
349  * \ingroup  Synchronization
350  */
351 bool os_mutex_delete(void *p_handle);
352 
353 /**
354  * os_sync.h
355  *
356  * \brief   Take a mutex.
357  *
358  * \param[in]   p_handle    The handle of the mutex to be taken.
359  *
360  * \param[in]   wait_ms     The time in milliseconds to wait for the mutex to become
361  *                          available.
362  * \arg \c 0           No blocking and return immediately.
363  * \arg \c 0xFFFFFFFF  Block infinitely until the mutex taken.
364  * \arg \c others      The timeout value in milliseconds.
365  *
366  * \return           The status of the mutex taking.
367  * \retval true      Mutex was taken successfully.
368  * \retval false     Mutex was failed to take.
369  *
370  * <b>Example usage</b>
371  * \code{.c}
372  * void *p_handle = NULL;
373  *
374  * // One task creates a mutex.
375  * void task1(void *p_param)
376  * {
377  *     // Create a mutex.
378  *     os_mutex_create(&p_handle);
379  * }
380  *
381  * // Anohter task uses the mutex.
382  * void task2(void *p_param)
383  * {
384  *     // See if we can obtain the mutex. If the mutex is
385  *     // not available, wait for 100ms.
386  *     if (os_mutex_take(p_handle, 100) == true)
387  *     {
388  *         // Access the share resource.
389  *
390  *         // In real code, recursive calls of mutex may occur.
391  *         os_mutex_take(p_handle, 100);
392  *         os_mutex_take(p_handle, 200);
393  *
394  *         // The mutex has now been 'taken' three times, so will not be
395  *         // available to another task until it has also been given back
396  *         // three times.
397  *         os_mutex_give(p_handle);
398  *         os_mutex_give(p_handle);
399  *         os_mutex_give(p_handle);
400  *
401  *         // Finish accessing the share resource, then release the semaphore.
402  *         // Now the mutex can be taken by other tasks.
403  *     }
404  *     else
405  *     {
406  *         // Could not access the share resource.
407  *     }
408  * }
409  * \endcode
410  *
411  * \ingroup  Synchronization
412  */
413 bool os_mutex_take(void *p_handle, uint32_t wait_ms);
414 
415 /**
416  * os_sync.h
417  *
418  * \brief   Give a mutex.
419  *
420  * \param[in]   p_handle    The handle of the mutex to be given.
421  *
422  * \return           The status of the mutex giving.
423  * \retval true      Mutex was given successfully.
424  * \retval false     Mutex was failed to give.
425  *
426  * <b>Example usage</b>
427  * \code{.c}
428  * void *p_handle = NULL;
429  *
430  * // One task creates a mutex.
431  * void task1(void *p_param)
432  * {
433  *     // Create a mutex.
434  *     os_mutex_create(&p_handle);
435  * }
436  *
437  * // Anohter task uses the mutex.
438  * void task2(void *p_param)
439  * {
440  *     // See if we can obtain the mutex. If the mutex is
441  *     // not available, wait for 100ms.
442  *     if (os_mutex_take(p_handle, 100) == true)
443  *     {
444  *         // Access the share resource.
445  *
446  *         // In real code, recursive calls of mutex may occur.
447  *         os_mutex_take(p_handle, 100);
448  *         os_mutex_take(p_handle, 200);
449  *
450  *         // The mutex has now been 'taken' three times, so will not be
451  *         // available to another task until it has also been given back
452  *         // three times.
453  *         os_mutex_give(p_handle);
454  *         os_mutex_give(p_handle);
455  *         os_mutex_give(p_handle);
456  *
457  *         // Finish accessing the share resource, then release the semaphore.
458  *         // Now the mutex can be taken by other tasks.
459  *     }
460  *     else
461  *     {
462  *         // Could not access the share resource.
463  *     }
464  * }
465  * \endcode
466  *
467  * \ingroup  Synchronization
468  */
469 bool os_mutex_give(void *p_handle);
470 
471 #ifdef __cplusplus
472 }
473 #endif
474 
475 #endif /* _OS_SYNC_H_ */
476