win_thread.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. /*
  2. * Copyright (C) 2019 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include "platform_api_vmcore.h"
  6. #include "platform_api_extension.h"
  7. #define bh_assert(v) assert(v)
  8. #define BH_SEM_COUNT_MAX 0xFFFF
  9. struct os_thread_data;
  10. typedef struct os_thread_wait_node {
  11. korp_sem sem;
  12. void *retval;
  13. os_thread_wait_list next;
  14. } os_thread_wait_node;
  15. typedef struct os_thread_data {
  16. /* Next thread data */
  17. struct os_thread_data *next;
  18. /* Thread data of parent thread */
  19. struct os_thread_data *parent;
  20. /* Thread Id */
  21. DWORD thread_id;
  22. /* Thread start routine */
  23. thread_start_routine_t start_routine;
  24. /* Thread start routine argument */
  25. void *arg;
  26. /* Wait node of current thread */
  27. os_thread_wait_node wait_node;
  28. /* Wait cond */
  29. korp_cond wait_cond;
  30. /* Wait lock */
  31. korp_mutex wait_lock;
  32. /* Waiting list of other threads who are joining this thread */
  33. os_thread_wait_list thread_wait_list;
  34. } os_thread_data;
  35. static bool is_thread_sys_inited = false;
  36. /* Thread data of supervisor thread */
  37. static os_thread_data supervisor_thread_data;
  38. /* Thread data key */
  39. static DWORD thread_data_key;
  40. int
  41. os_sem_init(korp_sem *sem);
  42. int
  43. os_sem_destroy(korp_sem *sem);
  44. int
  45. os_sem_wait(korp_sem *sem);
  46. int
  47. os_sem_reltimed_wait(korp_sem *sem, uint64 useconds);
  48. int
  49. os_sem_signal(korp_sem *sem);
  50. int
  51. os_thread_sys_init()
  52. {
  53. if (is_thread_sys_inited)
  54. return BHT_OK;
  55. if ((thread_data_key = TlsAlloc()) == TLS_OUT_OF_INDEXES)
  56. return BHT_ERROR;
  57. /* Initialize supervisor thread data */
  58. memset(&supervisor_thread_data, 0, sizeof(os_thread_data));
  59. supervisor_thread_data.thread_id = GetCurrentThreadId();
  60. if (os_sem_init(&supervisor_thread_data.wait_node.sem) != BHT_OK)
  61. goto fail1;
  62. if (os_mutex_init(&supervisor_thread_data.wait_lock) != BHT_OK)
  63. goto fail2;
  64. if (os_cond_init(&supervisor_thread_data.wait_cond) != BHT_OK)
  65. goto fail3;
  66. if (!TlsSetValue(thread_data_key, &supervisor_thread_data))
  67. goto fail4;
  68. is_thread_sys_inited = true;
  69. return BHT_OK;
  70. fail4:
  71. os_cond_destroy(&supervisor_thread_data.wait_cond);
  72. fail3:
  73. os_mutex_destroy(&supervisor_thread_data.wait_lock);
  74. fail2:
  75. os_sem_destroy(&supervisor_thread_data.wait_node.sem);
  76. fail1:
  77. TlsFree(thread_data_key);
  78. return BHT_ERROR;
  79. }
  80. void
  81. os_thread_sys_destroy()
  82. {
  83. if (is_thread_sys_inited) {
  84. os_cond_destroy(&supervisor_thread_data.wait_cond);
  85. os_mutex_destroy(&supervisor_thread_data.wait_lock);
  86. os_sem_destroy(&supervisor_thread_data.wait_node.sem);
  87. memset(&supervisor_thread_data, 0, sizeof(os_thread_data));
  88. TlsFree(thread_data_key);
  89. thread_data_key = 0;
  90. is_thread_sys_inited = false;
  91. }
  92. }
  93. static os_thread_data *
  94. thread_data_current()
  95. {
  96. return (os_thread_data *)TlsGetValue(thread_data_key);
  97. }
  98. static void
  99. os_thread_cleanup(void *retval)
  100. {
  101. os_thread_data *thread_data = thread_data_current();
  102. bh_assert(thread_data != NULL);
  103. os_mutex_lock(&thread_data->wait_lock);
  104. if (thread_data->thread_wait_list) {
  105. /* Signal each joining thread */
  106. os_thread_wait_list head = thread_data->thread_wait_list;
  107. while (head) {
  108. os_thread_wait_list next = head->next;
  109. head->retval = retval;
  110. os_sem_signal(&head->sem);
  111. head = next;
  112. }
  113. thread_data->thread_wait_list = NULL;
  114. }
  115. os_mutex_unlock(&thread_data->wait_lock);
  116. /* Destroy resources */
  117. os_cond_destroy(&thread_data->wait_cond);
  118. os_sem_destroy(&thread_data->wait_node.sem);
  119. os_mutex_destroy(&thread_data->wait_lock);
  120. BH_FREE(thread_data);
  121. }
  122. static unsigned __stdcall os_thread_wrapper(void *arg)
  123. {
  124. os_thread_data *thread_data = arg;
  125. os_thread_data *parent = thread_data->parent;
  126. void *retval;
  127. bool result;
  128. os_printf("THREAD CREATED %p\n", thread_data);
  129. os_mutex_lock(&parent->wait_lock);
  130. thread_data->thread_id = GetCurrentThreadId();
  131. result = TlsSetValue(thread_data_key, thread_data);
  132. #ifdef OS_ENABLE_HW_BOUND_CHECK
  133. if (result)
  134. result = os_thread_signal_init() == 0 ? true : false;
  135. #endif
  136. /* Notify parent thread */
  137. os_cond_signal(&parent->wait_cond);
  138. os_mutex_unlock(&parent->wait_lock);
  139. if (!result)
  140. return -1;
  141. retval = thread_data->start_routine(thread_data->arg);
  142. os_thread_cleanup(retval);
  143. return 0;
  144. }
  145. int
  146. os_thread_create_with_prio(korp_tid *p_tid, thread_start_routine_t start,
  147. void *arg, unsigned int stack_size, int prio)
  148. {
  149. os_thread_data *parent = thread_data_current();
  150. os_thread_data *thread_data;
  151. if (!p_tid || !start)
  152. return BHT_ERROR;
  153. if (stack_size < BH_APPLET_PRESERVED_STACK_SIZE)
  154. stack_size = BH_APPLET_PRESERVED_STACK_SIZE;
  155. if (!(thread_data = BH_MALLOC(sizeof(os_thread_data))))
  156. return BHT_ERROR;
  157. memset(thread_data, 0, sizeof(os_thread_data));
  158. thread_data->parent = parent;
  159. thread_data->start_routine = start;
  160. thread_data->arg = arg;
  161. if (os_sem_init(&thread_data->wait_node.sem) != BHT_OK)
  162. goto fail1;
  163. if (os_mutex_init(&thread_data->wait_lock) != BHT_OK)
  164. goto fail2;
  165. if (os_cond_init(&thread_data->wait_cond) != BHT_OK)
  166. goto fail3;
  167. os_mutex_lock(&parent->wait_lock);
  168. if (!_beginthreadex(NULL, stack_size, os_thread_wrapper, thread_data, 0,
  169. NULL)) {
  170. os_mutex_unlock(&parent->wait_lock);
  171. goto fail4;
  172. }
  173. /* Wait for the thread routine to set thread_data's tid
  174. and add thread_data to thread data list */
  175. os_cond_wait(&parent->wait_cond, &parent->wait_lock);
  176. os_mutex_unlock(&parent->wait_lock);
  177. *p_tid = (korp_tid)thread_data;
  178. return BHT_OK;
  179. fail4:
  180. os_cond_destroy(&thread_data->wait_cond);
  181. fail3:
  182. os_mutex_destroy(&thread_data->wait_lock);
  183. fail2:
  184. os_sem_destroy(&thread_data->wait_node.sem);
  185. fail1:
  186. BH_FREE(thread_data);
  187. return BHT_ERROR;
  188. }
  189. int
  190. os_thread_create(korp_tid *tid, thread_start_routine_t start, void *arg,
  191. unsigned int stack_size)
  192. {
  193. return os_thread_create_with_prio(tid, start, arg, stack_size,
  194. BH_THREAD_DEFAULT_PRIORITY);
  195. }
  196. korp_tid
  197. os_self_thread()
  198. {
  199. return (korp_tid)TlsGetValue(thread_data_key);
  200. }
  201. int
  202. os_thread_join(korp_tid thread, void **p_retval)
  203. {
  204. os_thread_data *thread_data, *curr_thread_data;
  205. /* Get thread data of current thread */
  206. curr_thread_data = thread_data_current();
  207. curr_thread_data->wait_node.next = NULL;
  208. /* Get thread data of thread to join */
  209. thread_data = (os_thread_data *)thread;
  210. bh_assert(thread_data);
  211. os_mutex_lock(&thread_data->wait_lock);
  212. if (!thread_data->thread_wait_list)
  213. thread_data->thread_wait_list = &curr_thread_data->wait_node;
  214. else {
  215. /* Add to end of waiting list */
  216. os_thread_wait_node *p = thread_data->thread_wait_list;
  217. while (p->next)
  218. p = p->next;
  219. p->next = &curr_thread_data->wait_node;
  220. }
  221. os_mutex_unlock(&thread_data->wait_lock);
  222. /* Wait the sem */
  223. os_sem_wait(&curr_thread_data->wait_node.sem);
  224. if (p_retval)
  225. *p_retval = curr_thread_data->wait_node.retval;
  226. return BHT_OK;
  227. }
  228. int
  229. os_thread_detach(korp_tid thread)
  230. {
  231. /* Do nothing */
  232. return BHT_OK;
  233. (void)thread;
  234. }
  235. void
  236. os_thread_exit(void *retval)
  237. {
  238. os_thread_cleanup(retval);
  239. _endthreadex(0);
  240. }
  241. int
  242. os_thread_env_init()
  243. {
  244. os_thread_data *thread_data = TlsGetValue(thread_data_key);
  245. if (thread_data)
  246. /* Already created */
  247. return BHT_OK;
  248. if (!(thread_data = BH_MALLOC(sizeof(os_thread_data))))
  249. return BHT_ERROR;
  250. memset(thread_data, 0, sizeof(os_thread_data));
  251. thread_data->thread_id = GetCurrentThreadId();
  252. if (os_sem_init(&thread_data->wait_node.sem) != BHT_OK)
  253. goto fail1;
  254. if (os_mutex_init(&thread_data->wait_lock) != BHT_OK)
  255. goto fail2;
  256. if (os_cond_init(&thread_data->wait_cond) != BHT_OK)
  257. goto fail3;
  258. if (!TlsSetValue(thread_data_key, thread_data))
  259. goto fail4;
  260. return BHT_OK;
  261. fail4:
  262. os_cond_destroy(&thread_data->wait_cond);
  263. fail3:
  264. os_mutex_destroy(&thread_data->wait_lock);
  265. fail2:
  266. os_sem_destroy(&thread_data->wait_node.sem);
  267. fail1:
  268. BH_FREE(thread_data);
  269. return BHT_ERROR;
  270. }
  271. void
  272. os_thread_env_destroy()
  273. {
  274. os_thread_data *thread_data = TlsGetValue(thread_data_key);
  275. /* Note that supervisor_thread_data's resources will be destroyed
  276. by os_thread_sys_destroy() */
  277. if (thread_data && thread_data != &supervisor_thread_data) {
  278. TlsSetValue(thread_data_key, NULL);
  279. os_cond_destroy(&thread_data->wait_cond);
  280. os_mutex_destroy(&thread_data->wait_lock);
  281. os_sem_destroy(&thread_data->wait_node.sem);
  282. BH_FREE(thread_data);
  283. }
  284. }
  285. int
  286. os_sem_init(korp_sem *sem)
  287. {
  288. bh_assert(sem);
  289. *sem = CreateSemaphore(NULL, 0, BH_SEM_COUNT_MAX, NULL);
  290. return (*sem != NULL) ? BHT_OK : BHT_ERROR;
  291. }
  292. int
  293. os_sem_destroy(korp_sem *sem)
  294. {
  295. bh_assert(sem);
  296. CloseHandle(*sem);
  297. return BHT_OK;
  298. }
  299. int
  300. os_sem_wait(korp_sem *sem)
  301. {
  302. DWORD ret;
  303. bh_assert(sem);
  304. ret = WaitForSingleObject(*sem, INFINITE);
  305. if (ret == WAIT_OBJECT_0)
  306. return BHT_OK;
  307. else if (ret == WAIT_TIMEOUT)
  308. return (int)WAIT_TIMEOUT;
  309. else /* WAIT_FAILED or others */
  310. return BHT_ERROR;
  311. }
  312. int
  313. os_sem_reltimed_wait(korp_sem *sem, uint64 useconds)
  314. {
  315. uint64 mseconds_64;
  316. DWORD ret, mseconds;
  317. bh_assert(sem);
  318. if (useconds == BHT_WAIT_FOREVER)
  319. mseconds = INFINITE;
  320. else {
  321. mseconds_64 = useconds / 1000;
  322. if (mseconds_64 < (uint64)(UINT32_MAX - 1)) {
  323. mseconds = (uint32)mseconds_64;
  324. }
  325. else {
  326. mseconds = UINT32_MAX - 1;
  327. os_printf("Warning: os_sem_reltimed_wait exceeds limit, "
  328. "set to max timeout instead\n");
  329. }
  330. }
  331. ret = WaitForSingleObject(*sem, mseconds);
  332. if (ret == WAIT_OBJECT_0)
  333. return BHT_OK;
  334. else if (ret == WAIT_TIMEOUT)
  335. return (int)WAIT_TIMEOUT;
  336. else /* WAIT_FAILED or others */
  337. return BHT_ERROR;
  338. }
  339. int
  340. os_sem_signal(korp_sem *sem)
  341. {
  342. bh_assert(sem);
  343. return ReleaseSemaphore(*sem, 1, NULL) != FALSE ? BHT_OK : BHT_ERROR;
  344. }
  345. int
  346. os_mutex_init(korp_mutex *mutex)
  347. {
  348. bh_assert(mutex);
  349. *mutex = CreateMutex(NULL, FALSE, NULL);
  350. return (*mutex != NULL) ? BHT_OK : BHT_ERROR;
  351. }
  352. int
  353. os_recursive_mutex_init(korp_mutex *mutex)
  354. {
  355. bh_assert(mutex);
  356. *mutex = CreateMutex(NULL, FALSE, NULL);
  357. return (*mutex != NULL) ? BHT_OK : BHT_ERROR;
  358. }
  359. int
  360. os_mutex_destroy(korp_mutex *mutex)
  361. {
  362. assert(mutex);
  363. return CloseHandle(*mutex) ? BHT_OK : BHT_ERROR;
  364. }
  365. int
  366. os_mutex_lock(korp_mutex *mutex)
  367. {
  368. int ret;
  369. assert(mutex);
  370. ret = WaitForSingleObject(*mutex, INFINITE);
  371. return ret != WAIT_FAILED ? BHT_OK : BHT_ERROR;
  372. }
  373. int
  374. os_mutex_unlock(korp_mutex *mutex)
  375. {
  376. bh_assert(mutex);
  377. return ReleaseMutex(*mutex) ? BHT_OK : BHT_ERROR;
  378. }
  379. int
  380. os_cond_init(korp_cond *cond)
  381. {
  382. bh_assert(cond);
  383. if (os_mutex_init(&cond->wait_list_lock) != BHT_OK)
  384. return BHT_ERROR;
  385. cond->thread_wait_list = NULL;
  386. return BHT_OK;
  387. }
  388. int
  389. os_cond_destroy(korp_cond *cond)
  390. {
  391. bh_assert(cond);
  392. os_mutex_destroy(&cond->wait_list_lock);
  393. return BHT_OK;
  394. }
  395. static int
  396. os_cond_wait_internal(korp_cond *cond, korp_mutex *mutex, bool timed,
  397. uint64 useconds)
  398. {
  399. os_thread_wait_node *node = &thread_data_current()->wait_node;
  400. node->next = NULL;
  401. bh_assert(cond);
  402. bh_assert(mutex);
  403. os_mutex_lock(&cond->wait_list_lock);
  404. if (!cond->thread_wait_list)
  405. cond->thread_wait_list = node;
  406. else {
  407. /* Add to end of wait list */
  408. os_thread_wait_node *p = cond->thread_wait_list;
  409. while (p->next)
  410. p = p->next;
  411. p->next = node;
  412. }
  413. os_mutex_unlock(&cond->wait_list_lock);
  414. /* Unlock mutex, wait sem and lock mutex again */
  415. os_mutex_unlock(mutex);
  416. if (timed)
  417. os_sem_reltimed_wait(&node->sem, useconds);
  418. else
  419. os_sem_wait(&node->sem);
  420. os_mutex_lock(mutex);
  421. /* Remove wait node from wait list */
  422. os_mutex_lock(&cond->wait_list_lock);
  423. if (cond->thread_wait_list == node)
  424. cond->thread_wait_list = node->next;
  425. else {
  426. /* Remove from the wait list */
  427. os_thread_wait_node *p = cond->thread_wait_list;
  428. while (p->next != node)
  429. p = p->next;
  430. p->next = node->next;
  431. }
  432. os_mutex_unlock(&cond->wait_list_lock);
  433. return BHT_OK;
  434. }
  435. int
  436. os_cond_wait(korp_cond *cond, korp_mutex *mutex)
  437. {
  438. return os_cond_wait_internal(cond, mutex, false, 0);
  439. }
  440. int
  441. os_cond_reltimedwait(korp_cond *cond, korp_mutex *mutex, uint64 useconds)
  442. {
  443. if (useconds == BHT_WAIT_FOREVER) {
  444. return os_cond_wait_internal(cond, mutex, false, 0);
  445. }
  446. else {
  447. return os_cond_wait_internal(cond, mutex, true, useconds);
  448. }
  449. }
  450. int
  451. os_cond_signal(korp_cond *cond)
  452. {
  453. /* Signal the head wait node of wait list */
  454. os_mutex_lock(&cond->wait_list_lock);
  455. if (cond->thread_wait_list)
  456. os_sem_signal(&cond->thread_wait_list->sem);
  457. os_mutex_unlock(&cond->wait_list_lock);
  458. return BHT_OK;
  459. }
  460. static os_thread_local_attribute uint8 *thread_stack_boundary = NULL;
  461. #if _WIN32_WINNT < 0x0602
  462. static ULONG
  463. GetCurrentThreadStackLimits_Win7(PULONG_PTR p_low_limit,
  464. PULONG_PTR p_high_limit)
  465. {
  466. MEMORY_BASIC_INFORMATION mbi;
  467. NT_TIB *tib = (NT_TIB *)NtCurrentTeb();
  468. if (!tib) {
  469. os_printf("warning: NtCurrentTeb() failed\n");
  470. return -1;
  471. }
  472. *p_high_limit = (ULONG_PTR)tib->StackBase;
  473. if (VirtualQuery(tib->StackLimit, &mbi, sizeof(mbi))) {
  474. *p_low_limit = (ULONG_PTR)mbi.AllocationBase;
  475. return 0;
  476. }
  477. os_printf("warning: VirtualQuery() failed\n");
  478. return GetLastError();
  479. }
  480. #endif
  481. uint8 *
  482. os_thread_get_stack_boundary()
  483. {
  484. ULONG_PTR low_limit = 0, high_limit = 0;
  485. uint32 page_size;
  486. if (thread_stack_boundary)
  487. return thread_stack_boundary;
  488. page_size = os_getpagesize();
  489. #if _WIN32_WINNT >= 0x0602
  490. GetCurrentThreadStackLimits(&low_limit, &high_limit);
  491. #else
  492. if (0 != GetCurrentThreadStackLimits_Win7(&low_limit, &high_limit)) {
  493. return NULL;
  494. }
  495. #endif
  496. /* 4 pages are set unaccessible by system, we reserved
  497. one more page at least for safety */
  498. thread_stack_boundary = (uint8 *)(uintptr_t)low_limit + page_size * 5;
  499. return thread_stack_boundary;
  500. }
  501. #ifdef OS_ENABLE_HW_BOUND_CHECK
  502. static os_thread_local_attribute bool thread_signal_inited = false;
  503. int
  504. os_thread_signal_init()
  505. {
  506. ULONG StackSizeInBytes = 16 * 1024;
  507. bool ret;
  508. if (thread_signal_inited)
  509. return true;
  510. ret = SetThreadStackGuarantee(&StackSizeInBytes);
  511. if (ret)
  512. thread_signal_inited = true;
  513. return ret ? 0 : -1;
  514. }
  515. void
  516. os_thread_signal_destroy()
  517. {
  518. /* Do nothing */
  519. }
  520. bool
  521. os_thread_signal_inited()
  522. {
  523. return thread_signal_inited;
  524. }
  525. #endif