thread.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  1. /*
  2. * Copyright (c) 2018 Intel Corporation
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <kernel.h>
  7. #include <ksched.h>
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <sys/atomic.h>
  11. #include <debug/stack.h>
  12. #include "wrapper.h"
  13. static const osThreadAttr_t init_thread_attrs = {
  14. .name = "ZephyrThread",
  15. .attr_bits = osThreadDetached,
  16. .cb_mem = NULL,
  17. .cb_size = 0,
  18. .stack_mem = NULL,
  19. .stack_size = 0,
  20. .priority = osPriorityNormal,
  21. .tz_module = 0,
  22. .reserved = 0,
  23. };
  24. static sys_dlist_t thread_list;
  25. static struct cv2_thread cv2_thread_pool[CONFIG_CMSIS_V2_THREAD_MAX_COUNT];
  26. static uint32_t thread_num;
  27. static uint32_t thread_num_dynamic;
  28. #if CONFIG_CMSIS_V2_THREAD_DYNAMIC_MAX_COUNT != 0
  29. static K_THREAD_STACK_ARRAY_DEFINE(cv2_thread_stack_pool, \
  30. CONFIG_CMSIS_V2_THREAD_DYNAMIC_MAX_COUNT, \
  31. CONFIG_CMSIS_V2_THREAD_DYNAMIC_STACK_SIZE);
  32. #endif
  33. static inline int _is_thread_cmsis_inactive(struct k_thread *thread)
  34. {
  35. uint8_t state = thread->base.thread_state;
  36. return state & (_THREAD_PRESTART | _THREAD_DEAD);
  37. }
  38. static inline uint32_t zephyr_to_cmsis_priority(uint32_t z_prio)
  39. {
  40. return (osPriorityISR - z_prio);
  41. }
  42. static inline uint32_t cmsis_to_zephyr_priority(uint32_t c_prio)
  43. {
  44. return (osPriorityISR - c_prio);
  45. }
  46. static void zephyr_thread_wrapper(void *arg1, void *arg2, void *arg3)
  47. {
  48. struct cv2_thread *tid = arg2;
  49. void * (*fun_ptr)(void *) = arg3;
  50. fun_ptr(arg1);
  51. tid->has_joined = TRUE;
  52. k_sem_give(&tid->join_guard);
  53. }
  54. void *is_cmsis_rtos_v2_thread(void *thread_id)
  55. {
  56. sys_dnode_t *pnode;
  57. struct cv2_thread *itr;
  58. SYS_DLIST_FOR_EACH_NODE(&thread_list, pnode) {
  59. itr = CONTAINER_OF(pnode, struct cv2_thread, node);
  60. if ((void *)itr == thread_id) {
  61. return itr;
  62. }
  63. }
  64. return NULL;
  65. }
  66. osThreadId_t get_cmsis_thread_id(k_tid_t tid)
  67. {
  68. sys_dnode_t *pnode;
  69. struct cv2_thread *itr;
  70. if (tid != NULL) {
  71. SYS_DLIST_FOR_EACH_NODE(&thread_list, pnode) {
  72. itr = CONTAINER_OF(pnode, struct cv2_thread, node);
  73. if (&itr->z_thread == tid) {
  74. return (osThreadId_t)itr;
  75. }
  76. }
  77. }
  78. return NULL;
  79. }
  80. /**
  81. * @brief Create a thread and add it to Active Threads.
  82. */
  83. osThreadId_t osThreadNew(osThreadFunc_t threadfunc, void *arg,
  84. const osThreadAttr_t *attr)
  85. {
  86. int32_t prio;
  87. osPriority_t cv2_prio;
  88. struct cv2_thread *tid;
  89. static uint32_t one_time;
  90. void *stack;
  91. size_t stack_size;
  92. uint32_t this_thread_num;
  93. if (k_is_in_isr()) {
  94. return NULL;
  95. }
  96. if (thread_num >= CONFIG_CMSIS_V2_THREAD_MAX_COUNT) {
  97. return NULL;
  98. }
  99. if (attr == NULL) {
  100. attr = &init_thread_attrs;
  101. }
  102. if (attr->priority == osPriorityNone) {
  103. cv2_prio = osPriorityNormal;
  104. } else {
  105. cv2_prio = attr->priority;
  106. }
  107. if ((attr->stack_mem == NULL) && (thread_num_dynamic >=
  108. CONFIG_CMSIS_V2_THREAD_DYNAMIC_MAX_COUNT)) {
  109. return NULL;
  110. }
  111. BUILD_ASSERT(osPriorityISR <= CONFIG_NUM_PREEMPT_PRIORITIES,
  112. "Configure NUM_PREEMPT_PRIORITIES to at least osPriorityISR");
  113. BUILD_ASSERT(CONFIG_CMSIS_V2_THREAD_DYNAMIC_MAX_COUNT <=
  114. CONFIG_CMSIS_V2_THREAD_MAX_COUNT,
  115. "Number of dynamic threads cannot exceed max number of threads.");
  116. BUILD_ASSERT(CONFIG_CMSIS_V2_THREAD_DYNAMIC_STACK_SIZE <=
  117. CONFIG_CMSIS_V2_THREAD_MAX_STACK_SIZE,
  118. "Default dynamic thread stack size cannot exceed max stack size");
  119. __ASSERT(attr->stack_size <= CONFIG_CMSIS_V2_THREAD_MAX_STACK_SIZE,
  120. "invalid stack size\n");
  121. __ASSERT((cv2_prio >= osPriorityIdle) && (cv2_prio <= osPriorityISR),
  122. "invalid priority\n");
  123. if (attr->stack_mem != NULL) {
  124. if (attr->stack_size == 0) {
  125. return NULL;
  126. }
  127. }
  128. prio = cmsis_to_zephyr_priority(cv2_prio);
  129. this_thread_num = atomic_inc((atomic_t *)&thread_num);
  130. tid = &cv2_thread_pool[this_thread_num];
  131. tid->attr_bits = attr->attr_bits;
  132. #if CONFIG_CMSIS_V2_THREAD_DYNAMIC_MAX_COUNT != 0
  133. if (attr->stack_mem == NULL) {
  134. uint32_t this_thread_num_dynamic;
  135. __ASSERT(CONFIG_CMSIS_V2_THREAD_DYNAMIC_STACK_SIZE > 0,
  136. "dynamic stack size must be configured to be non-zero\n");
  137. this_thread_num_dynamic =
  138. atomic_inc((atomic_t *)&thread_num_dynamic);
  139. stack_size = CONFIG_CMSIS_V2_THREAD_DYNAMIC_STACK_SIZE;
  140. stack = cv2_thread_stack_pool[this_thread_num_dynamic];
  141. } else
  142. #endif
  143. {
  144. stack_size = attr->stack_size;
  145. stack = attr->stack_mem;
  146. }
  147. k_poll_signal_init(&tid->poll_signal);
  148. k_poll_event_init(&tid->poll_event, K_POLL_TYPE_SIGNAL,
  149. K_POLL_MODE_NOTIFY_ONLY, &tid->poll_signal);
  150. tid->signal_results = 0U;
  151. /* TODO: Do this somewhere only once */
  152. if (one_time == 0U) {
  153. sys_dlist_init(&thread_list);
  154. one_time = 1U;
  155. }
  156. sys_dlist_append(&thread_list, &tid->node);
  157. k_sem_init(&tid->join_guard, 0, 1);
  158. tid->has_joined = FALSE;
  159. (void)k_thread_create(&tid->z_thread,
  160. stack, stack_size,
  161. (k_thread_entry_t)zephyr_thread_wrapper,
  162. (void *)arg, tid, threadfunc,
  163. prio, 0, K_NO_WAIT);
  164. if (attr->name == NULL) {
  165. strncpy(tid->name, init_thread_attrs.name,
  166. sizeof(tid->name) - 1);
  167. } else {
  168. strncpy(tid->name, attr->name, sizeof(tid->name) - 1);
  169. }
  170. k_thread_name_set(&tid->z_thread, tid->name);
  171. return (osThreadId_t)tid;
  172. }
  173. /**
  174. * @brief Get name of a thread.
  175. */
  176. const char *osThreadGetName(osThreadId_t thread_id)
  177. {
  178. const char *name = NULL;
  179. if (k_is_in_isr() || (thread_id == NULL)) {
  180. name = NULL;
  181. } else {
  182. if (is_cmsis_rtos_v2_thread(thread_id) == NULL) {
  183. name = NULL;
  184. } else {
  185. struct cv2_thread *tid =
  186. (struct cv2_thread *)thread_id;
  187. name = k_thread_name_get(&tid->z_thread);
  188. }
  189. }
  190. return name;
  191. }
  192. /**
  193. * @brief Return the thread ID of the current running thread.
  194. */
  195. osThreadId_t osThreadGetId(void)
  196. {
  197. k_tid_t tid = k_current_get();
  198. return get_cmsis_thread_id(tid);
  199. }
  200. /**
  201. * @brief Get current priority of an active thread.
  202. */
  203. osPriority_t osThreadGetPriority(osThreadId_t thread_id)
  204. {
  205. struct cv2_thread *tid = (struct cv2_thread *)thread_id;
  206. uint32_t priority;
  207. if (k_is_in_isr() || (tid == NULL) ||
  208. (is_cmsis_rtos_v2_thread(tid) == NULL) ||
  209. (_is_thread_cmsis_inactive(&tid->z_thread))) {
  210. return osPriorityError;
  211. }
  212. priority = k_thread_priority_get(&tid->z_thread);
  213. return zephyr_to_cmsis_priority(priority);
  214. }
  215. /**
  216. * @brief Change priority of an active thread.
  217. */
  218. osStatus_t osThreadSetPriority(osThreadId_t thread_id, osPriority_t priority)
  219. {
  220. struct cv2_thread *tid = (struct cv2_thread *)thread_id;
  221. if ((tid == NULL) || (is_cmsis_rtos_v2_thread(tid) == NULL) ||
  222. (priority <= osPriorityNone) || (priority > osPriorityISR)) {
  223. return osErrorParameter;
  224. }
  225. if (k_is_in_isr()) {
  226. return osErrorISR;
  227. }
  228. if (_is_thread_cmsis_inactive(&tid->z_thread)) {
  229. return osErrorResource;
  230. }
  231. k_thread_priority_set((k_tid_t)&tid->z_thread,
  232. cmsis_to_zephyr_priority(priority));
  233. return osOK;
  234. }
  235. /**
  236. * @brief Get current thread state of a thread.
  237. */
  238. osThreadState_t osThreadGetState(osThreadId_t thread_id)
  239. {
  240. struct cv2_thread *tid = (struct cv2_thread *)thread_id;
  241. osThreadState_t state;
  242. if (k_is_in_isr() || (tid == NULL) ||
  243. (is_cmsis_rtos_v2_thread(tid) == NULL)) {
  244. return osThreadError;
  245. }
  246. switch (tid->z_thread.base.thread_state) {
  247. case _THREAD_DUMMY:
  248. state = osThreadError;
  249. break;
  250. case _THREAD_PRESTART:
  251. state = osThreadInactive;
  252. break;
  253. case _THREAD_DEAD:
  254. state = osThreadTerminated;
  255. break;
  256. case _THREAD_SUSPENDED:
  257. case _THREAD_PENDING:
  258. state = osThreadBlocked;
  259. break;
  260. case _THREAD_QUEUED:
  261. state = osThreadReady;
  262. break;
  263. default:
  264. state = osThreadError;
  265. break;
  266. }
  267. if (osThreadGetId() == thread_id) {
  268. state = osThreadRunning;
  269. }
  270. return state;
  271. }
  272. /**
  273. * @brief Pass control to next thread that is in READY state.
  274. */
  275. osStatus_t osThreadYield(void)
  276. {
  277. if (k_is_in_isr()) {
  278. return osErrorISR;
  279. }
  280. k_yield();
  281. return osOK;
  282. }
  283. /**
  284. * @brief Get stack size of a thread.
  285. */
  286. uint32_t osThreadGetStackSize(osThreadId_t thread_id)
  287. {
  288. struct cv2_thread *tid = (struct cv2_thread *)thread_id;
  289. __ASSERT(tid, "");
  290. __ASSERT(is_cmsis_rtos_v2_thread(tid), "");
  291. __ASSERT(!k_is_in_isr(), "");
  292. return tid->z_thread.stack_info.size;
  293. }
  294. /**
  295. * @brief Get available stack space of a thread based on stack watermark
  296. * recording during execution.
  297. */
  298. uint32_t osThreadGetStackSpace(osThreadId_t thread_id)
  299. {
  300. struct cv2_thread *tid = (struct cv2_thread *)thread_id;
  301. size_t unused;
  302. int ret;
  303. __ASSERT(tid, "");
  304. __ASSERT(is_cmsis_rtos_v2_thread(tid), "");
  305. __ASSERT(!k_is_in_isr(), "");
  306. ret = k_thread_stack_space_get(&tid->z_thread, &unused);
  307. if (ret != 0) {
  308. unused = 0;
  309. }
  310. return (uint32_t)unused;
  311. }
  312. /**
  313. * @brief Suspend execution of a thread.
  314. */
  315. osStatus_t osThreadSuspend(osThreadId_t thread_id)
  316. {
  317. struct cv2_thread *tid = (struct cv2_thread *)thread_id;
  318. if ((tid == NULL) || (is_cmsis_rtos_v2_thread(tid) == NULL)) {
  319. return osErrorParameter;
  320. }
  321. if (k_is_in_isr()) {
  322. return osErrorISR;
  323. }
  324. if (_is_thread_cmsis_inactive(&tid->z_thread)) {
  325. return osErrorResource;
  326. }
  327. k_thread_suspend(&tid->z_thread);
  328. return osOK;
  329. }
  330. /**
  331. * @brief Resume execution of a thread.
  332. */
  333. osStatus_t osThreadResume(osThreadId_t thread_id)
  334. {
  335. struct cv2_thread *tid = (struct cv2_thread *)thread_id;
  336. if ((tid == NULL) || (is_cmsis_rtos_v2_thread(tid) == NULL)) {
  337. return osErrorParameter;
  338. }
  339. if (k_is_in_isr()) {
  340. return osErrorISR;
  341. }
  342. if (_is_thread_cmsis_inactive(&tid->z_thread)) {
  343. return osErrorResource;
  344. }
  345. k_thread_resume(&tid->z_thread);
  346. return osOK;
  347. }
  348. /**
  349. * @brief Detach a thread (thread storage can be reclaimed when thread
  350. * terminates).
  351. */
  352. osStatus_t osThreadDetach(osThreadId_t thread_id)
  353. {
  354. struct cv2_thread *tid = (struct cv2_thread *)thread_id;
  355. if ((tid == NULL) || (is_cmsis_rtos_v2_thread(tid) == NULL)) {
  356. return osErrorParameter;
  357. }
  358. if (k_is_in_isr()) {
  359. return osErrorISR;
  360. }
  361. if (_is_thread_cmsis_inactive(&tid->z_thread)) {
  362. return osErrorResource;
  363. }
  364. __ASSERT(tid->attr_bits != osThreadDetached,
  365. "Thread already detached, behaviour undefined.");
  366. tid->attr_bits = osThreadDetached;
  367. k_sem_give(&tid->join_guard);
  368. return osOK;
  369. }
  370. /**
  371. * @brief Wait for specified thread to terminate.
  372. */
  373. osStatus_t osThreadJoin(osThreadId_t thread_id)
  374. {
  375. struct cv2_thread *tid = (struct cv2_thread *)thread_id;
  376. osStatus_t status = osError;
  377. if ((tid == NULL) || (is_cmsis_rtos_v2_thread(tid) == NULL)) {
  378. return osErrorParameter;
  379. }
  380. if (k_is_in_isr()) {
  381. return osErrorISR;
  382. }
  383. if (_is_thread_cmsis_inactive(&tid->z_thread)) {
  384. return osErrorResource;
  385. }
  386. if (tid->attr_bits != osThreadJoinable) {
  387. return osErrorResource;
  388. }
  389. if (!tid->has_joined) {
  390. if (k_sem_take(&tid->join_guard, K_FOREVER) != 0) {
  391. __ASSERT(0, "Failed to take from join guard.");
  392. }
  393. k_sem_give(&tid->join_guard);
  394. }
  395. if (tid->has_joined && (tid->attr_bits == osThreadJoinable)) {
  396. status = osOK;
  397. } else {
  398. status = osErrorResource;
  399. }
  400. return status;
  401. }
  402. /**
  403. * @brief Terminate execution of current running thread.
  404. */
  405. __NO_RETURN void osThreadExit(void)
  406. {
  407. struct cv2_thread *tid;
  408. __ASSERT(!k_is_in_isr(), "");
  409. tid = osThreadGetId();
  410. k_sem_give(&tid->join_guard);
  411. k_thread_abort((k_tid_t)&tid->z_thread);
  412. CODE_UNREACHABLE;
  413. }
  414. /**
  415. * @brief Terminate execution of a thread.
  416. */
  417. osStatus_t osThreadTerminate(osThreadId_t thread_id)
  418. {
  419. struct cv2_thread *tid = (struct cv2_thread *)thread_id;
  420. if ((tid == NULL) || (is_cmsis_rtos_v2_thread(tid) == NULL)) {
  421. return osErrorParameter;
  422. }
  423. if (k_is_in_isr()) {
  424. return osErrorISR;
  425. }
  426. if (_is_thread_cmsis_inactive(&tid->z_thread)) {
  427. return osErrorResource;
  428. }
  429. k_sem_give(&tid->join_guard);
  430. k_thread_abort((k_tid_t)&tid->z_thread);
  431. return osOK;
  432. }
  433. /**
  434. * @brief Get number of active threads.
  435. */
  436. uint32_t osThreadGetCount(void)
  437. {
  438. struct k_thread *thread;
  439. uint32_t count = 0U;
  440. __ASSERT(!k_is_in_isr(), "");
  441. for (thread = _kernel.threads; thread; thread = thread->next_thread) {
  442. if (get_cmsis_thread_id(thread) && z_is_thread_queued(thread)) {
  443. count++;
  444. }
  445. }
  446. return count;
  447. }
  448. /**
  449. * @brief Enumerate active threads.
  450. */
  451. uint32_t osThreadEnumerate(osThreadId_t *thread_array, uint32_t array_items)
  452. {
  453. struct k_thread *thread;
  454. uint32_t count = 0U;
  455. osThreadId_t tid;
  456. __ASSERT(!k_is_in_isr(), "");
  457. __ASSERT(thread_array != NULL, "");
  458. __ASSERT(array_items, "");
  459. for (thread = _kernel.threads; thread; thread = thread->next_thread) {
  460. if (count == array_items) {
  461. break;
  462. }
  463. tid = get_cmsis_thread_id(thread);
  464. if (tid != NULL) {
  465. thread_array[count] = tid;
  466. count++;
  467. }
  468. }
  469. return (count);
  470. }