rtx_semaphore.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. /*
  2. * Copyright (c) 2013-2016 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. * http://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. // ==== Helper functions ====
  27. /// Decrement Semaphore tokens.
  28. /// \param[in] semaphore semaphore object.
  29. /// \return 1 - success, 0 - failure.
  30. static uint32_t os_SemaphoreTokenDecrement (os_semaphore_t *semaphore) {
  31. #if (__EXCLUSIVE_ACCESS == 0U)
  32. uint32_t primask = __get_PRIMASK();
  33. #endif
  34. uint32_t ret;
  35. #if (__EXCLUSIVE_ACCESS == 0U)
  36. __disable_irq();
  37. if (semaphore->tokens != 0U) {
  38. semaphore->tokens--;
  39. ret = 1U;
  40. } else {
  41. ret = 0U;
  42. }
  43. if (primask == 0U) {
  44. __enable_irq();
  45. }
  46. #else
  47. if (os_exc_dec16_nz(&semaphore->tokens) != 0U) {
  48. ret = 1U;
  49. } else {
  50. ret = 0U;
  51. }
  52. #endif
  53. return ret;
  54. }
  55. /// Increment Semaphore tokens.
  56. /// \param[in] semaphore semaphore object.
  57. /// \return 1 - success, 0 - failure.
  58. static uint32_t os_SemaphoreTokenIncrement (os_semaphore_t *semaphore) {
  59. #if (__EXCLUSIVE_ACCESS == 0U)
  60. uint32_t primask = __get_PRIMASK();
  61. #endif
  62. uint32_t ret;
  63. #if (__EXCLUSIVE_ACCESS == 0U)
  64. __disable_irq();
  65. if (semaphore->tokens < semaphore->max_tokens) {
  66. semaphore->tokens++;
  67. ret = 1U;
  68. } else {
  69. ret = 0U;
  70. }
  71. if (primask == 0U) {
  72. __enable_irq();
  73. }
  74. #else
  75. if (os_exc_inc16_lt(&semaphore->tokens, semaphore->max_tokens) < semaphore->max_tokens) {
  76. ret = 1U;
  77. } else {
  78. ret = 0U;
  79. }
  80. #endif
  81. return ret;
  82. }
  83. // ==== Library functions ====
  84. /// Semaphore post ISR processing.
  85. /// \param[in] semaphore semaphore object.
  86. void os_SemaphorePostProcess (os_semaphore_t *semaphore) {
  87. os_thread_t *thread;
  88. if (semaphore->state == os_ObjectInactive) {
  89. return;
  90. }
  91. // Check if Thread is waiting for a token
  92. if (semaphore->thread_list != NULL) {
  93. // Try to acquire token
  94. if (os_SemaphoreTokenDecrement(semaphore) != 0U) {
  95. // Wakeup waiting Thread with highest Priority
  96. thread = os_ThreadListGet((os_object_t*)semaphore);
  97. os_ThreadWaitExit(thread, (uint32_t)osOK, false);
  98. }
  99. }
  100. }
  101. // ==== Service Calls ====
  102. // Service Calls definitions
  103. SVC0_3(SemaphoreNew, osSemaphoreId_t, uint32_t, uint32_t, const osSemaphoreAttr_t *)
  104. SVC0_1(SemaphoreGetName, const char *, osSemaphoreId_t)
  105. SVC0_2(SemaphoreAcquire, osStatus_t, osSemaphoreId_t, uint32_t)
  106. SVC0_1(SemaphoreRelease, osStatus_t, osSemaphoreId_t)
  107. SVC0_1(SemaphoreGetCount, uint32_t, osSemaphoreId_t)
  108. SVC0_1(SemaphoreDelete, osStatus_t, osSemaphoreId_t)
  109. /// Create and Initialize a Semaphore object.
  110. /// \note API identical to osSemaphoreNew
  111. osSemaphoreId_t os_svcSemaphoreNew (uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr) {
  112. os_semaphore_t *semaphore;
  113. uint8_t flags;
  114. const char *name;
  115. // Check parameters
  116. if ((max_count == 0U) ||
  117. (max_count > os_SemaphoreTokenLimit) ||
  118. (initial_count > max_count)) {
  119. return NULL;
  120. }
  121. // Process attributes
  122. if (attr != NULL) {
  123. name = attr->name;
  124. semaphore = attr->cb_mem;
  125. if (semaphore != NULL) {
  126. if (((uint32_t)semaphore & 3U) || (attr->cb_size < sizeof(os_semaphore_t))) {
  127. return NULL;
  128. }
  129. } else {
  130. if (attr->cb_size != 0U) {
  131. return NULL;
  132. }
  133. }
  134. } else {
  135. name = NULL;
  136. semaphore = NULL;
  137. }
  138. // Allocate object memory if not provided
  139. if (semaphore == NULL) {
  140. if (os_Info.mpi.semaphore != NULL) {
  141. semaphore = os_MemoryPoolAlloc(os_Info.mpi.semaphore);
  142. } else {
  143. semaphore = os_MemoryAlloc(os_Info.mem.common, sizeof(os_semaphore_t), 1U);
  144. }
  145. if (semaphore == NULL) {
  146. return NULL;
  147. }
  148. flags = os_FlagSystemObject;
  149. } else {
  150. flags = 0U;
  151. }
  152. // Initialize control block
  153. semaphore->id = os_IdSemaphore;
  154. semaphore->state = os_ObjectActive;
  155. semaphore->flags = flags;
  156. semaphore->name = name;
  157. semaphore->thread_list = NULL;
  158. semaphore->tokens = (uint16_t)initial_count;
  159. semaphore->max_tokens = (uint16_t)max_count;
  160. // Register post ISR processing function
  161. os_Info.post_process.semaphore = os_SemaphorePostProcess;
  162. return semaphore;
  163. }
  164. /// Get name of a Semaphore object.
  165. /// \note API identical to osSemaphoreGetName
  166. const char *os_svcSemaphoreGetName (osSemaphoreId_t semaphore_id) {
  167. os_semaphore_t *semaphore = (os_semaphore_t *)semaphore_id;
  168. // Check parameters
  169. if ((semaphore == NULL) ||
  170. (semaphore->id != os_IdSemaphore)) {
  171. return NULL;
  172. }
  173. // Check object state
  174. if (semaphore->state == os_ObjectInactive) {
  175. return NULL;
  176. }
  177. return semaphore->name;
  178. }
  179. /// Acquire a Semaphore token or timeout if no tokens are available.
  180. /// \note API identical to osSemaphoreAcquire
  181. osStatus_t os_svcSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout) {
  182. os_semaphore_t *semaphore = (os_semaphore_t *)semaphore_id;
  183. // Check parameters
  184. if ((semaphore == NULL) ||
  185. (semaphore->id != os_IdSemaphore)) {
  186. return osErrorParameter;
  187. }
  188. // Check object state
  189. if (semaphore->state == os_ObjectInactive) {
  190. return osErrorResource;
  191. }
  192. // Try to acquire token
  193. if (os_SemaphoreTokenDecrement(semaphore) == 0U) {
  194. // No token available
  195. if (timeout != 0U) {
  196. // Suspend current Thread
  197. os_ThreadListPut((os_object_t*)semaphore, os_ThreadGetRunning());
  198. os_ThreadWaitEnter(os_ThreadWaitingSemaphore, timeout);
  199. return osErrorTimeout;
  200. } else {
  201. return osErrorResource;
  202. }
  203. }
  204. return osOK;
  205. }
  206. /// Release a Semaphore token that was acquired by osSemaphoreAcquire.
  207. /// \note API identical to osSemaphoreRelease
  208. osStatus_t os_svcSemaphoreRelease (osSemaphoreId_t semaphore_id) {
  209. os_semaphore_t *semaphore = (os_semaphore_t *)semaphore_id;
  210. os_thread_t *thread;
  211. // Check parameters
  212. if ((semaphore == NULL) ||
  213. (semaphore->id != os_IdSemaphore)) {
  214. return osErrorParameter;
  215. }
  216. // Check object state
  217. if (semaphore->state == os_ObjectInactive) {
  218. return osErrorResource;
  219. }
  220. // Check if Thread is waiting for a token
  221. if (semaphore->thread_list != NULL) {
  222. // Wakeup waiting Thread with highest Priority
  223. thread = os_ThreadListGet((os_object_t*)semaphore);
  224. os_ThreadWaitExit(thread, (uint32_t)osOK, true);
  225. } else {
  226. // Try to release token
  227. if (os_SemaphoreTokenIncrement(semaphore) == 0U) {
  228. return osErrorResource;
  229. }
  230. }
  231. return osOK;
  232. }
  233. /// Get current Semaphore token count.
  234. /// \note API identical to osSemaphoreGetCount
  235. uint32_t os_svcSemaphoreGetCount (osSemaphoreId_t semaphore_id) {
  236. os_semaphore_t *semaphore = (os_semaphore_t *)semaphore_id;
  237. // Check parameters
  238. if ((semaphore == NULL) ||
  239. (semaphore->id != os_IdSemaphore)) {
  240. return 0U;
  241. }
  242. // Check object state
  243. if (semaphore->state == os_ObjectInactive) {
  244. return 0U;
  245. }
  246. return semaphore->tokens;
  247. }
  248. /// Delete a Semaphore object.
  249. /// \note API identical to osSemaphoreDelete
  250. osStatus_t os_svcSemaphoreDelete (osSemaphoreId_t semaphore_id) {
  251. os_semaphore_t *semaphore = (os_semaphore_t *)semaphore_id;
  252. os_thread_t *thread;
  253. // Check parameters
  254. if ((semaphore == NULL) ||
  255. (semaphore->id != os_IdSemaphore)) {
  256. return osErrorParameter;
  257. }
  258. // Check object state
  259. if (semaphore->state == os_ObjectInactive) {
  260. return osErrorResource;
  261. }
  262. // Mark object as inactive
  263. semaphore->state = os_ObjectInactive;
  264. // Unblock waiting threads
  265. if (semaphore->thread_list != NULL) {
  266. do {
  267. thread = os_ThreadListGet((os_object_t*)semaphore);
  268. os_ThreadWaitExit(thread, (uint32_t)osErrorResource, false);
  269. } while (semaphore->thread_list != NULL);
  270. os_ThreadDispatch(NULL);
  271. }
  272. // Free object memory
  273. if (semaphore->flags & os_FlagSystemObject) {
  274. if (os_Info.mpi.semaphore != NULL) {
  275. os_MemoryPoolFree(os_Info.mpi.semaphore, semaphore);
  276. } else {
  277. os_MemoryFree(os_Info.mem.common, semaphore);
  278. }
  279. }
  280. return osOK;
  281. }
  282. // ==== ISR Calls ====
  283. /// Acquire a Semaphore token or timeout if no tokens are available.
  284. /// \note API identical to osSemaphoreAcquire
  285. __STATIC_INLINE
  286. osStatus_t os_isrSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout) {
  287. os_semaphore_t *semaphore = (os_semaphore_t *)semaphore_id;
  288. // Check parameters
  289. if ((semaphore == NULL) ||
  290. (semaphore->id != os_IdSemaphore)) {
  291. return osErrorParameter;
  292. }
  293. if (timeout != 0U) {
  294. return osErrorParameter;
  295. }
  296. // Check object state
  297. if (semaphore->state == os_ObjectInactive) {
  298. return osErrorResource;
  299. }
  300. // Try to acquire token
  301. if (os_SemaphoreTokenDecrement(semaphore) == 0U) {
  302. // No token available
  303. return osErrorResource;
  304. }
  305. return osOK;
  306. }
  307. /// Release a Semaphore token that was acquired by osSemaphoreAcquire.
  308. /// \note API identical to osSemaphoreRelease
  309. __STATIC_INLINE
  310. osStatus_t os_isrSemaphoreRelease (osSemaphoreId_t semaphore_id) {
  311. os_semaphore_t *semaphore = (os_semaphore_t *)semaphore_id;
  312. // Check parameters
  313. if ((semaphore == NULL) ||
  314. (semaphore->id != os_IdSemaphore)) {
  315. return osErrorParameter;
  316. }
  317. // Check object state
  318. if (semaphore->state == os_ObjectInactive) {
  319. return osErrorResource;
  320. }
  321. // Try to release token
  322. if (os_SemaphoreTokenIncrement(semaphore) != 0U) {
  323. // Register post ISR processing
  324. os_PostProcess((os_object_t *)semaphore);
  325. } else {
  326. return osErrorResource;
  327. }
  328. return osOK;
  329. }
  330. // ==== Public API ====
  331. /// Create and Initialize a Semaphore object.
  332. osSemaphoreId_t osSemaphoreNew (uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr) {
  333. if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
  334. return NULL;
  335. }
  336. if ((os_KernelGetState() == os_KernelReady) && IS_PRIVILEGED()) {
  337. // Kernel Ready (not running) and in Privileged mode
  338. return os_svcSemaphoreNew(max_count, initial_count, attr);
  339. } else {
  340. return __svcSemaphoreNew(max_count, initial_count, attr);
  341. }
  342. }
  343. /// Get name of a Semaphore object.
  344. const char *osSemaphoreGetName (osSemaphoreId_t semaphore_id) {
  345. if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
  346. return NULL;
  347. }
  348. return __svcSemaphoreGetName(semaphore_id);
  349. }
  350. /// Acquire a Semaphore token or timeout if no tokens are available.
  351. osStatus_t osSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout) {
  352. if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
  353. return os_isrSemaphoreAcquire(semaphore_id, timeout);
  354. } else {
  355. return __svcSemaphoreAcquire(semaphore_id, timeout);
  356. }
  357. }
  358. /// Release a Semaphore token that was acquired by osSemaphoreAcquire.
  359. osStatus_t osSemaphoreRelease (osSemaphoreId_t semaphore_id) {
  360. if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
  361. return os_isrSemaphoreRelease(semaphore_id);
  362. } else {
  363. return __svcSemaphoreRelease(semaphore_id);
  364. }
  365. }
  366. /// Get current Semaphore token count.
  367. uint32_t osSemaphoreGetCount (osSemaphoreId_t semaphore_id) {
  368. if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
  369. return os_svcSemaphoreGetCount(semaphore_id);
  370. } else {
  371. return __svcSemaphoreGetCount(semaphore_id);
  372. }
  373. }
  374. /// Delete a Semaphore object.
  375. osStatus_t osSemaphoreDelete (osSemaphoreId_t semaphore_id) {
  376. if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
  377. return osErrorISR;
  378. }
  379. return __svcSemaphoreDelete(semaphore_id);
  380. }