riot_thread.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. /*
  2. * Copyright (C) 2019 Intel Corporation. All rights reserved.
  3. * Copyright (C) 2020 TU Bergakademie Freiberg Karl Fessel
  4. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  5. */
  6. #include "platform_api_vmcore.h"
  7. #include "platform_api_extension.h"
  8. #include <panic.h>
  9. #include <sema.h>
  10. #include <ztimer.h>
  11. /* clang-format off */
  12. #define bh_assert(v) do { \
  13. if (!(v)) { \
  14. printf("\nASSERTION FAILED: %s, at %s, line %d\n", \
  15. #v, __FILE__, __LINE__); \
  16. core_panic(0, 0/*expr_string*/); \
  17. while (1); \
  18. } \
  19. } while (0)
  20. /* clang-format on */
  21. struct os_thread_data;
  22. typedef struct os_thread_wait_node {
  23. sema_t sem;
  24. void *ret;
  25. os_thread_wait_list next;
  26. } os_thread_wait_node;
  27. // all information for thread to cleanup it self
  28. typedef struct os_thread_data {
  29. /* Next thread data */
  30. struct os_thread_data *next;
  31. /* thread handle */
  32. kernel_pid_t tid;
  33. /* Thread start routine */
  34. thread_start_routine_t start_routine;
  35. /* Thread start routine argument */
  36. void *arg;
  37. /* thread local root */
  38. void *tlr;
  39. /* Lock for waiting list */
  40. mutex_t wait_list_lock;
  41. /* Waiting list of other threads who are joining this thread */
  42. os_thread_wait_list thread_wait_list;
  43. /* Thread stack size */
  44. unsigned stack_size;
  45. /* Thread stack */
  46. char stack[1];
  47. } os_thread_data;
  48. typedef struct os_thread_obj {
  49. korp_tid thread;
  50. /* Whether the thread is terminated and this thread object is to
  51. be freed in the future. */
  52. bool to_be_freed;
  53. struct os_thread_obj *next;
  54. } os_thread_obj;
  55. static bool is_thread_sys_inited = false;
  56. /* Lock for thread data list */
  57. static mutex_t thread_data_lock;
  58. /* Thread data list */
  59. static os_thread_data *thread_data_list = NULL;
  60. static void
  61. thread_data_list_add(os_thread_data *thread_data)
  62. {
  63. mutex_lock(&thread_data_lock);
  64. if (!thread_data_list)
  65. thread_data_list = thread_data;
  66. else {
  67. /* If already in list, just return */
  68. os_thread_data *p = thread_data_list;
  69. while (p) {
  70. if (p == thread_data) {
  71. mutex_unlock(&thread_data_lock);
  72. return;
  73. }
  74. p = p->next;
  75. }
  76. /* Set as head of list */
  77. thread_data->next = thread_data_list;
  78. thread_data_list = thread_data;
  79. }
  80. mutex_unlock(&thread_data_lock);
  81. }
  82. static void
  83. thread_data_list_remove(os_thread_data *thread_data)
  84. {
  85. mutex_lock(&thread_data_lock);
  86. if (thread_data_list) {
  87. if (thread_data_list == thread_data)
  88. thread_data_list = thread_data_list->next;
  89. else {
  90. /* Search and remove it from list */
  91. os_thread_data *p = thread_data_list;
  92. while (p && p->next != thread_data)
  93. p = p->next;
  94. if (p && p->next == thread_data)
  95. p->next = p->next->next;
  96. }
  97. }
  98. mutex_unlock(&thread_data_lock);
  99. }
  100. static os_thread_data *
  101. thread_data_list_lookup(korp_tid tid)
  102. {
  103. mutex_lock(&thread_data_lock);
  104. if (thread_data_list) {
  105. os_thread_data *p = thread_data_list;
  106. while (p) {
  107. if (p->tid == tid) {
  108. /* Found */
  109. mutex_unlock(&thread_data_lock);
  110. return p;
  111. }
  112. p = p->next;
  113. }
  114. }
  115. mutex_unlock(&thread_data_lock);
  116. return NULL;
  117. }
  118. int
  119. os_thread_sys_init()
  120. {
  121. if (is_thread_sys_inited)
  122. return BHT_OK;
  123. mutex_init(&thread_data_lock);
  124. is_thread_sys_inited = true;
  125. return BHT_OK;
  126. }
  127. void
  128. os_thread_sys_destroy()
  129. {
  130. if (is_thread_sys_inited) {
  131. is_thread_sys_inited = false;
  132. }
  133. }
  134. static os_thread_data *
  135. thread_data_current()
  136. {
  137. kernel_pid_t tid = thread_getpid();
  138. return thread_data_list_lookup(tid);
  139. }
  140. static void
  141. os_thread_cleanup(void)
  142. {
  143. // TODO Check this (Join sema trigger, cleanup of thread_data)
  144. os_thread_data *thread_data = thread_data_current();
  145. bh_assert(thread_data != NULL);
  146. mutex_lock(&thread_data->wait_list_lock);
  147. if (thread_data->thread_wait_list) {
  148. /* Signal each joining thread */
  149. os_thread_wait_list head = thread_data->thread_wait_list;
  150. while (head) {
  151. os_thread_wait_list next = head->next;
  152. head->ret = thread_data->arg;
  153. sema_post(&head->sem);
  154. head = next;
  155. }
  156. thread_data->thread_wait_list = NULL;
  157. }
  158. mutex_unlock(&thread_data->wait_list_lock);
  159. thread_data_list_remove(thread_data);
  160. }
  161. static void *
  162. os_thread_wrapper(void *thread_data)
  163. {
  164. /* Set thread custom data */
  165. os_thread_data *t = (os_thread_data *)thread_data;
  166. t->tid = thread_getpid();
  167. thread_data_list_add(t);
  168. // save the return value to arg since it is not need after the call
  169. t->arg = (t->start_routine)(t->arg);
  170. os_thread_cleanup(); // internal structures and joiners
  171. BH_FREE(thread_data);
  172. sched_task_exit(); // stop thread //clean
  173. return NULL; // never reached
  174. }
  175. int
  176. os_thread_create(korp_tid *p_tid, thread_start_routine_t start, void *arg,
  177. unsigned int stack_size)
  178. {
  179. return os_thread_create_with_prio(p_tid, start, arg, stack_size,
  180. BH_THREAD_DEFAULT_PRIORITY);
  181. }
  182. int
  183. os_thread_create_with_prio(korp_tid *p_tid, thread_start_routine_t start,
  184. void *arg, unsigned int stack_size, int prio)
  185. {
  186. kernel_pid_t tid;
  187. os_thread_data *thread_data;
  188. unsigned thread_data_size;
  189. if (!p_tid || !stack_size)
  190. return BHT_ERROR;
  191. /* Create and initialize thread data */
  192. thread_data_size = offsetof(os_thread_data, stack) + stack_size;
  193. if (!(thread_data = BH_MALLOC(thread_data_size))) {
  194. return BHT_ERROR;
  195. }
  196. memset(thread_data, 0, thread_data_size);
  197. mutex_init(&thread_data->wait_list_lock);
  198. thread_data->stack_size = stack_size;
  199. thread_data->start_routine = start;
  200. thread_data->arg = arg;
  201. /* Create the thread &*/
  202. if (!((tid = thread_create(thread_data->stack, stack_size, prio, 0,
  203. os_thread_wrapper, thread_data, "WASM")))) {
  204. BH_FREE(thread_data);
  205. return BHT_ERROR;
  206. }
  207. thread_data->tid = tid;
  208. /* Set thread custom data */
  209. thread_data_list_add(thread_data);
  210. *p_tid = tid;
  211. return BHT_OK;
  212. }
  213. korp_tid
  214. os_self_thread()
  215. {
  216. return (korp_tid)thread_getpid();
  217. }
  218. int
  219. os_thread_join(korp_tid thread, void **value_ptr)
  220. {
  221. // will test if thread is still working,
  222. // wait if it is
  223. os_thread_data *thread_data;
  224. os_thread_wait_node node;
  225. sema_create(&node.sem, 0);
  226. node.next = NULL;
  227. /* Get thread data */
  228. thread_data = thread_data_list_lookup(thread);
  229. if (thread_data == NULL) {
  230. // thread not found
  231. sema_destroy(&node.sem);
  232. return BHT_ERROR;
  233. }
  234. bh_assert(thread_data != NULL);
  235. mutex_lock(&thread_data->wait_list_lock);
  236. if (!thread_data->thread_wait_list)
  237. thread_data->thread_wait_list = &node;
  238. else {
  239. /* Add to end of waiting list */
  240. os_thread_wait_node *p = thread_data->thread_wait_list;
  241. while (p->next)
  242. p = p->next;
  243. p->next = &node;
  244. }
  245. mutex_unlock(&thread_data->wait_list_lock);
  246. sema_wait(&node.sem);
  247. // get the return value pointer conted may not be available after return
  248. if (value_ptr)
  249. (*value_ptr) = node.ret;
  250. /* Wait some time for the thread to be actually terminated */
  251. // TODO: k_sleep(100);
  252. // TODO: bump target prio to make it finish and free its resources
  253. thread_yield();
  254. // node has done its job
  255. sema_destroy(&node.sem);
  256. return BHT_OK;
  257. }
  258. // int vm_mutex_trylock(korp_mutex *mutex)
  259. // {
  260. // return mutex_trylock(mutex);
  261. // }
  262. int
  263. os_mutex_init(korp_mutex *mutex)
  264. {
  265. mutex_init(mutex);
  266. return BHT_OK;
  267. }
  268. int
  269. os_mutex_destroy(korp_mutex *mutex)
  270. {
  271. (void)mutex;
  272. return BHT_OK;
  273. }
  274. int
  275. os_mutex_lock(korp_mutex *mutex)
  276. {
  277. mutex_lock(mutex);
  278. return 0; // Riot mutexes do not return until success
  279. }
  280. int
  281. os_mutex_unlock(korp_mutex *mutex)
  282. {
  283. mutex_unlock(mutex);
  284. return 0; // Riot mutexes do not return until success
  285. }
  286. int
  287. os_cond_init(korp_cond *cond)
  288. {
  289. mutex_init(&cond->wait_list_lock);
  290. cond->thread_wait_list = NULL;
  291. return BHT_OK;
  292. }
  293. int
  294. os_cond_destroy(korp_cond *cond)
  295. {
  296. (void)cond;
  297. return BHT_OK;
  298. }
  299. static int
  300. os_cond_wait_internal(korp_cond *cond, korp_mutex *mutex, bool timed,
  301. uint64 useconds)
  302. {
  303. os_thread_wait_node *node;
  304. /* Create wait node and append it to wait list */
  305. if (!(node = BH_MALLOC(sizeof(os_thread_wait_node))))
  306. return BHT_ERROR;
  307. sema_create(&node->sem, 0);
  308. node->next = NULL;
  309. mutex_lock(&cond->wait_list_lock);
  310. if (!cond->thread_wait_list)
  311. cond->thread_wait_list = node;
  312. else {
  313. /* Add to end of wait list */
  314. os_thread_wait_node *p = cond->thread_wait_list;
  315. while (p->next)
  316. p = p->next;
  317. p->next = node;
  318. }
  319. mutex_unlock(&cond->wait_list_lock);
  320. /* Unlock mutex, wait sem and lock mutex again */
  321. mutex_unlock(mutex);
  322. if (timed)
  323. sema_wait(&node->sem);
  324. else
  325. sema_wait_timed_ztimer(&node->sem, ZTIMER_USEC, useconds);
  326. mutex_lock(mutex);
  327. /* Remove wait node from wait list */
  328. mutex_lock(&cond->wait_list_lock);
  329. if (cond->thread_wait_list == node)
  330. cond->thread_wait_list = node->next;
  331. else {
  332. /* Remove from the wait list */
  333. os_thread_wait_node *p = cond->thread_wait_list;
  334. while (p->next != node)
  335. p = p->next;
  336. p->next = node->next;
  337. }
  338. BH_FREE(node);
  339. mutex_unlock(&cond->wait_list_lock);
  340. return BHT_OK;
  341. }
  342. int
  343. os_cond_wait(korp_cond *cond, korp_mutex *mutex)
  344. {
  345. return os_cond_wait_internal(cond, mutex, false, 0);
  346. }
  347. int
  348. os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, uint64 useconds)
  349. {
  350. return os_cond_wait_internal(cond, mutex, (useconds != BHT_WAIT_FOREVER),
  351. useconds);
  352. }
  353. int
  354. os_cond_signal(korp_cond *cond)
  355. {
  356. /* Signal the head wait node of wait list */
  357. mutex_lock(&cond->wait_list_lock);
  358. if (cond->thread_wait_list)
  359. sema_post(&cond->thread_wait_list->sem);
  360. mutex_unlock(&cond->wait_list_lock);
  361. return BHT_OK;
  362. }
  363. uint8 *
  364. os_thread_get_stack_boundary()
  365. {
  366. #if defined(DEVELHELP) || defined(SCHED_TEST_STACK) \
  367. || defined(MODULE_MPU_STACK_GUARD)
  368. return (uint8 *)thread_get_active()->stack_start;
  369. #else
  370. return NULL;
  371. #endif
  372. }
  373. void
  374. os_thread_jit_write_protect_np(bool enabled)
  375. {}