rtx_semaphore.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. /*
  2. * Copyright (c) 2013-2018 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. #if ((defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0)))
  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. if (semaphore->state == osRtxObjectInactive) {
  95. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  96. return;
  97. }
  98. // Check if Thread is waiting for a token
  99. if (semaphore->thread_list != NULL) {
  100. // Try to acquire token
  101. if (SemaphoreTokenDecrement(semaphore) != 0U) {
  102. // Wakeup waiting Thread with highest Priority
  103. thread = osRtxThreadListGet(osRtxObject(semaphore));
  104. osRtxThreadWaitExit(thread, (uint32_t)osOK, FALSE);
  105. EvrRtxSemaphoreAcquired(semaphore);
  106. }
  107. }
  108. }
  109. // ==== Service Calls ====
  110. /// Create and Initialize a Semaphore object.
  111. /// \note API identical to osSemaphoreNew
  112. static osSemaphoreId_t svcRtxSemaphoreNew (uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr) {
  113. os_semaphore_t *semaphore;
  114. uint8_t flags;
  115. const char *name;
  116. // Check parameters
  117. if ((max_count == 0U) || (max_count > osRtxSemaphoreTokenLimit) || (initial_count > max_count)) {
  118. EvrRtxSemaphoreError(NULL, (int32_t)osErrorParameter);
  119. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  120. return NULL;
  121. }
  122. // Process attributes
  123. if (attr != NULL) {
  124. name = attr->name;
  125. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
  126. semaphore = attr->cb_mem;
  127. if (semaphore != NULL) {
  128. //lint -e(923) -e(9078) "cast from pointer to unsigned int" [MISRA Note 7]
  129. if ((((uint32_t)semaphore & 3U) != 0U) || (attr->cb_size < sizeof(os_semaphore_t))) {
  130. EvrRtxSemaphoreError(NULL, osRtxErrorInvalidControlBlock);
  131. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  132. return NULL;
  133. }
  134. } else {
  135. if (attr->cb_size != 0U) {
  136. EvrRtxSemaphoreError(NULL, osRtxErrorInvalidControlBlock);
  137. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  138. return NULL;
  139. }
  140. }
  141. } else {
  142. name = NULL;
  143. semaphore = NULL;
  144. }
  145. // Allocate object memory if not provided
  146. if (semaphore == NULL) {
  147. if (osRtxInfo.mpi.semaphore != NULL) {
  148. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
  149. semaphore = osRtxMemoryPoolAlloc(osRtxInfo.mpi.semaphore);
  150. } else {
  151. //lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
  152. semaphore = osRtxMemoryAlloc(osRtxInfo.mem.common, sizeof(os_semaphore_t), 1U);
  153. }
  154. #if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0))
  155. if (semaphore != NULL) {
  156. uint32_t used;
  157. osRtxSemaphoreMemUsage.cnt_alloc++;
  158. used = osRtxSemaphoreMemUsage.cnt_alloc - osRtxSemaphoreMemUsage.cnt_free;
  159. if (osRtxSemaphoreMemUsage.max_used < used) {
  160. osRtxSemaphoreMemUsage.max_used = used;
  161. }
  162. }
  163. #endif
  164. flags = osRtxFlagSystemObject;
  165. } else {
  166. flags = 0U;
  167. }
  168. if (semaphore != NULL) {
  169. // Initialize control block
  170. semaphore->id = osRtxIdSemaphore;
  171. semaphore->state = osRtxObjectActive;
  172. semaphore->flags = flags;
  173. semaphore->name = name;
  174. semaphore->thread_list = NULL;
  175. semaphore->tokens = (uint16_t)initial_count;
  176. semaphore->max_tokens = (uint16_t)max_count;
  177. // Register post ISR processing function
  178. osRtxInfo.post_process.semaphore = osRtxSemaphorePostProcess;
  179. EvrRtxSemaphoreCreated(semaphore, semaphore->name);
  180. } else {
  181. EvrRtxSemaphoreError(NULL,(int32_t)osErrorNoMemory);
  182. }
  183. return semaphore;
  184. }
  185. /// Get name of a Semaphore object.
  186. /// \note API identical to osSemaphoreGetName
  187. static const char *svcRtxSemaphoreGetName (osSemaphoreId_t semaphore_id) {
  188. os_semaphore_t *semaphore = osRtxSemaphoreId(semaphore_id);
  189. // Check parameters
  190. if ((semaphore == NULL) || (semaphore->id != osRtxIdSemaphore)) {
  191. EvrRtxSemaphoreGetName(semaphore, NULL);
  192. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  193. return NULL;
  194. }
  195. // Check object state
  196. if (semaphore->state == osRtxObjectInactive) {
  197. EvrRtxSemaphoreGetName(semaphore, NULL);
  198. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  199. return NULL;
  200. }
  201. EvrRtxSemaphoreGetName(semaphore, semaphore->name);
  202. return semaphore->name;
  203. }
  204. /// Acquire a Semaphore token or timeout if no tokens are available.
  205. /// \note API identical to osSemaphoreAcquire
  206. static osStatus_t svcRtxSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout) {
  207. os_semaphore_t *semaphore = osRtxSemaphoreId(semaphore_id);
  208. osStatus_t status;
  209. // Check parameters
  210. if ((semaphore == NULL) || (semaphore->id != osRtxIdSemaphore)) {
  211. EvrRtxSemaphoreError(semaphore, (int32_t)osErrorParameter);
  212. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  213. return osErrorParameter;
  214. }
  215. // Check object state
  216. if (semaphore->state == osRtxObjectInactive) {
  217. EvrRtxSemaphoreError(semaphore, (int32_t)osErrorResource);
  218. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  219. return osErrorResource;
  220. }
  221. // Try to acquire token
  222. if (SemaphoreTokenDecrement(semaphore) != 0U) {
  223. EvrRtxSemaphoreAcquired(semaphore);
  224. status = osOK;
  225. } else {
  226. // No token available
  227. if (timeout != 0U) {
  228. EvrRtxSemaphoreAcquirePending(semaphore, timeout);
  229. // Suspend current Thread
  230. if (osRtxThreadWaitEnter(osRtxThreadWaitingSemaphore, timeout)) {
  231. osRtxThreadListPut(osRtxObject(semaphore), osRtxThreadGetRunning());
  232. } else {
  233. EvrRtxSemaphoreAcquireTimeout(semaphore);
  234. }
  235. status = osErrorTimeout;
  236. } else {
  237. EvrRtxSemaphoreNotAcquired(semaphore);
  238. status = osErrorResource;
  239. }
  240. }
  241. return status;
  242. }
  243. /// Release a Semaphore token that was acquired by osSemaphoreAcquire.
  244. /// \note API identical to osSemaphoreRelease
  245. static osStatus_t svcRtxSemaphoreRelease (osSemaphoreId_t semaphore_id) {
  246. os_semaphore_t *semaphore = osRtxSemaphoreId(semaphore_id);
  247. os_thread_t *thread;
  248. osStatus_t status;
  249. // Check parameters
  250. if ((semaphore == NULL) || (semaphore->id != osRtxIdSemaphore)) {
  251. EvrRtxSemaphoreError(semaphore, (int32_t)osErrorParameter);
  252. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  253. return osErrorParameter;
  254. }
  255. // Check object state
  256. if (semaphore->state == osRtxObjectInactive) {
  257. EvrRtxSemaphoreError(semaphore, (int32_t)osErrorResource);
  258. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  259. return osErrorResource;
  260. }
  261. // Check if Thread is waiting for a token
  262. if (semaphore->thread_list != NULL) {
  263. EvrRtxSemaphoreReleased(semaphore);
  264. // Wakeup waiting Thread with highest Priority
  265. thread = osRtxThreadListGet(osRtxObject(semaphore));
  266. osRtxThreadWaitExit(thread, (uint32_t)osOK, TRUE);
  267. EvrRtxSemaphoreAcquired(semaphore);
  268. status = osOK;
  269. } else {
  270. // Try to release token
  271. if (SemaphoreTokenIncrement(semaphore) != 0U) {
  272. EvrRtxSemaphoreReleased(semaphore);
  273. status = osOK;
  274. } else {
  275. EvrRtxSemaphoreError(semaphore, osRtxErrorSemaphoreCountLimit);
  276. status = osErrorResource;
  277. }
  278. }
  279. return status;
  280. }
  281. /// Get current Semaphore token count.
  282. /// \note API identical to osSemaphoreGetCount
  283. static uint32_t svcRtxSemaphoreGetCount (osSemaphoreId_t semaphore_id) {
  284. os_semaphore_t *semaphore = osRtxSemaphoreId(semaphore_id);
  285. // Check parameters
  286. if ((semaphore == NULL) || (semaphore->id != osRtxIdSemaphore)) {
  287. EvrRtxSemaphoreGetCount(semaphore, 0U);
  288. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  289. return 0U;
  290. }
  291. // Check object state
  292. if (semaphore->state == osRtxObjectInactive) {
  293. EvrRtxSemaphoreGetCount(semaphore, 0U);
  294. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  295. return 0U;
  296. }
  297. EvrRtxSemaphoreGetCount(semaphore, semaphore->tokens);
  298. return semaphore->tokens;
  299. }
  300. /// Delete a Semaphore object.
  301. /// \note API identical to osSemaphoreDelete
  302. static osStatus_t svcRtxSemaphoreDelete (osSemaphoreId_t semaphore_id) {
  303. os_semaphore_t *semaphore = osRtxSemaphoreId(semaphore_id);
  304. os_thread_t *thread;
  305. // Check parameters
  306. if ((semaphore == NULL) || (semaphore->id != osRtxIdSemaphore)) {
  307. EvrRtxSemaphoreError(semaphore, (int32_t)osErrorParameter);
  308. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  309. return osErrorParameter;
  310. }
  311. // Check object state
  312. if (semaphore->state == osRtxObjectInactive) {
  313. EvrRtxSemaphoreError(semaphore, (int32_t)osErrorResource);
  314. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  315. return osErrorResource;
  316. }
  317. // Mark object as inactive
  318. semaphore->state = osRtxObjectInactive;
  319. // Unblock waiting threads
  320. if (semaphore->thread_list != NULL) {
  321. do {
  322. thread = osRtxThreadListGet(osRtxObject(semaphore));
  323. osRtxThreadWaitExit(thread, (uint32_t)osErrorResource, FALSE);
  324. } while (semaphore->thread_list != NULL);
  325. osRtxThreadDispatch(NULL);
  326. }
  327. // Free object memory
  328. if ((semaphore->flags & osRtxFlagSystemObject) != 0U) {
  329. if (osRtxInfo.mpi.semaphore != NULL) {
  330. (void)osRtxMemoryPoolFree(osRtxInfo.mpi.semaphore, semaphore);
  331. } else {
  332. (void)osRtxMemoryFree(osRtxInfo.mem.common, semaphore);
  333. }
  334. #if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0))
  335. osRtxSemaphoreMemUsage.cnt_free++;
  336. #endif
  337. }
  338. EvrRtxSemaphoreDestroyed(semaphore);
  339. return osOK;
  340. }
  341. // Service Calls definitions
  342. //lint ++flb "Library Begin" [MISRA Note 11]
  343. SVC0_3(SemaphoreNew, osSemaphoreId_t, uint32_t, uint32_t, const osSemaphoreAttr_t *)
  344. SVC0_1(SemaphoreGetName, const char *, osSemaphoreId_t)
  345. SVC0_2(SemaphoreAcquire, osStatus_t, osSemaphoreId_t, uint32_t)
  346. SVC0_1(SemaphoreRelease, osStatus_t, osSemaphoreId_t)
  347. SVC0_1(SemaphoreGetCount, uint32_t, osSemaphoreId_t)
  348. SVC0_1(SemaphoreDelete, osStatus_t, osSemaphoreId_t)
  349. //lint --flb "Library End"
  350. // ==== ISR Calls ====
  351. /// Acquire a Semaphore token or timeout if no tokens are available.
  352. /// \note API identical to osSemaphoreAcquire
  353. __STATIC_INLINE
  354. osStatus_t isrRtxSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout) {
  355. os_semaphore_t *semaphore = osRtxSemaphoreId(semaphore_id);
  356. osStatus_t status;
  357. // Check parameters
  358. if ((semaphore == NULL) || (semaphore->id != osRtxIdSemaphore) || (timeout != 0U)) {
  359. EvrRtxSemaphoreError(semaphore, (int32_t)osErrorParameter);
  360. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  361. return osErrorParameter;
  362. }
  363. // Check object state
  364. if (semaphore->state == osRtxObjectInactive) {
  365. EvrRtxSemaphoreError(semaphore, (int32_t)osErrorResource);
  366. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  367. return osErrorResource;
  368. }
  369. // Try to acquire token
  370. if (SemaphoreTokenDecrement(semaphore) != 0U) {
  371. EvrRtxSemaphoreAcquired(semaphore);
  372. status = osOK;
  373. } else {
  374. // No token available
  375. EvrRtxSemaphoreNotAcquired(semaphore);
  376. status = osErrorResource;
  377. }
  378. return status;
  379. }
  380. /// Release a Semaphore token that was acquired by osSemaphoreAcquire.
  381. /// \note API identical to osSemaphoreRelease
  382. __STATIC_INLINE
  383. osStatus_t isrRtxSemaphoreRelease (osSemaphoreId_t semaphore_id) {
  384. os_semaphore_t *semaphore = osRtxSemaphoreId(semaphore_id);
  385. osStatus_t status;
  386. // Check parameters
  387. if ((semaphore == NULL) || (semaphore->id != osRtxIdSemaphore)) {
  388. EvrRtxSemaphoreError(semaphore, (int32_t)osErrorParameter);
  389. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  390. return osErrorParameter;
  391. }
  392. // Check object state
  393. if (semaphore->state == osRtxObjectInactive) {
  394. EvrRtxSemaphoreError(semaphore, (int32_t)osErrorResource);
  395. //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  396. return osErrorResource;
  397. }
  398. // Try to release token
  399. if (SemaphoreTokenIncrement(semaphore) != 0U) {
  400. // Register post ISR processing
  401. osRtxPostProcess(osRtxObject(semaphore));
  402. EvrRtxSemaphoreReleased(semaphore);
  403. status = osOK;
  404. } else {
  405. EvrRtxSemaphoreError(semaphore, osRtxErrorSemaphoreCountLimit);
  406. status = osErrorResource;
  407. }
  408. return status;
  409. }
  410. // ==== Public API ====
  411. /// Create and Initialize a Semaphore object.
  412. osSemaphoreId_t osSemaphoreNew (uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr) {
  413. osSemaphoreId_t semaphore_id;
  414. EvrRtxSemaphoreNew(max_count, initial_count, attr);
  415. if (IsIrqMode() || IsIrqMasked()) {
  416. EvrRtxSemaphoreError(NULL, (int32_t)osErrorISR);
  417. semaphore_id = NULL;
  418. } else {
  419. semaphore_id = __svcSemaphoreNew(max_count, initial_count, attr);
  420. }
  421. return semaphore_id;
  422. }
  423. /// Get name of a Semaphore object.
  424. const char *osSemaphoreGetName (osSemaphoreId_t semaphore_id) {
  425. const char *name;
  426. if (IsIrqMode() || IsIrqMasked()) {
  427. EvrRtxSemaphoreGetName(semaphore_id, NULL);
  428. name = NULL;
  429. } else {
  430. name = __svcSemaphoreGetName(semaphore_id);
  431. }
  432. return name;
  433. }
  434. /// Acquire a Semaphore token or timeout if no tokens are available.
  435. osStatus_t osSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout) {
  436. osStatus_t status;
  437. EvrRtxSemaphoreAcquire(semaphore_id, timeout);
  438. if (IsIrqMode() || IsIrqMasked()) {
  439. status = isrRtxSemaphoreAcquire(semaphore_id, timeout);
  440. } else {
  441. status = __svcSemaphoreAcquire(semaphore_id, timeout);
  442. }
  443. return status;
  444. }
  445. /// Release a Semaphore token that was acquired by osSemaphoreAcquire.
  446. osStatus_t osSemaphoreRelease (osSemaphoreId_t semaphore_id) {
  447. osStatus_t status;
  448. EvrRtxSemaphoreRelease(semaphore_id);
  449. if (IsIrqMode() || IsIrqMasked()) {
  450. status = isrRtxSemaphoreRelease(semaphore_id);
  451. } else {
  452. status = __svcSemaphoreRelease(semaphore_id);
  453. }
  454. return status;
  455. }
  456. /// Get current Semaphore token count.
  457. uint32_t osSemaphoreGetCount (osSemaphoreId_t semaphore_id) {
  458. uint32_t count;
  459. if (IsIrqMode() || IsIrqMasked()) {
  460. count = svcRtxSemaphoreGetCount(semaphore_id);
  461. } else {
  462. count = __svcSemaphoreGetCount(semaphore_id);
  463. }
  464. return count;
  465. }
  466. /// Delete a Semaphore object.
  467. osStatus_t osSemaphoreDelete (osSemaphoreId_t semaphore_id) {
  468. osStatus_t status;
  469. EvrRtxSemaphoreDelete(semaphore_id);
  470. if (IsIrqMode() || IsIrqMasked()) {
  471. EvrRtxSemaphoreError(semaphore_id, (int32_t)osErrorISR);
  472. status = osErrorISR;
  473. } else {
  474. status = __svcSemaphoreDelete(semaphore_id);
  475. }
  476. return status;
  477. }