bh_thread.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. /*
  2. * Copyright (C) 2019 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include "bh_thread.h"
  6. #include "bh_assert.h"
  7. #include "bh_log.h"
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <sys/time.h>
  11. static bool is_thread_sys_inited = false;
  12. static korp_mutex thread_list_lock;
  13. static pthread_key_t thread_local_storage_key[BH_MAX_TLS_NUM];
  14. int _vm_thread_sys_init()
  15. {
  16. unsigned i, j;
  17. int ret;
  18. if (is_thread_sys_inited)
  19. return 0;
  20. for (i = 0; i < BH_MAX_TLS_NUM; i++) {
  21. ret = pthread_key_create(&thread_local_storage_key[i], NULL);
  22. if (ret)
  23. goto fail;
  24. }
  25. ret = vm_mutex_init(&thread_list_lock);
  26. if (ret)
  27. goto fail;
  28. is_thread_sys_inited = true;
  29. return 0;
  30. fail: for (j = 0; j < i; j++)
  31. pthread_key_delete(thread_local_storage_key[j]);
  32. return -1;
  33. }
  34. void vm_thread_sys_destroy(void)
  35. {
  36. if (is_thread_sys_inited) {
  37. unsigned i;
  38. for (i = 0; i < BH_MAX_TLS_NUM; i++)
  39. pthread_key_delete(thread_local_storage_key[i]);
  40. vm_mutex_destroy(&thread_list_lock);
  41. is_thread_sys_inited = false;
  42. }
  43. }
  44. typedef struct {
  45. thread_start_routine_t start;
  46. void* stack;
  47. uint32 stack_size;
  48. void* arg;
  49. } thread_wrapper_arg;
  50. static void *vm_thread_wrapper(void *arg)
  51. {
  52. thread_wrapper_arg * targ = arg;
  53. LOG_VERBOSE("THREAD CREATE 0x%08x\n", &targ);
  54. targ->stack = (void *)((uintptr_t)(&arg) & (uintptr_t)~0xfff);
  55. _vm_tls_put(1, targ);
  56. targ->start(targ->arg);
  57. BH_FREE(targ);
  58. _vm_tls_put(1, NULL);
  59. return NULL;
  60. }
  61. int _vm_thread_create_with_prio(korp_tid *tid, thread_start_routine_t start,
  62. void *arg, unsigned int stack_size, int prio)
  63. {
  64. pthread_attr_t tattr;
  65. thread_wrapper_arg *targ;
  66. bh_assert(stack_size > 0);
  67. bh_assert(tid);
  68. bh_assert(start);
  69. *tid = INVALID_THREAD_ID;
  70. pthread_attr_init(&tattr);
  71. pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE);
  72. if (pthread_attr_setstacksize(&tattr, stack_size) != 0) {
  73. bh_debug("Invalid thread stack size %u. Min stack size on Linux = %u",
  74. stack_size, PTHREAD_STACK_MIN);
  75. pthread_attr_destroy(&tattr);
  76. return BHT_ERROR;
  77. }
  78. targ = (thread_wrapper_arg*) BH_MALLOC(sizeof(*targ));
  79. if (!targ) {
  80. pthread_attr_destroy(&tattr);
  81. return BHT_ERROR;
  82. }
  83. targ->start = start;
  84. targ->arg = arg;
  85. targ->stack_size = stack_size;
  86. if (pthread_create(tid, &tattr, vm_thread_wrapper, targ) != 0) {
  87. pthread_attr_destroy(&tattr);
  88. BH_FREE(targ);
  89. return BHT_ERROR;
  90. }
  91. pthread_attr_destroy(&tattr);
  92. return BHT_OK;
  93. }
  94. int _vm_thread_create(korp_tid *tid, thread_start_routine_t start, void *arg,
  95. unsigned int stack_size)
  96. {
  97. return _vm_thread_create_with_prio(tid, start, arg, stack_size,
  98. BH_THREAD_DEFAULT_PRIORITY);
  99. }
  100. korp_tid _vm_self_thread()
  101. {
  102. return (korp_tid) pthread_self();
  103. }
  104. void vm_thread_exit(void * code)
  105. {
  106. BH_FREE(_vm_tls_get(1));
  107. _vm_tls_put(1, NULL);
  108. pthread_exit(code);
  109. }
  110. void *_vm_tls_get(unsigned idx)
  111. {
  112. bh_assert(idx < BH_MAX_TLS_NUM);
  113. return pthread_getspecific(thread_local_storage_key[idx]);
  114. }
  115. int _vm_tls_put(unsigned idx, void * tls)
  116. {
  117. bh_assert(idx < BH_MAX_TLS_NUM);
  118. pthread_setspecific(thread_local_storage_key[idx], tls);
  119. return BHT_OK;
  120. }
  121. int _vm_mutex_init(korp_mutex *mutex)
  122. {
  123. return pthread_mutex_init(mutex, NULL) == 0 ? BHT_OK : BHT_ERROR;
  124. }
  125. int _vm_recursive_mutex_init(korp_mutex *mutex)
  126. {
  127. int ret;
  128. pthread_mutexattr_t mattr;
  129. bh_assert(mutex);
  130. ret = pthread_mutexattr_init(&mattr);
  131. if (ret)
  132. return BHT_ERROR;
  133. pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE_NP);
  134. ret = pthread_mutex_init(mutex, &mattr);
  135. pthread_mutexattr_destroy(&mattr);
  136. return ret == 0 ? BHT_OK : BHT_ERROR;
  137. }
  138. int _vm_mutex_destroy(korp_mutex *mutex)
  139. {
  140. int ret;
  141. bh_assert(mutex);
  142. ret = pthread_mutex_destroy(mutex);
  143. return ret == 0 ? BHT_OK : BHT_ERROR;
  144. }
  145. /* Returned error (EINVAL, EAGAIN and EDEADLK) from
  146. locking the mutex indicates some logic error present in
  147. the program somewhere.
  148. Don't try to recover error for an existing unknown error.*/
  149. void vm_mutex_lock(korp_mutex *mutex)
  150. {
  151. int ret;
  152. bh_assert(mutex);
  153. ret = pthread_mutex_lock(mutex);
  154. if (0 != ret) {
  155. printf("vm mutex lock failed (ret=%d)!\n", ret);
  156. exit(-1);
  157. }
  158. }
  159. int vm_mutex_trylock(korp_mutex *mutex)
  160. {
  161. int ret;
  162. bh_assert(mutex);
  163. ret = pthread_mutex_trylock(mutex);
  164. return ret == 0 ? BHT_OK : BHT_ERROR;
  165. }
  166. /* Returned error (EINVAL, EAGAIN and EPERM) from
  167. unlocking the mutex indicates some logic error present
  168. in the program somewhere.
  169. Don't try to recover error for an existing unknown error.*/
  170. void vm_mutex_unlock(korp_mutex *mutex)
  171. {
  172. int ret;
  173. bh_assert(mutex);
  174. ret = pthread_mutex_unlock(mutex);
  175. if (0 != ret) {
  176. printf("vm mutex unlock failed (ret=%d)!\n", ret);
  177. exit(-1);
  178. }
  179. }
  180. int _vm_sem_init(korp_sem* sem, unsigned int c)
  181. {
  182. int ret;
  183. bh_assert(sem);
  184. ret = sem_init(sem, 0, c);
  185. return ret == 0 ? BHT_OK : BHT_ERROR;
  186. }
  187. int _vm_sem_destroy(korp_sem *sem)
  188. {
  189. int ret;
  190. bh_assert(sem);
  191. ret = sem_destroy(sem);
  192. return ret == 0 ? BHT_OK : BHT_ERROR;
  193. }
  194. int _vm_sem_wait(korp_sem *sem)
  195. {
  196. int ret;
  197. bh_assert(sem);
  198. ret = sem_wait(sem);
  199. return ret == 0 ? BHT_OK : BHT_ERROR;
  200. }
  201. int _vm_sem_reltimedwait(korp_sem *sem, int mills)
  202. {
  203. int ret = BHT_OK;
  204. struct timespec timeout;
  205. const int mills_per_sec = 1000;
  206. const int mills_to_nsec = 1E6;
  207. bh_assert(sem);
  208. if (mills == (int)BHT_WAIT_FOREVER) {
  209. ret = sem_wait(sem);
  210. } else {
  211. timeout.tv_sec = mills / mills_per_sec;
  212. timeout.tv_nsec = (mills % mills_per_sec) * mills_to_nsec;
  213. timeout.tv_sec += time(NULL);
  214. ret = sem_timedwait(sem, &timeout);
  215. }
  216. if (ret != BHT_OK) {
  217. if (errno == BHT_TIMEDOUT) {
  218. ret = BHT_TIMEDOUT;
  219. errno = 0;
  220. } else {
  221. bh_debug("Faliure happens when timed wait is called");
  222. bh_assert(0);
  223. }
  224. }
  225. return ret;
  226. }
  227. int _vm_sem_post(korp_sem *sem)
  228. {
  229. bh_assert(sem);
  230. return sem_post(sem) == 0 ? BHT_OK : BHT_ERROR;
  231. }
  232. int _vm_cond_init(korp_cond *cond)
  233. {
  234. bh_assert(cond);
  235. if (pthread_cond_init(cond, NULL) != BHT_OK)
  236. return BHT_ERROR;
  237. return BHT_OK;
  238. }
  239. int _vm_cond_destroy(korp_cond *cond)
  240. {
  241. bh_assert(cond);
  242. if (pthread_cond_destroy(cond) != BHT_OK)
  243. return BHT_ERROR;
  244. return BHT_OK;
  245. }
  246. int _vm_cond_wait(korp_cond *cond, korp_mutex *mutex)
  247. {
  248. bh_assert(cond);
  249. bh_assert(mutex);
  250. if (pthread_cond_wait(cond, mutex) != BHT_OK)
  251. return BHT_ERROR;
  252. return BHT_OK;
  253. }
  254. static void msec_nsec_to_abstime(struct timespec *ts, int64 msec, int32 nsec)
  255. {
  256. struct timeval tv;
  257. gettimeofday(&tv, NULL);
  258. ts->tv_sec = (long int)(tv.tv_sec + msec / 1000);
  259. ts->tv_nsec = (long int)(tv.tv_usec * 1000 + (msec % 1000) * 1000000 + nsec);
  260. if (ts->tv_nsec >= 1000000000L) {
  261. ts->tv_sec++;
  262. ts->tv_nsec -= 1000000000L;
  263. }
  264. }
  265. int _vm_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, int mills)
  266. {
  267. int ret;
  268. struct timespec abstime;
  269. if (mills == (int)BHT_WAIT_FOREVER)
  270. ret = pthread_cond_wait(cond, mutex);
  271. else {
  272. msec_nsec_to_abstime(&abstime, mills, 0);
  273. ret = pthread_cond_timedwait(cond, mutex, &abstime);
  274. }
  275. if (ret != BHT_OK && ret != BHT_TIMEDOUT)
  276. return BHT_ERROR;
  277. return BHT_OK;
  278. }
  279. int _vm_cond_signal(korp_cond *cond)
  280. {
  281. bh_assert(cond);
  282. if (pthread_cond_signal(cond) != BHT_OK)
  283. return BHT_ERROR;
  284. return BHT_OK;
  285. }
  286. int _vm_cond_broadcast(korp_cond *cond)
  287. {
  288. bh_assert(cond);
  289. if (pthread_cond_broadcast(cond) != BHT_OK)
  290. return BHT_ERROR;
  291. return BHT_OK;
  292. }
  293. int _vm_thread_cancel(korp_tid thread)
  294. {
  295. return pthread_cancel(thread);
  296. }
  297. int _vm_thread_join(korp_tid thread, void **value_ptr, int mills)
  298. {
  299. return pthread_join(thread, value_ptr);
  300. }
  301. int _vm_thread_detach(korp_tid thread)
  302. {
  303. return pthread_detach(thread);
  304. }