thread_manager.c 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130
  1. /*
  2. * Copyright (C) 2019 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include "thread_manager.h"
  6. #if WASM_ENABLE_INTERP != 0
  7. #include "../interpreter/wasm_runtime.h"
  8. #endif
  9. #if WASM_ENABLE_AOT != 0
  10. #include "../aot/aot_runtime.h"
  11. #endif
  12. #if WASM_ENABLE_DEBUG_INTERP != 0
  13. #include "debug_engine.h"
  14. #endif
  15. typedef struct {
  16. bh_list_link l;
  17. void (*destroy_cb)(WASMCluster *);
  18. } DestroyCallBackNode;
  19. static bh_list destroy_callback_list_head;
  20. static bh_list *const destroy_callback_list = &destroy_callback_list_head;
  21. static bh_list cluster_list_head;
  22. static bh_list *const cluster_list = &cluster_list_head;
  23. static korp_mutex cluster_list_lock;
  24. typedef void (*list_visitor)(void *, void *);
  25. static uint32 cluster_max_thread_num = CLUSTER_MAX_THREAD_NUM;
  26. /* Set the maximum thread number, if this function is not called,
  27. the max thread num is defined by CLUSTER_MAX_THREAD_NUM */
  28. void
  29. wasm_cluster_set_max_thread_num(uint32 num)
  30. {
  31. if (num > 0)
  32. cluster_max_thread_num = num;
  33. }
  34. bool
  35. thread_manager_init()
  36. {
  37. if (bh_list_init(cluster_list) != 0)
  38. return false;
  39. if (os_mutex_init(&cluster_list_lock) != 0)
  40. return false;
  41. return true;
  42. }
  43. void
  44. thread_manager_destroy()
  45. {
  46. WASMCluster *cluster = bh_list_first_elem(cluster_list);
  47. WASMCluster *next;
  48. while (cluster) {
  49. next = bh_list_elem_next(cluster);
  50. wasm_cluster_destroy(cluster);
  51. cluster = next;
  52. }
  53. wasm_cluster_cancel_all_callbacks();
  54. os_mutex_destroy(&cluster_list_lock);
  55. }
  56. static void
  57. traverse_list(bh_list *l, list_visitor visitor, void *user_data)
  58. {
  59. void *next, *node = bh_list_first_elem(l);
  60. while (node) {
  61. next = bh_list_elem_next(node);
  62. visitor(node, user_data);
  63. node = next;
  64. }
  65. }
  66. /* The caller must lock cluster->lock */
  67. static bool
  68. allocate_aux_stack(WASMExecEnv *exec_env, uint32 *start, uint32 *size)
  69. {
  70. WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
  71. #if WASM_ENABLE_HEAP_AUX_STACK_ALLOCATION != 0
  72. WASMModuleInstanceCommon *module_inst =
  73. wasm_exec_env_get_module_inst(exec_env);
  74. uint32 stack_end;
  75. stack_end =
  76. wasm_runtime_module_malloc(module_inst, cluster->stack_size, NULL);
  77. *start = stack_end + cluster->stack_size;
  78. *size = cluster->stack_size;
  79. return stack_end != 0;
  80. #else
  81. uint32 i;
  82. /* If the module doesn't have aux stack info,
  83. it can't create any threads */
  84. if (!cluster->stack_segment_occupied)
  85. return false;
  86. for (i = 0; i < cluster_max_thread_num; i++) {
  87. if (!cluster->stack_segment_occupied[i]) {
  88. if (start)
  89. *start = cluster->stack_tops[i];
  90. if (size)
  91. *size = cluster->stack_size;
  92. cluster->stack_segment_occupied[i] = true;
  93. return true;
  94. }
  95. }
  96. return false;
  97. #endif
  98. }
  99. /* The caller must lock cluster->lock */
  100. static bool
  101. free_aux_stack(WASMExecEnv *exec_env, uint32 start)
  102. {
  103. WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
  104. #if WASM_ENABLE_HEAP_AUX_STACK_ALLOCATION != 0
  105. WASMModuleInstanceCommon *module_inst =
  106. wasm_exec_env_get_module_inst(exec_env);
  107. if (!wasm_exec_env_is_aux_stack_managed_by_runtime(exec_env)) {
  108. return true;
  109. }
  110. bh_assert(start >= cluster->stack_size);
  111. wasm_runtime_module_free(module_inst, start - cluster->stack_size);
  112. return true;
  113. #else
  114. uint32 i;
  115. for (i = 0; i < cluster_max_thread_num; i++) {
  116. if (start == cluster->stack_tops[i]) {
  117. cluster->stack_segment_occupied[i] = false;
  118. return true;
  119. }
  120. }
  121. return false;
  122. #endif
  123. }
  124. WASMCluster *
  125. wasm_cluster_create(WASMExecEnv *exec_env)
  126. {
  127. WASMCluster *cluster;
  128. uint32 aux_stack_start, aux_stack_size;
  129. bh_assert(exec_env->cluster == NULL);
  130. if (!(cluster = wasm_runtime_malloc(sizeof(WASMCluster)))) {
  131. LOG_ERROR("thread manager error: failed to allocate memory");
  132. return NULL;
  133. }
  134. memset(cluster, 0, sizeof(WASMCluster));
  135. exec_env->cluster = cluster;
  136. bh_list_init(&cluster->exec_env_list);
  137. bh_list_insert(&cluster->exec_env_list, exec_env);
  138. if (os_mutex_init(&cluster->lock) != 0) {
  139. wasm_runtime_free(cluster);
  140. LOG_ERROR("thread manager error: failed to init mutex");
  141. return NULL;
  142. }
  143. /* Prepare the aux stack top and size for every thread */
  144. if (!wasm_exec_env_get_aux_stack(exec_env, &aux_stack_start,
  145. &aux_stack_size)) {
  146. LOG_VERBOSE("No aux stack info for this module, can't create thread");
  147. /* If the module don't have aux stack info, don't throw error here,
  148. but remain stack_tops and stack_segment_occupied as NULL */
  149. os_mutex_lock(&cluster_list_lock);
  150. if (bh_list_insert(cluster_list, cluster) != 0) {
  151. os_mutex_unlock(&cluster_list_lock);
  152. goto fail;
  153. }
  154. os_mutex_unlock(&cluster_list_lock);
  155. return cluster;
  156. }
  157. #if WASM_ENABLE_HEAP_AUX_STACK_ALLOCATION != 0
  158. cluster->stack_size = aux_stack_size;
  159. #else
  160. cluster->stack_size = aux_stack_size / (cluster_max_thread_num + 1);
  161. if (cluster->stack_size < WASM_THREAD_AUX_STACK_SIZE_MIN) {
  162. goto fail;
  163. }
  164. /* Make stack size 16-byte aligned */
  165. cluster->stack_size = cluster->stack_size & (~15);
  166. #endif
  167. /* Set initial aux stack top to the instance and
  168. aux stack boundary to the main exec_env */
  169. if (!wasm_exec_env_set_aux_stack(exec_env, aux_stack_start,
  170. cluster->stack_size))
  171. goto fail;
  172. #if WASM_ENABLE_HEAP_AUX_STACK_ALLOCATION == 0
  173. if (cluster_max_thread_num != 0) {
  174. uint64 total_size = cluster_max_thread_num * sizeof(uint32);
  175. uint32 i;
  176. if (total_size >= UINT32_MAX
  177. || !(cluster->stack_tops =
  178. wasm_runtime_malloc((uint32)total_size))) {
  179. goto fail;
  180. }
  181. memset(cluster->stack_tops, 0, (uint32)total_size);
  182. if (!(cluster->stack_segment_occupied =
  183. wasm_runtime_malloc(cluster_max_thread_num * sizeof(bool)))) {
  184. goto fail;
  185. }
  186. memset(cluster->stack_segment_occupied, 0,
  187. cluster_max_thread_num * sizeof(bool));
  188. /* Reserve space for main instance */
  189. aux_stack_start -= cluster->stack_size;
  190. for (i = 0; i < cluster_max_thread_num; i++) {
  191. cluster->stack_tops[i] = aux_stack_start - cluster->stack_size * i;
  192. }
  193. }
  194. #endif
  195. os_mutex_lock(&cluster_list_lock);
  196. if (bh_list_insert(cluster_list, cluster) != 0) {
  197. os_mutex_unlock(&cluster_list_lock);
  198. goto fail;
  199. }
  200. os_mutex_unlock(&cluster_list_lock);
  201. return cluster;
  202. fail:
  203. if (cluster)
  204. wasm_cluster_destroy(cluster);
  205. return NULL;
  206. }
  207. static void
  208. destroy_cluster_visitor(void *node, void *user_data)
  209. {
  210. DestroyCallBackNode *destroy_node = (DestroyCallBackNode *)node;
  211. WASMCluster *cluster = (WASMCluster *)user_data;
  212. destroy_node->destroy_cb(cluster);
  213. }
  214. void
  215. wasm_cluster_destroy(WASMCluster *cluster)
  216. {
  217. traverse_list(destroy_callback_list, destroy_cluster_visitor,
  218. (void *)cluster);
  219. /* Remove the cluster from the cluster list */
  220. os_mutex_lock(&cluster_list_lock);
  221. bh_list_remove(cluster_list, cluster);
  222. os_mutex_unlock(&cluster_list_lock);
  223. os_mutex_destroy(&cluster->lock);
  224. #if WASM_ENABLE_HEAP_AUX_STACK_ALLOCATION == 0
  225. if (cluster->stack_tops)
  226. wasm_runtime_free(cluster->stack_tops);
  227. if (cluster->stack_segment_occupied)
  228. wasm_runtime_free(cluster->stack_segment_occupied);
  229. #endif
  230. #if WASM_ENABLE_DEBUG_INTERP != 0
  231. wasm_debug_instance_destroy(cluster);
  232. #endif
  233. wasm_runtime_free(cluster);
  234. }
  235. static void
  236. free_node_visitor(void *node, void *user_data)
  237. {
  238. wasm_runtime_free(node);
  239. }
  240. void
  241. wasm_cluster_cancel_all_callbacks()
  242. {
  243. traverse_list(destroy_callback_list, free_node_visitor, NULL);
  244. bh_list_init(destroy_callback_list);
  245. }
  246. WASMCluster *
  247. wasm_exec_env_get_cluster(WASMExecEnv *exec_env)
  248. {
  249. return exec_env->cluster;
  250. }
  251. /* The caller must lock cluster->lock */
  252. static bool
  253. wasm_cluster_add_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env)
  254. {
  255. bool ret = true;
  256. exec_env->cluster = cluster;
  257. if (cluster->exec_env_list.len == cluster_max_thread_num + 1) {
  258. LOG_ERROR("thread manager error: "
  259. "maximum number of threads exceeded");
  260. ret = false;
  261. }
  262. if (ret && bh_list_insert(&cluster->exec_env_list, exec_env) != 0)
  263. ret = false;
  264. return ret;
  265. }
  266. /* The caller should lock cluster->lock for thread safety */
  267. bool
  268. wasm_cluster_del_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env)
  269. {
  270. bool ret = true;
  271. bh_assert(exec_env->cluster == cluster);
  272. #if WASM_ENABLE_DEBUG_INTERP != 0
  273. /* Wait for debugger control thread to process the
  274. stop event of this thread */
  275. if (cluster->debug_inst) {
  276. /* lock the debug_inst->wait_lock so
  277. other threads can't fire stop events */
  278. os_mutex_lock(&cluster->debug_inst->wait_lock);
  279. while (cluster->debug_inst->stopped_thread == exec_env) {
  280. /* either wakes up by signal or by 1-second timeout */
  281. os_cond_reltimedwait(&cluster->debug_inst->wait_cond,
  282. &cluster->debug_inst->wait_lock, 1000000);
  283. }
  284. os_mutex_unlock(&cluster->debug_inst->wait_lock);
  285. }
  286. #endif
  287. if (bh_list_remove(&cluster->exec_env_list, exec_env) != 0)
  288. ret = false;
  289. if (cluster->exec_env_list.len == 0) {
  290. /* exec_env_list empty, destroy the cluster */
  291. wasm_cluster_destroy(cluster);
  292. }
  293. return ret;
  294. }
  295. static WASMExecEnv *
  296. wasm_cluster_search_exec_env(WASMCluster *cluster,
  297. WASMModuleInstanceCommon *module_inst)
  298. {
  299. WASMExecEnv *node = NULL;
  300. os_mutex_lock(&cluster->lock);
  301. node = bh_list_first_elem(&cluster->exec_env_list);
  302. while (node) {
  303. if (node->module_inst == module_inst) {
  304. os_mutex_unlock(&cluster->lock);
  305. return node;
  306. }
  307. node = bh_list_elem_next(node);
  308. }
  309. os_mutex_unlock(&cluster->lock);
  310. return NULL;
  311. }
  312. /* search the global cluster list to find if the given
  313. module instance have a corresponding exec_env */
  314. WASMExecEnv *
  315. wasm_clusters_search_exec_env(WASMModuleInstanceCommon *module_inst)
  316. {
  317. WASMCluster *cluster = NULL;
  318. WASMExecEnv *exec_env = NULL;
  319. os_mutex_lock(&cluster_list_lock);
  320. cluster = bh_list_first_elem(cluster_list);
  321. while (cluster) {
  322. exec_env = wasm_cluster_search_exec_env(cluster, module_inst);
  323. if (exec_env) {
  324. os_mutex_unlock(&cluster_list_lock);
  325. return exec_env;
  326. }
  327. cluster = bh_list_elem_next(cluster);
  328. }
  329. os_mutex_unlock(&cluster_list_lock);
  330. return NULL;
  331. }
  332. WASMExecEnv *
  333. wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env)
  334. {
  335. WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
  336. wasm_module_inst_t module_inst = get_module_inst(exec_env);
  337. wasm_module_t module;
  338. wasm_module_inst_t new_module_inst;
  339. #if WASM_ENABLE_LIBC_WASI != 0
  340. WASIContext *wasi_ctx;
  341. #endif
  342. WASMExecEnv *new_exec_env;
  343. uint32 aux_stack_start, aux_stack_size;
  344. uint32 stack_size = 8192;
  345. if (!module_inst || !(module = wasm_exec_env_get_module(exec_env))) {
  346. return NULL;
  347. }
  348. os_mutex_lock(&cluster->lock);
  349. if (cluster->has_exception || cluster->processing) {
  350. goto fail1;
  351. }
  352. #if WASM_ENABLE_INTERP != 0
  353. if (module_inst->module_type == Wasm_Module_Bytecode) {
  354. stack_size =
  355. ((WASMModuleInstance *)module_inst)->default_wasm_stack_size;
  356. }
  357. #endif
  358. #if WASM_ENABLE_AOT != 0
  359. if (module_inst->module_type == Wasm_Module_AoT) {
  360. stack_size =
  361. ((AOTModuleInstance *)module_inst)->default_wasm_stack_size;
  362. }
  363. #endif
  364. if (!(new_module_inst = wasm_runtime_instantiate_internal(
  365. module, true, stack_size, 0, NULL, 0))) {
  366. goto fail1;
  367. }
  368. /* Set custom_data to new module instance */
  369. wasm_runtime_set_custom_data_internal(
  370. new_module_inst, wasm_runtime_get_custom_data(module_inst));
  371. #if WASM_ENABLE_LIBC_WASI != 0
  372. wasi_ctx = wasm_runtime_get_wasi_ctx(module_inst);
  373. wasm_runtime_set_wasi_ctx(new_module_inst, wasi_ctx);
  374. #endif
  375. new_exec_env = wasm_exec_env_create_internal(new_module_inst,
  376. exec_env->wasm_stack_size);
  377. if (!new_exec_env)
  378. goto fail2;
  379. if (!allocate_aux_stack(exec_env, &aux_stack_start, &aux_stack_size)) {
  380. LOG_ERROR("thread manager error: "
  381. "failed to allocate aux stack space for new thread");
  382. goto fail3;
  383. }
  384. /* Set aux stack for current thread */
  385. if (!wasm_exec_env_set_aux_stack(new_exec_env, aux_stack_start,
  386. aux_stack_size)) {
  387. goto fail4;
  388. }
  389. if (!wasm_cluster_add_exec_env(cluster, new_exec_env))
  390. goto fail4;
  391. os_mutex_unlock(&cluster->lock);
  392. return new_exec_env;
  393. fail4:
  394. /* free the allocated aux stack space */
  395. free_aux_stack(exec_env, aux_stack_start);
  396. fail3:
  397. wasm_exec_env_destroy(new_exec_env);
  398. fail2:
  399. wasm_runtime_deinstantiate_internal(new_module_inst, true);
  400. fail1:
  401. os_mutex_unlock(&cluster->lock);
  402. return NULL;
  403. }
  404. void
  405. wasm_cluster_destroy_spawned_exec_env(WASMExecEnv *exec_env)
  406. {
  407. WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
  408. wasm_module_inst_t module_inst = wasm_runtime_get_module_inst(exec_env);
  409. bh_assert(cluster != NULL);
  410. /* Free aux stack space */
  411. os_mutex_lock(&cluster->lock);
  412. free_aux_stack(exec_env, exec_env->aux_stack_bottom.bottom);
  413. wasm_cluster_del_exec_env(cluster, exec_env);
  414. os_mutex_unlock(&cluster->lock);
  415. wasm_exec_env_destroy_internal(exec_env);
  416. wasm_runtime_deinstantiate_internal(module_inst, true);
  417. }
  418. /* start routine of thread manager */
  419. static void *
  420. thread_manager_start_routine(void *arg)
  421. {
  422. void *ret;
  423. WASMExecEnv *exec_env = (WASMExecEnv *)arg;
  424. WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
  425. WASMModuleInstanceCommon *module_inst =
  426. wasm_exec_env_get_module_inst(exec_env);
  427. bh_assert(cluster != NULL);
  428. bh_assert(module_inst != NULL);
  429. exec_env->handle = os_self_thread();
  430. ret = exec_env->thread_start_routine(exec_env);
  431. #ifdef OS_ENABLE_HW_BOUND_CHECK
  432. if (exec_env->suspend_flags.flags & 0x08)
  433. ret = exec_env->thread_ret_value;
  434. #endif
  435. /* Routine exit */
  436. /* Detach the native thread here to ensure the resources are freed */
  437. wasm_cluster_detach_thread(exec_env);
  438. #if WASM_ENABLE_DEBUG_INTERP != 0
  439. wasm_cluster_thread_exited(exec_env);
  440. #endif
  441. os_mutex_lock(&cluster->lock);
  442. /* Free aux stack space */
  443. free_aux_stack(exec_env, exec_env->aux_stack_bottom.bottom);
  444. /* routine exit, destroy instance */
  445. wasm_runtime_deinstantiate_internal(module_inst, true);
  446. /* Remove and exec_env */
  447. wasm_cluster_del_exec_env(cluster, exec_env);
  448. os_mutex_unlock(&cluster->lock);
  449. /* destroy exec_env */
  450. wasm_exec_env_destroy_internal(exec_env);
  451. os_thread_exit(ret);
  452. return ret;
  453. }
  454. int32
  455. wasm_cluster_create_thread(WASMExecEnv *exec_env,
  456. wasm_module_inst_t module_inst, bool alloc_aux_stack,
  457. void *(*thread_routine)(void *), void *arg)
  458. {
  459. WASMCluster *cluster;
  460. WASMExecEnv *new_exec_env;
  461. uint32 aux_stack_start = 0, aux_stack_size;
  462. korp_tid tid;
  463. cluster = wasm_exec_env_get_cluster(exec_env);
  464. bh_assert(cluster);
  465. os_mutex_lock(&cluster->lock);
  466. if (cluster->has_exception || cluster->processing) {
  467. goto fail1;
  468. }
  469. new_exec_env =
  470. wasm_exec_env_create_internal(module_inst, exec_env->wasm_stack_size);
  471. if (!new_exec_env)
  472. goto fail1;
  473. if (alloc_aux_stack) {
  474. if (!allocate_aux_stack(exec_env, &aux_stack_start, &aux_stack_size)) {
  475. LOG_ERROR("thread manager error: "
  476. "failed to allocate aux stack space for new thread");
  477. goto fail2;
  478. }
  479. /* Set aux stack for current thread */
  480. if (!wasm_exec_env_set_aux_stack(new_exec_env, aux_stack_start,
  481. aux_stack_size)) {
  482. goto fail3;
  483. }
  484. }
  485. else {
  486. /* Disable aux stack */
  487. new_exec_env->aux_stack_boundary.boundary = 0;
  488. new_exec_env->aux_stack_bottom.bottom = UINT32_MAX;
  489. }
  490. if (!wasm_cluster_add_exec_env(cluster, new_exec_env))
  491. goto fail3;
  492. new_exec_env->thread_start_routine = thread_routine;
  493. new_exec_env->thread_arg = arg;
  494. if (0
  495. != os_thread_create(&tid, thread_manager_start_routine,
  496. (void *)new_exec_env,
  497. APP_THREAD_STACK_SIZE_DEFAULT)) {
  498. goto fail4;
  499. }
  500. os_mutex_unlock(&cluster->lock);
  501. return 0;
  502. fail4:
  503. wasm_cluster_del_exec_env(cluster, new_exec_env);
  504. fail3:
  505. /* free the allocated aux stack space */
  506. if (alloc_aux_stack)
  507. free_aux_stack(exec_env, aux_stack_start);
  508. fail2:
  509. wasm_exec_env_destroy(new_exec_env);
  510. fail1:
  511. os_mutex_unlock(&cluster->lock);
  512. return -1;
  513. }
  514. #if WASM_ENABLE_DEBUG_INTERP != 0
  515. WASMCurrentEnvStatus *
  516. wasm_cluster_create_exenv_status()
  517. {
  518. WASMCurrentEnvStatus *status;
  519. if (!(status = wasm_runtime_malloc(sizeof(WASMCurrentEnvStatus)))) {
  520. return NULL;
  521. }
  522. status->step_count = 0;
  523. status->signal_flag = 0;
  524. status->running_status = 0;
  525. return status;
  526. }
  527. void
  528. wasm_cluster_destroy_exenv_status(WASMCurrentEnvStatus *status)
  529. {
  530. wasm_runtime_free(status);
  531. }
  532. inline static bool
  533. wasm_cluster_thread_is_running(WASMExecEnv *exec_env)
  534. {
  535. return exec_env->current_status->running_status == STATUS_RUNNING
  536. || exec_env->current_status->running_status == STATUS_STEP;
  537. }
  538. void
  539. wasm_cluster_clear_thread_signal(WASMExecEnv *exec_env)
  540. {
  541. exec_env->current_status->signal_flag = 0;
  542. }
  543. void
  544. wasm_cluster_thread_send_signal(WASMExecEnv *exec_env, uint32 signo)
  545. {
  546. exec_env->current_status->signal_flag = signo;
  547. }
  548. static void
  549. notify_debug_instance(WASMExecEnv *exec_env)
  550. {
  551. WASMCluster *cluster;
  552. cluster = wasm_exec_env_get_cluster(exec_env);
  553. bh_assert(cluster);
  554. if (!cluster->debug_inst) {
  555. return;
  556. }
  557. on_thread_stop_event(cluster->debug_inst, exec_env);
  558. }
  559. static void
  560. notify_debug_instance_exit(WASMExecEnv *exec_env)
  561. {
  562. WASMCluster *cluster;
  563. cluster = wasm_exec_env_get_cluster(exec_env);
  564. bh_assert(cluster);
  565. if (!cluster->debug_inst) {
  566. return;
  567. }
  568. on_thread_exit_event(cluster->debug_inst, exec_env);
  569. }
  570. void
  571. wasm_cluster_thread_waiting_run(WASMExecEnv *exec_env)
  572. {
  573. os_mutex_lock(&exec_env->wait_lock);
  574. /* Wake up debugger thread after we get the lock, otherwise we may miss the
  575. * signal from debugger thread, see
  576. * https://github.com/bytecodealliance/wasm-micro-runtime/issues/1860 */
  577. exec_env->current_status->running_status = STATUS_STOP;
  578. notify_debug_instance(exec_env);
  579. while (!wasm_cluster_thread_is_running(exec_env)) {
  580. os_cond_wait(&exec_env->wait_cond, &exec_env->wait_lock);
  581. }
  582. os_mutex_unlock(&exec_env->wait_lock);
  583. }
  584. void
  585. wasm_cluster_send_signal_all(WASMCluster *cluster, uint32 signo)
  586. {
  587. WASMExecEnv *exec_env = bh_list_first_elem(&cluster->exec_env_list);
  588. while (exec_env) {
  589. wasm_cluster_thread_send_signal(exec_env, signo);
  590. exec_env = bh_list_elem_next(exec_env);
  591. }
  592. }
  593. void
  594. wasm_cluster_thread_exited(WASMExecEnv *exec_env)
  595. {
  596. exec_env->current_status->running_status = STATUS_EXIT;
  597. notify_debug_instance_exit(exec_env);
  598. }
  599. void
  600. wasm_cluster_thread_continue(WASMExecEnv *exec_env)
  601. {
  602. os_mutex_lock(&exec_env->wait_lock);
  603. wasm_cluster_clear_thread_signal(exec_env);
  604. exec_env->current_status->running_status = STATUS_RUNNING;
  605. os_cond_signal(&exec_env->wait_cond);
  606. os_mutex_unlock(&exec_env->wait_lock);
  607. }
  608. void
  609. wasm_cluster_thread_step(WASMExecEnv *exec_env)
  610. {
  611. os_mutex_lock(&exec_env->wait_lock);
  612. exec_env->current_status->running_status = STATUS_STEP;
  613. os_cond_signal(&exec_env->wait_cond);
  614. os_mutex_unlock(&exec_env->wait_lock);
  615. }
  616. void
  617. wasm_cluster_set_debug_inst(WASMCluster *cluster, WASMDebugInstance *inst)
  618. {
  619. cluster->debug_inst = inst;
  620. }
  621. #endif /* end of WASM_ENABLE_DEBUG_INTERP */
  622. /* Check whether the exec_env is in one of all clusters, the caller
  623. should add lock to the cluster list before calling us */
  624. static bool
  625. clusters_have_exec_env(WASMExecEnv *exec_env)
  626. {
  627. WASMCluster *cluster = bh_list_first_elem(cluster_list);
  628. WASMExecEnv *node;
  629. while (cluster) {
  630. node = bh_list_first_elem(&cluster->exec_env_list);
  631. while (node) {
  632. if (node == exec_env) {
  633. bh_assert(exec_env->cluster == cluster);
  634. return true;
  635. }
  636. node = bh_list_elem_next(node);
  637. }
  638. cluster = bh_list_elem_next(cluster);
  639. }
  640. return false;
  641. }
  642. int32
  643. wasm_cluster_join_thread(WASMExecEnv *exec_env, void **ret_val)
  644. {
  645. korp_tid handle;
  646. os_mutex_lock(&cluster_list_lock);
  647. if (!clusters_have_exec_env(exec_env) || exec_env->thread_is_detached) {
  648. /* Invalid thread, thread has exited or thread has been detached */
  649. if (ret_val)
  650. *ret_val = NULL;
  651. os_mutex_unlock(&cluster_list_lock);
  652. return 0;
  653. }
  654. exec_env->wait_count++;
  655. handle = exec_env->handle;
  656. os_mutex_unlock(&cluster_list_lock);
  657. return os_thread_join(handle, ret_val);
  658. }
  659. int32
  660. wasm_cluster_detach_thread(WASMExecEnv *exec_env)
  661. {
  662. int32 ret = 0;
  663. os_mutex_lock(&cluster_list_lock);
  664. if (!clusters_have_exec_env(exec_env)) {
  665. /* Invalid thread or the thread has exited */
  666. os_mutex_unlock(&cluster_list_lock);
  667. return 0;
  668. }
  669. if (exec_env->wait_count == 0 && !exec_env->thread_is_detached) {
  670. /* Only detach current thread when there is no other thread
  671. joining it, otherwise let the system resources for the
  672. thread be released after joining */
  673. ret = os_thread_detach(exec_env->handle);
  674. exec_env->thread_is_detached = true;
  675. }
  676. os_mutex_unlock(&cluster_list_lock);
  677. return ret;
  678. }
  679. void
  680. wasm_cluster_exit_thread(WASMExecEnv *exec_env, void *retval)
  681. {
  682. WASMCluster *cluster;
  683. #ifdef OS_ENABLE_HW_BOUND_CHECK
  684. if (exec_env->jmpbuf_stack_top) {
  685. /* Store the return value in exec_env */
  686. exec_env->thread_ret_value = retval;
  687. exec_env->suspend_flags.flags |= 0x08;
  688. #ifndef BH_PLATFORM_WINDOWS
  689. /* Pop all jmpbuf_node except the last one */
  690. while (exec_env->jmpbuf_stack_top->prev) {
  691. wasm_exec_env_pop_jmpbuf(exec_env);
  692. }
  693. os_longjmp(exec_env->jmpbuf_stack_top->jmpbuf, 1);
  694. return;
  695. #endif
  696. }
  697. #endif
  698. cluster = wasm_exec_env_get_cluster(exec_env);
  699. bh_assert(cluster);
  700. #if WASM_ENABLE_DEBUG_INTERP != 0
  701. wasm_cluster_clear_thread_signal(exec_env);
  702. wasm_cluster_thread_exited(exec_env);
  703. #endif
  704. /* App exit the thread, free the resources before exit native thread */
  705. /* Detach the native thread here to ensure the resources are freed */
  706. wasm_cluster_detach_thread(exec_env);
  707. os_mutex_lock(&cluster->lock);
  708. /* Free aux stack space */
  709. free_aux_stack(exec_env, exec_env->aux_stack_bottom.bottom);
  710. /* Remove and destroy exec_env */
  711. wasm_cluster_del_exec_env(cluster, exec_env);
  712. os_mutex_unlock(&cluster->lock);
  713. wasm_exec_env_destroy_internal(exec_env);
  714. os_thread_exit(retval);
  715. }
  716. static void
  717. set_thread_cancel_flags(WASMExecEnv *exec_env)
  718. {
  719. /* Set the termination flag */
  720. #if WASM_ENABLE_DEBUG_INTERP != 0
  721. wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TERM);
  722. #else
  723. exec_env->suspend_flags.flags |= 0x01;
  724. #endif
  725. }
  726. int32
  727. wasm_cluster_cancel_thread(WASMExecEnv *exec_env)
  728. {
  729. os_mutex_lock(&cluster_list_lock);
  730. if (!clusters_have_exec_env(exec_env)) {
  731. /* Invalid thread or the thread has exited */
  732. os_mutex_unlock(&cluster_list_lock);
  733. return 0;
  734. }
  735. os_mutex_unlock(&cluster_list_lock);
  736. set_thread_cancel_flags(exec_env);
  737. return 0;
  738. }
  739. static void
  740. terminate_thread_visitor(void *node, void *user_data)
  741. {
  742. WASMExecEnv *curr_exec_env = (WASMExecEnv *)node;
  743. WASMExecEnv *exec_env = (WASMExecEnv *)user_data;
  744. if (curr_exec_env == exec_env)
  745. return;
  746. wasm_cluster_cancel_thread(curr_exec_env);
  747. wasm_cluster_join_thread(curr_exec_env, NULL);
  748. }
  749. void
  750. wasm_cluster_terminate_all(WASMCluster *cluster)
  751. {
  752. os_mutex_lock(&cluster->lock);
  753. cluster->processing = true;
  754. os_mutex_unlock(&cluster->lock);
  755. traverse_list(&cluster->exec_env_list, terminate_thread_visitor, NULL);
  756. os_mutex_lock(&cluster->lock);
  757. cluster->processing = false;
  758. os_mutex_unlock(&cluster->lock);
  759. }
  760. void
  761. wasm_cluster_terminate_all_except_self(WASMCluster *cluster,
  762. WASMExecEnv *exec_env)
  763. {
  764. os_mutex_lock(&cluster->lock);
  765. cluster->processing = true;
  766. os_mutex_unlock(&cluster->lock);
  767. traverse_list(&cluster->exec_env_list, terminate_thread_visitor,
  768. (void *)exec_env);
  769. os_mutex_lock(&cluster->lock);
  770. cluster->processing = false;
  771. os_mutex_unlock(&cluster->lock);
  772. }
  773. static void
  774. wait_for_thread_visitor(void *node, void *user_data)
  775. {
  776. WASMExecEnv *curr_exec_env = (WASMExecEnv *)node;
  777. WASMExecEnv *exec_env = (WASMExecEnv *)user_data;
  778. if (curr_exec_env == exec_env)
  779. return;
  780. wasm_cluster_join_thread(curr_exec_env, NULL);
  781. }
  782. void
  783. wams_cluster_wait_for_all(WASMCluster *cluster)
  784. {
  785. os_mutex_lock(&cluster->lock);
  786. cluster->processing = true;
  787. os_mutex_unlock(&cluster->lock);
  788. traverse_list(&cluster->exec_env_list, wait_for_thread_visitor, NULL);
  789. os_mutex_lock(&cluster->lock);
  790. cluster->processing = false;
  791. os_mutex_unlock(&cluster->lock);
  792. }
  793. void
  794. wasm_cluster_wait_for_all_except_self(WASMCluster *cluster,
  795. WASMExecEnv *exec_env)
  796. {
  797. os_mutex_lock(&cluster->lock);
  798. cluster->processing = true;
  799. os_mutex_unlock(&cluster->lock);
  800. traverse_list(&cluster->exec_env_list, wait_for_thread_visitor,
  801. (void *)exec_env);
  802. os_mutex_lock(&cluster->lock);
  803. cluster->processing = false;
  804. os_mutex_unlock(&cluster->lock);
  805. }
  806. bool
  807. wasm_cluster_register_destroy_callback(void (*callback)(WASMCluster *))
  808. {
  809. DestroyCallBackNode *node;
  810. if (!(node = wasm_runtime_malloc(sizeof(DestroyCallBackNode)))) {
  811. LOG_ERROR("thread manager error: failed to allocate memory");
  812. return false;
  813. }
  814. node->destroy_cb = callback;
  815. bh_list_insert(destroy_callback_list, node);
  816. return true;
  817. }
  818. void
  819. wasm_cluster_suspend_thread(WASMExecEnv *exec_env)
  820. {
  821. /* Set the suspend flag */
  822. exec_env->suspend_flags.flags |= 0x02;
  823. }
  824. static void
  825. suspend_thread_visitor(void *node, void *user_data)
  826. {
  827. WASMExecEnv *curr_exec_env = (WASMExecEnv *)node;
  828. WASMExecEnv *exec_env = (WASMExecEnv *)user_data;
  829. if (curr_exec_env == exec_env)
  830. return;
  831. wasm_cluster_suspend_thread(curr_exec_env);
  832. }
  833. void
  834. wasm_cluster_suspend_all(WASMCluster *cluster)
  835. {
  836. os_mutex_lock(&cluster->lock);
  837. traverse_list(&cluster->exec_env_list, suspend_thread_visitor, NULL);
  838. os_mutex_unlock(&cluster->lock);
  839. }
  840. void
  841. wasm_cluster_suspend_all_except_self(WASMCluster *cluster,
  842. WASMExecEnv *exec_env)
  843. {
  844. os_mutex_lock(&cluster->lock);
  845. traverse_list(&cluster->exec_env_list, suspend_thread_visitor,
  846. (void *)exec_env);
  847. os_mutex_unlock(&cluster->lock);
  848. }
  849. void
  850. wasm_cluster_resume_thread(WASMExecEnv *exec_env)
  851. {
  852. exec_env->suspend_flags.flags &= ~0x02;
  853. os_cond_signal(&exec_env->wait_cond);
  854. }
  855. static void
  856. resume_thread_visitor(void *node, void *user_data)
  857. {
  858. WASMExecEnv *curr_exec_env = (WASMExecEnv *)node;
  859. wasm_cluster_resume_thread(curr_exec_env);
  860. }
  861. void
  862. wasm_cluster_resume_all(WASMCluster *cluster)
  863. {
  864. os_mutex_lock(&cluster->lock);
  865. traverse_list(&cluster->exec_env_list, resume_thread_visitor, NULL);
  866. os_mutex_unlock(&cluster->lock);
  867. }
  868. static void
  869. set_exception_visitor(void *node, void *user_data)
  870. {
  871. WASMExecEnv *curr_exec_env = (WASMExecEnv *)node;
  872. WASMExecEnv *exec_env = (WASMExecEnv *)user_data;
  873. WASMModuleInstanceCommon *module_inst = get_module_inst(exec_env);
  874. WASMModuleInstance *wasm_inst = (WASMModuleInstance *)module_inst;
  875. if (curr_exec_env != exec_env) {
  876. WASMModuleInstance *curr_wasm_inst =
  877. (WASMModuleInstance *)get_module_inst(curr_exec_env);
  878. bh_memcpy_s(curr_wasm_inst->cur_exception,
  879. sizeof(curr_wasm_inst->cur_exception),
  880. wasm_inst->cur_exception, sizeof(wasm_inst->cur_exception));
  881. /* Terminate the thread so it can exit from dead loops */
  882. set_thread_cancel_flags(curr_exec_env);
  883. }
  884. }
  885. static void
  886. clear_exception_visitor(void *node, void *user_data)
  887. {
  888. WASMExecEnv *exec_env = (WASMExecEnv *)user_data;
  889. WASMExecEnv *curr_exec_env = (WASMExecEnv *)node;
  890. if (curr_exec_env != exec_env) {
  891. WASMModuleInstance *curr_wasm_inst =
  892. (WASMModuleInstance *)get_module_inst(curr_exec_env);
  893. curr_wasm_inst->cur_exception[0] = '\0';
  894. }
  895. }
  896. void
  897. wasm_cluster_spread_exception(WASMExecEnv *exec_env, bool clear)
  898. {
  899. WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
  900. bh_assert(cluster);
  901. os_mutex_lock(&cluster->lock);
  902. cluster->has_exception = !clear;
  903. traverse_list(&cluster->exec_env_list,
  904. clear ? clear_exception_visitor : set_exception_visitor,
  905. exec_env);
  906. os_mutex_unlock(&cluster->lock);
  907. }
  908. static void
  909. set_custom_data_visitor(void *node, void *user_data)
  910. {
  911. WASMExecEnv *curr_exec_env = (WASMExecEnv *)node;
  912. WASMModuleInstanceCommon *module_inst = get_module_inst(curr_exec_env);
  913. wasm_runtime_set_custom_data_internal(module_inst, user_data);
  914. }
  915. void
  916. wasm_cluster_spread_custom_data(WASMModuleInstanceCommon *module_inst,
  917. void *custom_data)
  918. {
  919. WASMExecEnv *exec_env = wasm_clusters_search_exec_env(module_inst);
  920. if (exec_env == NULL) {
  921. /* Maybe threads have not been started yet. */
  922. wasm_runtime_set_custom_data_internal(module_inst, custom_data);
  923. }
  924. else {
  925. WASMCluster *cluster;
  926. cluster = wasm_exec_env_get_cluster(exec_env);
  927. bh_assert(cluster);
  928. os_mutex_lock(&cluster->lock);
  929. traverse_list(&cluster->exec_env_list, set_custom_data_visitor,
  930. custom_data);
  931. os_mutex_unlock(&cluster->lock);
  932. }
  933. }