rtx_semaphore.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. /*
  2. * Copyright (c) 2013-2021 Arm Limited. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the License); you may
  7. * not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an AS IS BASIS, WITHOUT
  14. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. *
  18. * -----------------------------------------------------------------------------
  19. *
  20. * Project: CMSIS-RTOS RTX
  21. * Title: Semaphore functions
  22. *
  23. * -----------------------------------------------------------------------------
  24. */
  25. #include "rtx_lib.h"
  26. // OS Runtime Object Memory Usage
  27. #ifdef RTX_OBJ_MEM_USAGE
  28. osRtxObjectMemUsage_t osRtxSemaphoreMemUsage \
  29. __attribute__((section(".data.os.semaphore.obj"))) =
  30. { 0U, 0U, 0U };
  31. #endif
  32. // ==== Helper functions ====
  33. /// Decrement Semaphore tokens.
  34. /// \param[in] semaphore semaphore object.
  35. /// \return 1 - success, 0 - failure.
  36. static uint32_t SemaphoreTokenDecrement (os_semaphore_t *semaphore) {
  37. #if (EXCLUSIVE_ACCESS == 0)
  38. uint32_t primask = __get_PRIMASK();
  39. #endif
  40. uint32_t ret;
  41. #if (EXCLUSIVE_ACCESS == 0)
  42. __disable_irq();
  43. if (semaphore->tokens != 0U) {
  44. semaphore->tokens--;
  45. ret = 1U;
  46. } else {
  47. ret = 0U;
  48. }
  49. if (primask == 0U) {
  50. __enable_irq();
  51. }
  52. #else
  53. if (atomic_dec16_nz(&semaphore->tokens) != 0U) {
  54. ret = 1U;
  55. } else {
  56. ret = 0U;
  57. }
  58. #endif
  59. return ret;
  60. }
  61. /// Increment Semaphore tokens.
  62. /// \param[in] semaphore semaphore object.
  63. /// \return 1 - success, 0 - failure.
  64. static uint32_t SemaphoreTokenIncrement (os_semaphore_t *semaphore) {
  65. #if (EXCLUSIVE_ACCESS == 0)
  66. uint32_t primask = __get_PRIMASK();
  67. #endif
  68. uint32_t ret;
  69. #if (EXCLUSIVE_ACCESS == 0)
  70. __disable_irq();
  71. if (semaphore->tokens < semaphore->max_tokens) {
  72. semaphore->tokens++;
  73. ret = 1U;
  74. } else {
  75. ret = 0U;
  76. }
  77. if (primask == 0U) {
  78. __enable_irq();
  79. }
  80. #else
  81. if (atomic_inc16_lt(&semaphore->tokens, semaphore->max_tokens) < semaphore->max_tokens) {
  82. ret = 1U;
  83. } else {
  84. ret = 0U;
  85. }
  86. #endif
  87. return ret;
  88. }
  89. // ==== Post ISR processing ====
  90. /// Semaphore post ISR processing.
  91. /// \param[in] semaphore semaphore object.
  92. static void osRtxSemaphorePostProcess (os_semaphore_t *semaphore) {
  93. os_thread_t *thread;
  94. // Check if Thread is waiting for a token
  95. if (semaphore->thread_list != NULL) {
  96. // Try to acquire token
  97. if (SemaphoreTokenDecrement(semaphore) != 0U) {
  98. // Wakeup waiting Thread with highest Priority
  99. thread = osRtxThreadListGet(osRtxObject(semaphore));
  100. osRtxThreadWaitExit(thread, (uint32_t)osOK, FALSE);
  101. EvrRtxSemaphoreAcquired(semaphore, semaphore->tokens);
  102. }
  103. }
  104. }
  105. // ==== Service Calls ====
  106. /// Create and Initialize a Semaphore object.
  107. /// \note API identical to osSemaphoreNew
  108. static osSemaphoreId_t svcRtxSemaphoreNew (uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr) {
  109. os_semaphore_t *semaphore;
  110. uint8_t flags;
  111. const char *name;
  112. // Check parameters
  113. if ((max_count == 0U) || (max_count > osRtxSemaphoreTokenLimit) || (initial_count > max_count)) {
  114. EvrRtxSemaphoreError(NULL, (int32_t)osErrorParameter);
  115. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  116. return NULL;
  117. }
  118. // Process attributes
  119. if (attr != NULL) {
  120. name = attr->name;
  121. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
  122. semaphore = attr->cb_mem;
  123. if (semaphore != NULL) {
  124. //lint -e(923) -e(9078) "cast from pointer to unsigned int" [MISRA Note 7]
  125. if ((((uint32_t)semaphore & 3U) != 0U) || (attr->cb_size < sizeof(os_semaphore_t))) {
  126. EvrRtxSemaphoreError(NULL, osRtxErrorInvalidControlBlock);
  127. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  128. return NULL;
  129. }
  130. } else {
  131. if (attr->cb_size != 0U) {
  132. EvrRtxSemaphoreError(NULL, osRtxErrorInvalidControlBlock);
  133. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  134. return NULL;
  135. }
  136. }
  137. } else {
  138. name = NULL;
  139. semaphore = NULL;
  140. }
  141. // Allocate object memory if not provided
  142. if (semaphore == NULL) {
  143. if (osRtxInfo.mpi.semaphore != NULL) {
  144. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
  145. semaphore = osRtxMemoryPoolAlloc(osRtxInfo.mpi.semaphore);
  146. } else {
  147. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
  148. semaphore = osRtxMemoryAlloc(osRtxInfo.mem.common, sizeof(os_semaphore_t), 1U);
  149. }
  150. #ifdef RTX_OBJ_MEM_USAGE
  151. if (semaphore != NULL) {
  152. uint32_t used;
  153. osRtxSemaphoreMemUsage.cnt_alloc++;
  154. used = osRtxSemaphoreMemUsage.cnt_alloc - osRtxSemaphoreMemUsage.cnt_free;
  155. if (osRtxSemaphoreMemUsage.max_used < used) {
  156. osRtxSemaphoreMemUsage.max_used = used;
  157. }
  158. }
  159. #endif
  160. flags = osRtxFlagSystemObject;
  161. } else {
  162. flags = 0U;
  163. }
  164. if (semaphore != NULL) {
  165. // Initialize control block
  166. semaphore->id = osRtxIdSemaphore;
  167. semaphore->flags = flags;
  168. semaphore->name = name;
  169. semaphore->thread_list = NULL;
  170. semaphore->tokens = (uint16_t)initial_count;
  171. semaphore->max_tokens = (uint16_t)max_count;
  172. // Register post ISR processing function
  173. osRtxInfo.post_process.semaphore = osRtxSemaphorePostProcess;
  174. EvrRtxSemaphoreCreated(semaphore, semaphore->name);
  175. } else {
  176. EvrRtxSemaphoreError(NULL,(int32_t)osErrorNoMemory);
  177. }
  178. return semaphore;
  179. }
  180. /// Get name of a Semaphore object.
  181. /// \note API identical to osSemaphoreGetName
  182. static const char *svcRtxSemaphoreGetName (osSemaphoreId_t semaphore_id) {
  183. os_semaphore_t *semaphore = osRtxSemaphoreId(semaphore_id);
  184. // Check parameters
  185. if ((semaphore == NULL) || (semaphore->id != osRtxIdSemaphore)) {
  186. EvrRtxSemaphoreGetName(semaphore, NULL);
  187. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  188. return NULL;
  189. }
  190. EvrRtxSemaphoreGetName(semaphore, semaphore->name);
  191. return semaphore->name;
  192. }
  193. /// Acquire a Semaphore token or timeout if no tokens are available.
  194. /// \note API identical to osSemaphoreAcquire
  195. static osStatus_t svcRtxSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout) {
  196. os_semaphore_t *semaphore = osRtxSemaphoreId(semaphore_id);
  197. osStatus_t status;
  198. // Check parameters
  199. if ((semaphore == NULL) || (semaphore->id != osRtxIdSemaphore)) {
  200. EvrRtxSemaphoreError(semaphore, (int32_t)osErrorParameter);
  201. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  202. return osErrorParameter;
  203. }
  204. // Try to acquire token
  205. if (SemaphoreTokenDecrement(semaphore) != 0U) {
  206. EvrRtxSemaphoreAcquired(semaphore, semaphore->tokens);
  207. status = osOK;
  208. } else {
  209. // No token available
  210. if (timeout != 0U) {
  211. EvrRtxSemaphoreAcquirePending(semaphore, timeout);
  212. // Suspend current Thread
  213. if (osRtxThreadWaitEnter(osRtxThreadWaitingSemaphore, timeout)) {
  214. osRtxThreadListPut(osRtxObject(semaphore), osRtxThreadGetRunning());
  215. } else {
  216. EvrRtxSemaphoreAcquireTimeout(semaphore);
  217. }
  218. status = osErrorTimeout;
  219. } else {
  220. EvrRtxSemaphoreNotAcquired(semaphore);
  221. status = osErrorResource;
  222. }
  223. }
  224. return status;
  225. }
  226. /// Release a Semaphore token that was acquired by osSemaphoreAcquire.
  227. /// \note API identical to osSemaphoreRelease
  228. static osStatus_t svcRtxSemaphoreRelease (osSemaphoreId_t semaphore_id) {
  229. os_semaphore_t *semaphore = osRtxSemaphoreId(semaphore_id);
  230. os_thread_t *thread;
  231. osStatus_t status;
  232. // Check parameters
  233. if ((semaphore == NULL) || (semaphore->id != osRtxIdSemaphore)) {
  234. EvrRtxSemaphoreError(semaphore, (int32_t)osErrorParameter);
  235. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  236. return osErrorParameter;
  237. }
  238. // Check if Thread is waiting for a token
  239. if (semaphore->thread_list != NULL) {
  240. EvrRtxSemaphoreReleased(semaphore, semaphore->tokens);
  241. // Wakeup waiting Thread with highest Priority
  242. thread = osRtxThreadListGet(osRtxObject(semaphore));
  243. osRtxThreadWaitExit(thread, (uint32_t)osOK, TRUE);
  244. EvrRtxSemaphoreAcquired(semaphore, semaphore->tokens);
  245. status = osOK;
  246. } else {
  247. // Try to release token
  248. if (SemaphoreTokenIncrement(semaphore) != 0U) {
  249. EvrRtxSemaphoreReleased(semaphore, semaphore->tokens);
  250. status = osOK;
  251. } else {
  252. EvrRtxSemaphoreError(semaphore, osRtxErrorSemaphoreCountLimit);
  253. status = osErrorResource;
  254. }
  255. }
  256. return status;
  257. }
  258. /// Get current Semaphore token count.
  259. /// \note API identical to osSemaphoreGetCount
  260. static uint32_t svcRtxSemaphoreGetCount (osSemaphoreId_t semaphore_id) {
  261. os_semaphore_t *semaphore = osRtxSemaphoreId(semaphore_id);
  262. // Check parameters
  263. if ((semaphore == NULL) || (semaphore->id != osRtxIdSemaphore)) {
  264. EvrRtxSemaphoreGetCount(semaphore, 0U);
  265. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  266. return 0U;
  267. }
  268. EvrRtxSemaphoreGetCount(semaphore, semaphore->tokens);
  269. return semaphore->tokens;
  270. }
  271. /// Delete a Semaphore object.
  272. /// \note API identical to osSemaphoreDelete
  273. static osStatus_t svcRtxSemaphoreDelete (osSemaphoreId_t semaphore_id) {
  274. os_semaphore_t *semaphore = osRtxSemaphoreId(semaphore_id);
  275. os_thread_t *thread;
  276. // Check parameters
  277. if ((semaphore == NULL) || (semaphore->id != osRtxIdSemaphore)) {
  278. EvrRtxSemaphoreError(semaphore, (int32_t)osErrorParameter);
  279. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  280. return osErrorParameter;
  281. }
  282. // Unblock waiting threads
  283. if (semaphore->thread_list != NULL) {
  284. do {
  285. thread = osRtxThreadListGet(osRtxObject(semaphore));
  286. osRtxThreadWaitExit(thread, (uint32_t)osErrorResource, FALSE);
  287. } while (semaphore->thread_list != NULL);
  288. osRtxThreadDispatch(NULL);
  289. }
  290. // Mark object as invalid
  291. semaphore->id = osRtxIdInvalid;
  292. // Free object memory
  293. if ((semaphore->flags & osRtxFlagSystemObject) != 0U) {
  294. if (osRtxInfo.mpi.semaphore != NULL) {
  295. (void)osRtxMemoryPoolFree(osRtxInfo.mpi.semaphore, semaphore);
  296. } else {
  297. (void)osRtxMemoryFree(osRtxInfo.mem.common, semaphore);
  298. }
  299. #ifdef RTX_OBJ_MEM_USAGE
  300. osRtxSemaphoreMemUsage.cnt_free++;
  301. #endif
  302. }
  303. EvrRtxSemaphoreDestroyed(semaphore);
  304. return osOK;
  305. }
  306. // Service Calls definitions
  307. //lint ++flb "Library Begin" [MISRA Note 11]
  308. SVC0_3(SemaphoreNew, osSemaphoreId_t, uint32_t, uint32_t, const osSemaphoreAttr_t *)
  309. SVC0_1(SemaphoreGetName, const char *, osSemaphoreId_t)
  310. SVC0_2(SemaphoreAcquire, osStatus_t, osSemaphoreId_t, uint32_t)
  311. SVC0_1(SemaphoreRelease, osStatus_t, osSemaphoreId_t)
  312. SVC0_1(SemaphoreGetCount, uint32_t, osSemaphoreId_t)
  313. SVC0_1(SemaphoreDelete, osStatus_t, osSemaphoreId_t)
  314. //lint --flb "Library End"
  315. // ==== ISR Calls ====
  316. /// Acquire a Semaphore token or timeout if no tokens are available.
  317. /// \note API identical to osSemaphoreAcquire
  318. __STATIC_INLINE
  319. osStatus_t isrRtxSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout) {
  320. os_semaphore_t *semaphore = osRtxSemaphoreId(semaphore_id);
  321. osStatus_t status;
  322. // Check parameters
  323. if ((semaphore == NULL) || (semaphore->id != osRtxIdSemaphore) || (timeout != 0U)) {
  324. EvrRtxSemaphoreError(semaphore, (int32_t)osErrorParameter);
  325. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  326. return osErrorParameter;
  327. }
  328. // Try to acquire token
  329. if (SemaphoreTokenDecrement(semaphore) != 0U) {
  330. EvrRtxSemaphoreAcquired(semaphore, semaphore->tokens);
  331. status = osOK;
  332. } else {
  333. // No token available
  334. EvrRtxSemaphoreNotAcquired(semaphore);
  335. status = osErrorResource;
  336. }
  337. return status;
  338. }
  339. /// Release a Semaphore token that was acquired by osSemaphoreAcquire.
  340. /// \note API identical to osSemaphoreRelease
  341. __STATIC_INLINE
  342. osStatus_t isrRtxSemaphoreRelease (osSemaphoreId_t semaphore_id) {
  343. os_semaphore_t *semaphore = osRtxSemaphoreId(semaphore_id);
  344. osStatus_t status;
  345. // Check parameters
  346. if ((semaphore == NULL) || (semaphore->id != osRtxIdSemaphore)) {
  347. EvrRtxSemaphoreError(semaphore, (int32_t)osErrorParameter);
  348. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  349. return osErrorParameter;
  350. }
  351. // Try to release token
  352. if (SemaphoreTokenIncrement(semaphore) != 0U) {
  353. // Register post ISR processing
  354. osRtxPostProcess(osRtxObject(semaphore));
  355. EvrRtxSemaphoreReleased(semaphore, semaphore->tokens);
  356. status = osOK;
  357. } else {
  358. EvrRtxSemaphoreError(semaphore, osRtxErrorSemaphoreCountLimit);
  359. status = osErrorResource;
  360. }
  361. return status;
  362. }
  363. // ==== Public API ====
  364. /// Create and Initialize a Semaphore object.
  365. osSemaphoreId_t osSemaphoreNew (uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr) {
  366. osSemaphoreId_t semaphore_id;
  367. EvrRtxSemaphoreNew(max_count, initial_count, attr);
  368. if (IsException() || IsIrqMasked()) {
  369. EvrRtxSemaphoreError(NULL, (int32_t)osErrorISR);
  370. semaphore_id = NULL;
  371. } else {
  372. semaphore_id = __svcSemaphoreNew(max_count, initial_count, attr);
  373. }
  374. return semaphore_id;
  375. }
  376. /// Get name of a Semaphore object.
  377. const char *osSemaphoreGetName (osSemaphoreId_t semaphore_id) {
  378. const char *name;
  379. if (IsException() || IsIrqMasked()) {
  380. EvrRtxSemaphoreGetName(semaphore_id, NULL);
  381. name = NULL;
  382. } else {
  383. name = __svcSemaphoreGetName(semaphore_id);
  384. }
  385. return name;
  386. }
  387. /// Acquire a Semaphore token or timeout if no tokens are available.
  388. osStatus_t osSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout) {
  389. osStatus_t status;
  390. EvrRtxSemaphoreAcquire(semaphore_id, timeout);
  391. if (IsException() || IsIrqMasked()) {
  392. status = isrRtxSemaphoreAcquire(semaphore_id, timeout);
  393. } else {
  394. status = __svcSemaphoreAcquire(semaphore_id, timeout);
  395. }
  396. return status;
  397. }
  398. /// Release a Semaphore token that was acquired by osSemaphoreAcquire.
  399. osStatus_t osSemaphoreRelease (osSemaphoreId_t semaphore_id) {
  400. osStatus_t status;
  401. EvrRtxSemaphoreRelease(semaphore_id);
  402. if (IsException() || IsIrqMasked()) {
  403. status = isrRtxSemaphoreRelease(semaphore_id);
  404. } else {
  405. status = __svcSemaphoreRelease(semaphore_id);
  406. }
  407. return status;
  408. }
  409. /// Get current Semaphore token count.
  410. uint32_t osSemaphoreGetCount (osSemaphoreId_t semaphore_id) {
  411. uint32_t count;
  412. if (IsException() || IsIrqMasked()) {
  413. count = svcRtxSemaphoreGetCount(semaphore_id);
  414. } else {
  415. count = __svcSemaphoreGetCount(semaphore_id);
  416. }
  417. return count;
  418. }
  419. /// Delete a Semaphore object.
  420. osStatus_t osSemaphoreDelete (osSemaphoreId_t semaphore_id) {
  421. osStatus_t status;
  422. EvrRtxSemaphoreDelete(semaphore_id);
  423. if (IsException() || IsIrqMasked()) {
  424. EvrRtxSemaphoreError(semaphore_id, (int32_t)osErrorISR);
  425. status = osErrorISR;
  426. } else {
  427. status = __svcSemaphoreDelete(semaphore_id);
  428. }
  429. return status;
  430. }