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