lib_pthread_wrapper.c 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081
  1. /*
  2. * Copyright (C) 2019 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include "bh_common.h"
  6. #include "bh_log.h"
  7. #include "wasm_export.h"
  8. #include "../interpreter/wasm.h"
  9. #include "../common/wasm_runtime_common.h"
  10. #include "thread_manager.h"
  11. #define WAMR_PTHREAD_KEYS_MAX 32
  12. /* clang-format off */
  13. #define get_module(exec_env) \
  14. wasm_exec_env_get_module(exec_env)
  15. #define get_module_inst(exec_env) \
  16. wasm_runtime_get_module_inst(exec_env)
  17. #define get_thread_arg(exec_env) \
  18. wasm_exec_env_get_thread_arg(exec_env)
  19. #define get_wasi_ctx(module_inst) \
  20. wasm_runtime_get_wasi_ctx(module_inst)
  21. #define validate_app_addr(offset, size) \
  22. wasm_runtime_validate_app_addr(module_inst, offset, size)
  23. #define validate_native_addr(addr, size) \
  24. wasm_runtime_validate_native_addr(module_inst, addr, size)
  25. #define addr_app_to_native(offset) \
  26. wasm_runtime_addr_app_to_native(module_inst, offset)
  27. #define addr_native_to_app(ptr) \
  28. wasm_runtime_addr_native_to_app(module_inst, ptr)
  29. /* clang-format on */
  30. extern bool
  31. wasm_runtime_call_indirect(wasm_exec_env_t exec_env, uint32 element_indices,
  32. uint32 argc, uint32 argv[]);
  33. enum {
  34. T_THREAD,
  35. T_MUTEX,
  36. T_COND,
  37. };
  38. enum thread_status_t {
  39. THREAD_INIT,
  40. THREAD_RUNNING,
  41. THREAD_CANCELLED,
  42. THREAD_EXIT,
  43. };
  44. enum mutex_status_t {
  45. MUTEX_CREATED,
  46. MUTEX_DESTROYED,
  47. };
  48. enum cond_status_t {
  49. COND_CREATED,
  50. COND_DESTROYED,
  51. };
  52. typedef struct ThreadKeyValueNode {
  53. bh_list_link l;
  54. wasm_exec_env_t exec_env;
  55. int32 thread_key_values[WAMR_PTHREAD_KEYS_MAX];
  56. } ThreadKeyValueNode;
  57. typedef struct KeyData {
  58. int32 destructor_func;
  59. bool is_created;
  60. } KeyData;
  61. typedef struct ClusterInfoNode {
  62. bh_list_link l;
  63. WASMCluster *cluster;
  64. HashMap *thread_info_map;
  65. /* Key data list */
  66. KeyData key_data_list[WAMR_PTHREAD_KEYS_MAX];
  67. korp_mutex key_data_list_lock;
  68. /* Every node contains the key value list for a thread */
  69. bh_list thread_list_head;
  70. bh_list *thread_list;
  71. } ClusterInfoNode;
  72. typedef struct ThreadInfoNode {
  73. wasm_exec_env_t parent_exec_env;
  74. wasm_exec_env_t exec_env;
  75. /* the id returned to app */
  76. uint32 handle;
  77. /* type can be [THREAD | MUTEX | CONDITION] */
  78. uint32 type;
  79. /* Thread status, this variable should be volatile
  80. as its value may be changed in different threads */
  81. volatile uint32 status;
  82. bool joinable;
  83. union {
  84. korp_tid thread;
  85. korp_mutex *mutex;
  86. korp_cond *cond;
  87. /* A copy of the thread return value */
  88. void *ret;
  89. } u;
  90. } ThreadInfoNode;
  91. typedef struct {
  92. ThreadInfoNode *info_node;
  93. /* table elem index of the app's entry function */
  94. uint32 elem_index;
  95. /* arg of the app's entry function */
  96. uint32 arg;
  97. wasm_module_inst_t module_inst;
  98. } ThreadRoutineArgs;
  99. static bh_list cluster_info_list;
  100. static korp_mutex thread_global_lock;
  101. static uint32 handle_id = 1;
  102. static void
  103. lib_pthread_destroy_callback(WASMCluster *cluster);
  104. static uint32
  105. thread_handle_hash(void *handle)
  106. {
  107. return (uint32)(uintptr_t)handle;
  108. }
  109. static bool
  110. thread_handle_equal(void *h1, void *h2)
  111. {
  112. return (uint32)(uintptr_t)h1 == (uint32)(uintptr_t)h2 ? true : false;
  113. }
  114. static void
  115. thread_info_destroy(void *node)
  116. {
  117. ThreadInfoNode *info_node = (ThreadInfoNode *)node;
  118. os_mutex_lock(&thread_global_lock);
  119. if (info_node->type == T_MUTEX) {
  120. if (info_node->status != MUTEX_DESTROYED)
  121. os_mutex_destroy(info_node->u.mutex);
  122. wasm_runtime_free(info_node->u.mutex);
  123. }
  124. else if (info_node->type == T_COND) {
  125. if (info_node->status != COND_DESTROYED)
  126. os_cond_destroy(info_node->u.cond);
  127. wasm_runtime_free(info_node->u.cond);
  128. }
  129. wasm_runtime_free(info_node);
  130. os_mutex_unlock(&thread_global_lock);
  131. }
  132. bool
  133. lib_pthread_init()
  134. {
  135. if (0 != os_mutex_init(&thread_global_lock))
  136. return false;
  137. bh_list_init(&cluster_info_list);
  138. if (!wasm_cluster_register_destroy_callback(lib_pthread_destroy_callback)) {
  139. os_mutex_destroy(&thread_global_lock);
  140. return false;
  141. }
  142. return true;
  143. }
  144. void
  145. lib_pthread_destroy()
  146. {
  147. os_mutex_destroy(&thread_global_lock);
  148. }
  149. static ClusterInfoNode *
  150. get_cluster_info(WASMCluster *cluster)
  151. {
  152. ClusterInfoNode *node;
  153. os_mutex_lock(&thread_global_lock);
  154. node = bh_list_first_elem(&cluster_info_list);
  155. while (node) {
  156. if (cluster == node->cluster) {
  157. os_mutex_unlock(&thread_global_lock);
  158. return node;
  159. }
  160. node = bh_list_elem_next(node);
  161. }
  162. os_mutex_unlock(&thread_global_lock);
  163. return NULL;
  164. }
  165. static KeyData *
  166. key_data_list_lookup(wasm_exec_env_t exec_env, int32 key)
  167. {
  168. ClusterInfoNode *node;
  169. WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
  170. if ((node = get_cluster_info(cluster))) {
  171. return (key >= 0 && key < WAMR_PTHREAD_KEYS_MAX
  172. && node->key_data_list[key].is_created)
  173. ? &(node->key_data_list[key])
  174. : NULL;
  175. }
  176. return NULL;
  177. }
  178. /**
  179. * Lookup the thread key value node for a thread, create a new one if failed
  180. * This design will reduce the memory usage. If the thread doesn't use the
  181. * local storage, it will not occupy memory space.
  182. */
  183. static int32 *
  184. key_value_list_lookup_or_create(wasm_exec_env_t exec_env, ClusterInfoNode *info,
  185. int32 key)
  186. {
  187. KeyData *key_node;
  188. ThreadKeyValueNode *data;
  189. /* Check if the key is valid */
  190. key_node = key_data_list_lookup(exec_env, key);
  191. if (!key_node) {
  192. return NULL;
  193. }
  194. /* Find key values node */
  195. data = bh_list_first_elem(info->thread_list);
  196. while (data) {
  197. if (data->exec_env == exec_env)
  198. return data->thread_key_values;
  199. data = bh_list_elem_next(data);
  200. }
  201. /* If not found, create a new node for this thread */
  202. if (!(data = wasm_runtime_malloc(sizeof(ThreadKeyValueNode))))
  203. return NULL;
  204. memset(data, 0, sizeof(ThreadKeyValueNode));
  205. data->exec_env = exec_env;
  206. if (bh_list_insert(info->thread_list, data) != 0) {
  207. wasm_runtime_free(data);
  208. return NULL;
  209. }
  210. return data->thread_key_values;
  211. }
  212. static void
  213. call_key_destructor(wasm_exec_env_t exec_env)
  214. {
  215. int32 i;
  216. uint32 destructor_index;
  217. KeyData *key_node;
  218. ThreadKeyValueNode *value_node;
  219. WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
  220. ClusterInfoNode *info = get_cluster_info(cluster);
  221. if (!info) {
  222. return;
  223. }
  224. value_node = bh_list_first_elem(info->thread_list);
  225. while (value_node) {
  226. if (value_node->exec_env == exec_env)
  227. break;
  228. value_node = bh_list_elem_next(value_node);
  229. }
  230. /* This thread hasn't created key value node */
  231. if (!value_node)
  232. return;
  233. /* Destroy key values */
  234. for (i = 0; i < WAMR_PTHREAD_KEYS_MAX; i++) {
  235. if (value_node->thread_key_values[i] != 0) {
  236. int32 value = value_node->thread_key_values[i];
  237. os_mutex_lock(&info->key_data_list_lock);
  238. if ((key_node = key_data_list_lookup(exec_env, i)))
  239. destructor_index = key_node->destructor_func;
  240. else
  241. destructor_index = 0;
  242. os_mutex_unlock(&info->key_data_list_lock);
  243. /* reset key value */
  244. value_node->thread_key_values[i] = 0;
  245. /* Call the destructor func provided by app */
  246. if (destructor_index) {
  247. uint32 argv[1];
  248. argv[0] = value;
  249. wasm_runtime_call_indirect(exec_env, destructor_index, 1, argv);
  250. }
  251. }
  252. }
  253. bh_list_remove(info->thread_list, value_node);
  254. wasm_runtime_free(value_node);
  255. }
  256. static void
  257. destroy_thread_key_value_list(bh_list *list)
  258. {
  259. ThreadKeyValueNode *node, *next;
  260. /* There should be only one node for main thread */
  261. bh_assert(list->len <= 1);
  262. if (list->len) {
  263. node = bh_list_first_elem(list);
  264. while (node) {
  265. next = bh_list_elem_next(node);
  266. call_key_destructor(node->exec_env);
  267. node = next;
  268. }
  269. }
  270. }
  271. static ClusterInfoNode *
  272. create_cluster_info(WASMCluster *cluster)
  273. {
  274. ClusterInfoNode *node;
  275. bh_list_status ret;
  276. if (!(node = wasm_runtime_malloc(sizeof(ClusterInfoNode)))) {
  277. return NULL;
  278. }
  279. memset(node, 0, sizeof(WASMCluster));
  280. node->thread_list = &node->thread_list_head;
  281. ret = bh_list_init(node->thread_list);
  282. bh_assert(ret == BH_LIST_SUCCESS);
  283. if (os_mutex_init(&node->key_data_list_lock) != 0) {
  284. wasm_runtime_free(node);
  285. return NULL;
  286. }
  287. node->cluster = cluster;
  288. if (!(node->thread_info_map = bh_hash_map_create(
  289. 32, true, (HashFunc)thread_handle_hash,
  290. (KeyEqualFunc)thread_handle_equal, NULL, thread_info_destroy))) {
  291. os_mutex_destroy(&node->key_data_list_lock);
  292. wasm_runtime_free(node);
  293. return NULL;
  294. }
  295. os_mutex_lock(&thread_global_lock);
  296. ret = bh_list_insert(&cluster_info_list, node);
  297. bh_assert(ret == BH_LIST_SUCCESS);
  298. os_mutex_unlock(&thread_global_lock);
  299. (void)ret;
  300. return node;
  301. }
  302. static bool
  303. destroy_cluster_info(WASMCluster *cluster)
  304. {
  305. ClusterInfoNode *node = get_cluster_info(cluster);
  306. if (node) {
  307. bh_hash_map_destroy(node->thread_info_map);
  308. destroy_thread_key_value_list(node->thread_list);
  309. os_mutex_destroy(&node->key_data_list_lock);
  310. /* Remove from the cluster info list */
  311. os_mutex_lock(&thread_global_lock);
  312. bh_list_remove(&cluster_info_list, node);
  313. wasm_runtime_free(node);
  314. os_mutex_unlock(&thread_global_lock);
  315. return true;
  316. }
  317. return false;
  318. }
  319. static void
  320. lib_pthread_destroy_callback(WASMCluster *cluster)
  321. {
  322. destroy_cluster_info(cluster);
  323. }
  324. static void
  325. delete_thread_info_node(ThreadInfoNode *thread_info)
  326. {
  327. ClusterInfoNode *node;
  328. bool ret;
  329. WASMCluster *cluster = wasm_exec_env_get_cluster(thread_info->exec_env);
  330. if ((node = get_cluster_info(cluster))) {
  331. ret = bh_hash_map_remove(node->thread_info_map,
  332. (void *)(uintptr_t)thread_info->handle, NULL,
  333. NULL);
  334. (void)ret;
  335. }
  336. thread_info_destroy(thread_info);
  337. }
  338. static bool
  339. append_thread_info_node(ThreadInfoNode *thread_info)
  340. {
  341. ClusterInfoNode *node;
  342. WASMCluster *cluster = wasm_exec_env_get_cluster(thread_info->exec_env);
  343. if (!(node = get_cluster_info(cluster))) {
  344. if (!(node = create_cluster_info(cluster))) {
  345. return false;
  346. }
  347. }
  348. if (!bh_hash_map_insert(node->thread_info_map,
  349. (void *)(uintptr_t)thread_info->handle,
  350. thread_info)) {
  351. return false;
  352. }
  353. return true;
  354. }
  355. static ThreadInfoNode *
  356. get_thread_info(wasm_exec_env_t exec_env, uint32 handle)
  357. {
  358. WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
  359. ClusterInfoNode *info = get_cluster_info(cluster);
  360. if (!info) {
  361. return NULL;
  362. }
  363. return bh_hash_map_find(info->thread_info_map, (void *)(uintptr_t)handle);
  364. }
  365. static uint32
  366. allocate_handle()
  367. {
  368. uint32 id;
  369. os_mutex_lock(&thread_global_lock);
  370. id = handle_id++;
  371. os_mutex_unlock(&thread_global_lock);
  372. return id;
  373. }
  374. static void *
  375. pthread_start_routine(void *arg)
  376. {
  377. wasm_exec_env_t exec_env = (wasm_exec_env_t)arg;
  378. wasm_exec_env_t parent_exec_env;
  379. wasm_module_inst_t module_inst = get_module_inst(exec_env);
  380. ThreadRoutineArgs *routine_args = exec_env->thread_arg;
  381. ThreadInfoNode *info_node = routine_args->info_node;
  382. uint32 argv[1];
  383. parent_exec_env = info_node->parent_exec_env;
  384. os_mutex_lock(&parent_exec_env->wait_lock);
  385. info_node->exec_env = exec_env;
  386. info_node->u.thread = exec_env->handle;
  387. if (!append_thread_info_node(info_node)) {
  388. wasm_runtime_deinstantiate_internal(module_inst, true);
  389. delete_thread_info_node(info_node);
  390. os_cond_signal(&parent_exec_env->wait_cond);
  391. os_mutex_unlock(&parent_exec_env->wait_lock);
  392. return NULL;
  393. }
  394. info_node->status = THREAD_RUNNING;
  395. os_cond_signal(&parent_exec_env->wait_cond);
  396. os_mutex_unlock(&parent_exec_env->wait_lock);
  397. wasm_exec_env_set_thread_info(exec_env);
  398. argv[0] = routine_args->arg;
  399. if (!wasm_runtime_call_indirect(exec_env, routine_args->elem_index, 1,
  400. argv)) {
  401. if (wasm_runtime_get_exception(module_inst))
  402. wasm_cluster_spread_exception(exec_env);
  403. }
  404. /* destroy pthread key values */
  405. call_key_destructor(exec_env);
  406. /* routine exit, destroy instance */
  407. wasm_runtime_deinstantiate_internal(module_inst, true);
  408. wasm_runtime_free(routine_args);
  409. /* if the thread is joinable, store the result in its info node,
  410. if the other threads join this thread after exited, then we
  411. can return the stored result */
  412. if (!info_node->joinable) {
  413. delete_thread_info_node(info_node);
  414. }
  415. else {
  416. info_node->u.ret = (void *)(uintptr_t)argv[0];
  417. #ifdef OS_ENABLE_HW_BOUND_CHECK
  418. if (exec_env->suspend_flags.flags & 0x08)
  419. /* argv[0] isn't set after longjmp(1) to
  420. invoke_native_with_hw_bound_check */
  421. info_node->u.ret = exec_env->thread_ret_value;
  422. #endif
  423. /* Update node status after ret value was set */
  424. info_node->status = THREAD_EXIT;
  425. }
  426. return (void *)(uintptr_t)argv[0];
  427. }
  428. static int
  429. pthread_create_wrapper(wasm_exec_env_t exec_env,
  430. uint32 *thread, /* thread_handle */
  431. const void *attr, /* not supported */
  432. uint32 elem_index, /* entry function */
  433. uint32 arg) /* arguments buffer */
  434. {
  435. wasm_module_t module = get_module(exec_env);
  436. wasm_module_inst_t module_inst = get_module_inst(exec_env);
  437. wasm_module_inst_t new_module_inst = NULL;
  438. ThreadInfoNode *info_node = NULL;
  439. ThreadRoutineArgs *routine_args = NULL;
  440. uint32 thread_handle;
  441. int32 ret = -1;
  442. #if WASM_ENABLE_LIBC_WASI != 0
  443. WASIContext *wasi_ctx;
  444. #endif
  445. bh_assert(module);
  446. bh_assert(module_inst);
  447. if (!(new_module_inst = wasm_runtime_instantiate_internal(
  448. module, true, 8192, 0, NULL, 0)))
  449. return -1;
  450. /* Set custom_data to new module instance */
  451. wasm_runtime_set_custom_data_internal(
  452. new_module_inst, wasm_runtime_get_custom_data(module_inst));
  453. #if WASM_ENABLE_LIBC_WASI != 0
  454. wasi_ctx = get_wasi_ctx(module_inst);
  455. if (wasi_ctx)
  456. wasm_runtime_set_wasi_ctx(new_module_inst, wasi_ctx);
  457. #endif
  458. if (!(info_node = wasm_runtime_malloc(sizeof(ThreadInfoNode))))
  459. goto fail;
  460. memset(info_node, 0, sizeof(ThreadInfoNode));
  461. thread_handle = allocate_handle();
  462. info_node->parent_exec_env = exec_env;
  463. info_node->handle = thread_handle;
  464. info_node->type = T_THREAD;
  465. info_node->status = THREAD_INIT;
  466. info_node->joinable = true;
  467. if (!(routine_args = wasm_runtime_malloc(sizeof(ThreadRoutineArgs))))
  468. goto fail;
  469. routine_args->arg = arg;
  470. routine_args->elem_index = elem_index;
  471. routine_args->info_node = info_node;
  472. routine_args->module_inst = new_module_inst;
  473. os_mutex_lock(&exec_env->wait_lock);
  474. ret = wasm_cluster_create_thread(
  475. exec_env, new_module_inst, pthread_start_routine, (void *)routine_args);
  476. if (ret != 0) {
  477. os_mutex_unlock(&exec_env->wait_lock);
  478. goto fail;
  479. }
  480. /* Wait for the thread routine to assign the exec_env to
  481. thread_info_node, otherwise the exec_env in the thread
  482. info node may be NULL in the next pthread API call */
  483. os_cond_wait(&exec_env->wait_cond, &exec_env->wait_lock);
  484. os_mutex_unlock(&exec_env->wait_lock);
  485. if (thread)
  486. *thread = thread_handle;
  487. return 0;
  488. fail:
  489. if (new_module_inst)
  490. wasm_runtime_deinstantiate_internal(new_module_inst, true);
  491. if (info_node)
  492. wasm_runtime_free(info_node);
  493. if (routine_args)
  494. wasm_runtime_free(routine_args);
  495. return ret;
  496. }
  497. static int32
  498. pthread_join_wrapper(wasm_exec_env_t exec_env, uint32 thread,
  499. int32 retval_offset) /* void **retval */
  500. {
  501. uint32 *ret;
  502. int32 join_ret;
  503. void **retval;
  504. ThreadInfoNode *node;
  505. wasm_module_inst_t module_inst;
  506. wasm_exec_env_t target_exec_env;
  507. module_inst = get_module_inst(exec_env);
  508. /* validate addr, we can use current thread's
  509. module instance here as the memory is shared */
  510. if (!validate_app_addr(retval_offset, sizeof(int32))) {
  511. /* Join failed, but we don't want to terminate all threads,
  512. do not spread exception here */
  513. wasm_runtime_set_exception(module_inst, NULL);
  514. return -1;
  515. }
  516. retval = (void **)addr_app_to_native(retval_offset);
  517. node = get_thread_info(exec_env, thread);
  518. if (!node) {
  519. /* The thread has exited and not joinable, return 0 to app */
  520. return 0;
  521. }
  522. target_exec_env = node->exec_env;
  523. bh_assert(target_exec_env);
  524. if (node->status != THREAD_EXIT) {
  525. /* if the thread is still running, call the platforms join API */
  526. join_ret = wasm_cluster_join_thread(target_exec_env, (void **)&ret);
  527. }
  528. else {
  529. /* if the thread has exited, return stored results */
  530. /* this thread must be joinable, otherwise the
  531. info_node should be destroyed once exit */
  532. bh_assert(node->joinable);
  533. join_ret = 0;
  534. ret = node->u.ret;
  535. }
  536. if (retval_offset != 0)
  537. *(uint32 *)retval = (uint32)(uintptr_t)ret;
  538. return join_ret;
  539. }
  540. static int32
  541. pthread_detach_wrapper(wasm_exec_env_t exec_env, uint32 thread)
  542. {
  543. ThreadInfoNode *node;
  544. wasm_exec_env_t target_exec_env;
  545. node = get_thread_info(exec_env, thread);
  546. if (!node)
  547. return 0;
  548. node->joinable = false;
  549. target_exec_env = node->exec_env;
  550. bh_assert(target_exec_env != NULL);
  551. return wasm_cluster_detach_thread(target_exec_env);
  552. }
  553. static int32
  554. pthread_cancel_wrapper(wasm_exec_env_t exec_env, uint32 thread)
  555. {
  556. ThreadInfoNode *node;
  557. wasm_exec_env_t target_exec_env;
  558. node = get_thread_info(exec_env, thread);
  559. if (!node)
  560. return 0;
  561. node->status = THREAD_CANCELLED;
  562. node->joinable = false;
  563. target_exec_env = node->exec_env;
  564. bh_assert(target_exec_env != NULL);
  565. return wasm_cluster_cancel_thread(target_exec_env);
  566. }
  567. static int32
  568. pthread_self_wrapper(wasm_exec_env_t exec_env)
  569. {
  570. ThreadRoutineArgs *args = get_thread_arg(exec_env);
  571. /* If thread_arg is NULL, it's the exec_env of the main thread,
  572. return id 0 to app */
  573. if (!args)
  574. return 0;
  575. return args->info_node->handle;
  576. }
  577. static void
  578. pthread_exit_wrapper(wasm_exec_env_t exec_env, int32 retval_offset)
  579. {
  580. wasm_module_inst_t module_inst = get_module_inst(exec_env);
  581. ThreadRoutineArgs *args = get_thread_arg(exec_env);
  582. /* Currently exit main thread is not allowed */
  583. if (!args)
  584. return;
  585. #if defined(OS_ENABLE_HW_BOUND_CHECK) && !defined(BH_PLATFORM_WINDOWS)
  586. /* If hardware bound check enabled, don't deinstantiate module inst
  587. and thread info node here for AoT module, as they will be freed
  588. in pthread_start_routine */
  589. if (exec_env->jmpbuf_stack_top) {
  590. wasm_cluster_exit_thread(exec_env, (void *)(uintptr_t)retval_offset);
  591. }
  592. #endif
  593. /* destroy pthread key values */
  594. call_key_destructor(exec_env);
  595. /* routine exit, destroy instance */
  596. wasm_runtime_deinstantiate_internal(module_inst, true);
  597. if (!args->info_node->joinable) {
  598. delete_thread_info_node(args->info_node);
  599. }
  600. else {
  601. args->info_node->u.ret = (void *)(uintptr_t)retval_offset;
  602. /* Update node status after ret value was set */
  603. args->info_node->status = THREAD_EXIT;
  604. }
  605. wasm_runtime_free(args);
  606. wasm_cluster_exit_thread(exec_env, (void *)(uintptr_t)retval_offset);
  607. }
  608. static int32
  609. pthread_mutex_init_wrapper(wasm_exec_env_t exec_env, uint32 *mutex, void *attr)
  610. {
  611. korp_mutex *pmutex;
  612. ThreadInfoNode *info_node;
  613. if (!(pmutex = wasm_runtime_malloc(sizeof(korp_mutex)))) {
  614. return -1;
  615. }
  616. if (os_mutex_init(pmutex) != 0) {
  617. goto fail1;
  618. }
  619. if (!(info_node = wasm_runtime_malloc(sizeof(ThreadInfoNode))))
  620. goto fail2;
  621. memset(info_node, 0, sizeof(ThreadInfoNode));
  622. info_node->exec_env = exec_env;
  623. info_node->handle = allocate_handle();
  624. info_node->type = T_MUTEX;
  625. info_node->u.mutex = pmutex;
  626. info_node->status = MUTEX_CREATED;
  627. if (!append_thread_info_node(info_node))
  628. goto fail3;
  629. /* Return the mutex handle to app */
  630. if (mutex)
  631. *(uint32 *)mutex = info_node->handle;
  632. return 0;
  633. fail3:
  634. delete_thread_info_node(info_node);
  635. fail2:
  636. os_mutex_destroy(pmutex);
  637. fail1:
  638. wasm_runtime_free(pmutex);
  639. return -1;
  640. }
  641. static int32
  642. pthread_mutex_lock_wrapper(wasm_exec_env_t exec_env, uint32 *mutex)
  643. {
  644. ThreadInfoNode *info_node = get_thread_info(exec_env, *mutex);
  645. if (!info_node || info_node->type != T_MUTEX)
  646. return -1;
  647. return os_mutex_lock(info_node->u.mutex);
  648. }
  649. static int32
  650. pthread_mutex_unlock_wrapper(wasm_exec_env_t exec_env, uint32 *mutex)
  651. {
  652. ThreadInfoNode *info_node = get_thread_info(exec_env, *mutex);
  653. if (!info_node || info_node->type != T_MUTEX)
  654. return -1;
  655. return os_mutex_unlock(info_node->u.mutex);
  656. }
  657. static int32
  658. pthread_mutex_destroy_wrapper(wasm_exec_env_t exec_env, uint32 *mutex)
  659. {
  660. int32 ret_val;
  661. ThreadInfoNode *info_node = get_thread_info(exec_env, *mutex);
  662. if (!info_node || info_node->type != T_MUTEX)
  663. return -1;
  664. ret_val = os_mutex_destroy(info_node->u.mutex);
  665. info_node->status = MUTEX_DESTROYED;
  666. delete_thread_info_node(info_node);
  667. return ret_val;
  668. }
  669. static int32
  670. pthread_cond_init_wrapper(wasm_exec_env_t exec_env, uint32 *cond, void *attr)
  671. {
  672. korp_cond *pcond;
  673. ThreadInfoNode *info_node;
  674. if (!(pcond = wasm_runtime_malloc(sizeof(korp_cond)))) {
  675. return -1;
  676. }
  677. if (os_cond_init(pcond) != 0) {
  678. goto fail1;
  679. }
  680. if (!(info_node = wasm_runtime_malloc(sizeof(ThreadInfoNode))))
  681. goto fail2;
  682. memset(info_node, 0, sizeof(ThreadInfoNode));
  683. info_node->exec_env = exec_env;
  684. info_node->handle = allocate_handle();
  685. info_node->type = T_COND;
  686. info_node->u.cond = pcond;
  687. info_node->status = COND_CREATED;
  688. if (!append_thread_info_node(info_node))
  689. goto fail3;
  690. /* Return the cond handle to app */
  691. if (cond)
  692. *(uint32 *)cond = info_node->handle;
  693. return 0;
  694. fail3:
  695. delete_thread_info_node(info_node);
  696. fail2:
  697. os_cond_destroy(pcond);
  698. fail1:
  699. wasm_runtime_free(pcond);
  700. return -1;
  701. }
  702. static int32
  703. pthread_cond_wait_wrapper(wasm_exec_env_t exec_env, uint32 *cond, uint32 *mutex)
  704. {
  705. ThreadInfoNode *cond_info_node, *mutex_info_node;
  706. cond_info_node = get_thread_info(exec_env, *cond);
  707. if (!cond_info_node || cond_info_node->type != T_COND)
  708. return -1;
  709. mutex_info_node = get_thread_info(exec_env, *mutex);
  710. if (!mutex_info_node || mutex_info_node->type != T_MUTEX)
  711. return -1;
  712. return os_cond_wait(cond_info_node->u.cond, mutex_info_node->u.mutex);
  713. }
  714. /**
  715. * Currently we don't support struct timespec in built-in libc,
  716. * so the pthread_cond_timedwait use useconds instead
  717. */
  718. static int32
  719. pthread_cond_timedwait_wrapper(wasm_exec_env_t exec_env, uint32 *cond,
  720. uint32 *mutex, uint64 useconds)
  721. {
  722. ThreadInfoNode *cond_info_node, *mutex_info_node;
  723. cond_info_node = get_thread_info(exec_env, *cond);
  724. if (!cond_info_node || cond_info_node->type != T_COND)
  725. return -1;
  726. mutex_info_node = get_thread_info(exec_env, *mutex);
  727. if (!mutex_info_node || mutex_info_node->type != T_MUTEX)
  728. return -1;
  729. return os_cond_reltimedwait(cond_info_node->u.cond,
  730. mutex_info_node->u.mutex, useconds);
  731. }
  732. static int32
  733. pthread_cond_signal_wrapper(wasm_exec_env_t exec_env, uint32 *cond)
  734. {
  735. ThreadInfoNode *info_node = get_thread_info(exec_env, *cond);
  736. if (!info_node || info_node->type != T_COND)
  737. return -1;
  738. return os_cond_signal(info_node->u.cond);
  739. }
  740. static int32
  741. pthread_cond_destroy_wrapper(wasm_exec_env_t exec_env, uint32 *cond)
  742. {
  743. int32 ret_val;
  744. ThreadInfoNode *info_node = get_thread_info(exec_env, *cond);
  745. if (!info_node || info_node->type != T_COND)
  746. return -1;
  747. ret_val = os_cond_destroy(info_node->u.cond);
  748. info_node->status = COND_DESTROYED;
  749. delete_thread_info_node(info_node);
  750. return ret_val;
  751. }
  752. static int32
  753. pthread_key_create_wrapper(wasm_exec_env_t exec_env, int32 *key,
  754. int32 destructor_elem_index)
  755. {
  756. uint32 i;
  757. WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
  758. ClusterInfoNode *info = get_cluster_info(cluster);
  759. if (!info) {
  760. /* The user may call pthread_key_create in main thread,
  761. in this case the cluster info hasn't been created */
  762. if (!(info = create_cluster_info(cluster))) {
  763. return -1;
  764. }
  765. }
  766. os_mutex_lock(&info->key_data_list_lock);
  767. for (i = 0; i < WAMR_PTHREAD_KEYS_MAX; i++) {
  768. if (!info->key_data_list[i].is_created) {
  769. break;
  770. }
  771. }
  772. if (i == WAMR_PTHREAD_KEYS_MAX) {
  773. os_mutex_unlock(&info->key_data_list_lock);
  774. return -1;
  775. }
  776. info->key_data_list[i].destructor_func = destructor_elem_index;
  777. info->key_data_list[i].is_created = true;
  778. *key = i;
  779. os_mutex_unlock(&info->key_data_list_lock);
  780. return 0;
  781. }
  782. static int32
  783. pthread_setspecific_wrapper(wasm_exec_env_t exec_env, int32 key,
  784. int32 value_offset)
  785. {
  786. WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
  787. ClusterInfoNode *info = get_cluster_info(cluster);
  788. int32 *key_values;
  789. if (!info)
  790. return -1;
  791. os_mutex_lock(&info->key_data_list_lock);
  792. key_values = key_value_list_lookup_or_create(exec_env, info, key);
  793. if (!key_values) {
  794. os_mutex_unlock(&info->key_data_list_lock);
  795. return 0;
  796. }
  797. key_values[key] = value_offset;
  798. os_mutex_unlock(&info->key_data_list_lock);
  799. return 0;
  800. }
  801. static int32
  802. pthread_getspecific_wrapper(wasm_exec_env_t exec_env, int32 key)
  803. {
  804. WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
  805. ClusterInfoNode *info = get_cluster_info(cluster);
  806. int32 ret, *key_values;
  807. if (!info)
  808. return -1;
  809. os_mutex_lock(&info->key_data_list_lock);
  810. key_values = key_value_list_lookup_or_create(exec_env, info, key);
  811. if (!key_values) {
  812. os_mutex_unlock(&info->key_data_list_lock);
  813. return 0;
  814. }
  815. ret = key_values[key];
  816. os_mutex_unlock(&info->key_data_list_lock);
  817. return ret;
  818. }
  819. static int32
  820. pthread_key_delete_wrapper(wasm_exec_env_t exec_env, int32 key)
  821. {
  822. KeyData *data;
  823. WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
  824. ClusterInfoNode *info = get_cluster_info(cluster);
  825. if (!info)
  826. return -1;
  827. os_mutex_lock(&info->key_data_list_lock);
  828. data = key_data_list_lookup(exec_env, key);
  829. if (!data) {
  830. os_mutex_unlock(&info->key_data_list_lock);
  831. return -1;
  832. }
  833. memset(data, 0, sizeof(KeyData));
  834. os_mutex_unlock(&info->key_data_list_lock);
  835. return 0;
  836. }
  837. /**
  838. * Currently the memory allocator doesn't support alloc specific aligned
  839. * space, we wrap posix_memalign to simply malloc memory
  840. */
  841. static int32
  842. posix_memalign_wrapper(wasm_exec_env_t exec_env, void **memptr, int32 align,
  843. int32 size)
  844. {
  845. wasm_module_inst_t module_inst = get_module_inst(exec_env);
  846. void *p = NULL;
  847. *((int32 *)memptr) = module_malloc(size, (void **)&p);
  848. if (!p)
  849. return -1;
  850. return 0;
  851. }
  852. /* clang-format off */
  853. #define REG_NATIVE_FUNC(func_name, signature) \
  854. { #func_name, func_name##_wrapper, signature, NULL }
  855. /* clang-format on */
  856. static NativeSymbol native_symbols_lib_pthread[] = {
  857. REG_NATIVE_FUNC(pthread_create, "(**ii)i"),
  858. REG_NATIVE_FUNC(pthread_join, "(ii)i"),
  859. REG_NATIVE_FUNC(pthread_detach, "(i)i"),
  860. REG_NATIVE_FUNC(pthread_cancel, "(i)i"),
  861. REG_NATIVE_FUNC(pthread_self, "()i"),
  862. REG_NATIVE_FUNC(pthread_exit, "(i)"),
  863. REG_NATIVE_FUNC(pthread_mutex_init, "(**)i"),
  864. REG_NATIVE_FUNC(pthread_mutex_lock, "(*)i"),
  865. REG_NATIVE_FUNC(pthread_mutex_unlock, "(*)i"),
  866. REG_NATIVE_FUNC(pthread_mutex_destroy, "(*)i"),
  867. REG_NATIVE_FUNC(pthread_cond_init, "(**)i"),
  868. REG_NATIVE_FUNC(pthread_cond_wait, "(**)i"),
  869. REG_NATIVE_FUNC(pthread_cond_timedwait, "(**I)i"),
  870. REG_NATIVE_FUNC(pthread_cond_signal, "(*)i"),
  871. REG_NATIVE_FUNC(pthread_cond_destroy, "(*)i"),
  872. REG_NATIVE_FUNC(pthread_key_create, "(*i)i"),
  873. REG_NATIVE_FUNC(pthread_setspecific, "(ii)i"),
  874. REG_NATIVE_FUNC(pthread_getspecific, "(i)i"),
  875. REG_NATIVE_FUNC(pthread_key_delete, "(i)i"),
  876. REG_NATIVE_FUNC(posix_memalign, "(*ii)i"),
  877. };
  878. uint32
  879. get_lib_pthread_export_apis(NativeSymbol **p_lib_pthread_apis)
  880. {
  881. *p_lib_pthread_apis = native_symbols_lib_pthread;
  882. return sizeof(native_symbols_lib_pthread) / sizeof(NativeSymbol);
  883. }