lib_pthread_wrapper.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731
  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 get_module(exec_env) \
  12. wasm_exec_env_get_module(exec_env)
  13. #define get_module_inst(exec_env) \
  14. wasm_runtime_get_module_inst(exec_env)
  15. #define get_thread_arg(exec_env) \
  16. wasm_exec_env_get_thread_arg(exec_env)
  17. #define get_wasi_ctx(module_inst) \
  18. wasm_runtime_get_wasi_ctx(module_inst)
  19. #define validate_app_addr(offset, size) \
  20. wasm_runtime_validate_app_addr(module_inst, offset, size)
  21. #define validate_native_addr(addr, size) \
  22. wasm_runtime_validate_native_addr(module_inst, addr, size)
  23. #define addr_app_to_native(offset) \
  24. wasm_runtime_addr_app_to_native(module_inst, offset)
  25. #define addr_native_to_app(ptr) \
  26. wasm_runtime_addr_native_to_app(module_inst, ptr)
  27. extern bool
  28. wasm_runtime_call_indirect(wasm_exec_env_t exec_env,
  29. uint32 element_indices,
  30. uint32 argc, uint32 argv[]);
  31. enum {
  32. T_THREAD,
  33. T_MUTEX,
  34. T_COND,
  35. };
  36. enum thread_status_t {
  37. THREAD_INIT,
  38. THREAD_RUNNING,
  39. THREAD_CANCELLED,
  40. THREAD_EXIT,
  41. };
  42. enum mutex_status_t {
  43. MUTEX_CREATED,
  44. MUTEX_DESTROYED,
  45. };
  46. enum cond_status_t {
  47. COND_CREATED,
  48. COND_DESTROYED,
  49. };
  50. typedef struct ClusterInfoNode {
  51. bh_list_link l;
  52. WASMCluster *cluster;
  53. HashMap *thread_info_map;
  54. } ClusterInfoNode;
  55. typedef struct ThreadInfoNode {
  56. wasm_exec_env_t parent_exec_env;
  57. wasm_exec_env_t exec_env;
  58. /* the id returned to app */
  59. uint32 handle;
  60. /* type can be [THREAD | MUTEX | CONDITION] */
  61. uint32 type;
  62. /* Thread status, this variable should be volatile
  63. as its value may be changed in different threads */
  64. volatile uint32 status;
  65. union {
  66. korp_tid thread;
  67. korp_mutex *mutex;
  68. korp_cond *cond;
  69. } u;
  70. } ThreadInfoNode;
  71. typedef struct {
  72. ThreadInfoNode *info_node;
  73. /* table elem index of the app's entry function */
  74. uint32 elem_index;
  75. /* arg of the app's entry function */
  76. void *arg;
  77. wasm_module_inst_t module_inst;
  78. } ThreadRoutineArgs;
  79. static bh_list cluster_info_list;
  80. static korp_mutex pthread_global_lock;
  81. static uint32 handle_id = 1;
  82. static void
  83. lib_pthread_destroy_callback(WASMCluster *cluster);
  84. static uint32
  85. thread_handle_hash(void *handle)
  86. {
  87. return (uint32)(uintptr_t)handle;
  88. }
  89. static bool
  90. thread_handle_equal(void *h1, void *h2)
  91. {
  92. return (uint32)(uintptr_t)h1 == (uint32)(uintptr_t)h2 ? true : false;
  93. }
  94. static void
  95. thread_info_destroy(void *node)
  96. {
  97. ThreadInfoNode *info_node = (ThreadInfoNode *)node;
  98. ThreadRoutineArgs *args;
  99. pthread_mutex_lock(&pthread_global_lock);
  100. if (info_node->type == T_THREAD) {
  101. args = get_thread_arg(info_node->exec_env);
  102. if (args) {
  103. wasm_runtime_free(args);
  104. }
  105. }
  106. else if (info_node->type == T_MUTEX) {
  107. if (info_node->status != MUTEX_DESTROYED)
  108. os_mutex_destroy(info_node->u.mutex);
  109. wasm_runtime_free(info_node->u.mutex);
  110. }
  111. else if (info_node->type == T_COND) {
  112. if (info_node->status != COND_DESTROYED)
  113. os_cond_destroy(info_node->u.cond);
  114. wasm_runtime_free(info_node->u.cond);
  115. }
  116. wasm_runtime_free(info_node);
  117. pthread_mutex_unlock(&pthread_global_lock);
  118. }
  119. bool
  120. lib_pthread_init()
  121. {
  122. if (0 != os_mutex_init(&pthread_global_lock))
  123. return false;
  124. bh_list_init(&cluster_info_list);
  125. if (!wasm_cluster_register_destroy_callback(
  126. lib_pthread_destroy_callback)) {
  127. os_mutex_destroy(&pthread_global_lock);
  128. return false;
  129. }
  130. return true;
  131. }
  132. void
  133. lib_pthread_destroy()
  134. {
  135. os_mutex_destroy(&pthread_global_lock);
  136. }
  137. static ClusterInfoNode*
  138. get_cluster_info(WASMCluster *cluster)
  139. {
  140. ClusterInfoNode *node;
  141. os_mutex_lock(&pthread_global_lock);
  142. node = bh_list_first_elem(&cluster_info_list);
  143. while (node) {
  144. if (cluster == node->cluster) {
  145. os_mutex_unlock(&pthread_global_lock);
  146. return node;
  147. }
  148. node = bh_list_elem_next(node);
  149. }
  150. os_mutex_unlock(&pthread_global_lock);
  151. return NULL;
  152. }
  153. static ClusterInfoNode*
  154. create_cluster_info(WASMCluster *cluster)
  155. {
  156. ClusterInfoNode *node;
  157. bh_list_status ret;
  158. if (!(node = wasm_runtime_malloc(sizeof(ClusterInfoNode)))) {
  159. return NULL;
  160. }
  161. node->cluster = cluster;
  162. if (!(node->thread_info_map =
  163. bh_hash_map_create(32, true,
  164. (HashFunc)thread_handle_hash,
  165. (KeyEqualFunc)thread_handle_equal,
  166. NULL,
  167. thread_info_destroy))) {
  168. wasm_runtime_free(node);
  169. return NULL;
  170. }
  171. os_mutex_lock(&pthread_global_lock);
  172. ret = bh_list_insert(&cluster_info_list, node);
  173. bh_assert(ret == 0);
  174. os_mutex_unlock(&pthread_global_lock);
  175. (void)ret;
  176. return node;
  177. }
  178. static bool
  179. destroy_cluster_info(WASMCluster *cluster)
  180. {
  181. ClusterInfoNode *node = get_cluster_info(cluster);
  182. if (node) {
  183. bh_hash_map_destroy(node->thread_info_map);
  184. os_mutex_lock(&pthread_global_lock);
  185. bh_list_remove(&cluster_info_list, node);
  186. wasm_runtime_free(node);
  187. os_mutex_unlock(&pthread_global_lock);
  188. return true;
  189. }
  190. return false;
  191. }
  192. static void
  193. lib_pthread_destroy_callback(WASMCluster *cluster)
  194. {
  195. destroy_cluster_info(cluster);
  196. }
  197. static void
  198. delete_thread_info_node(ThreadInfoNode *thread_info)
  199. {
  200. ClusterInfoNode *node;
  201. bool ret;
  202. WASMCluster *cluster =
  203. wasm_exec_env_get_cluster(thread_info->exec_env);
  204. if ((node = get_cluster_info(cluster))) {
  205. ret = bh_hash_map_remove(node->thread_info_map,
  206. (void *)(uintptr_t)thread_info->handle,
  207. NULL, NULL);
  208. (void)ret;
  209. }
  210. thread_info_destroy(thread_info);
  211. }
  212. static bool
  213. append_thread_info_node(ThreadInfoNode *thread_info)
  214. {
  215. ClusterInfoNode *node;
  216. WASMCluster *cluster =
  217. wasm_exec_env_get_cluster(thread_info->exec_env);
  218. if (!(node = get_cluster_info(cluster))) {
  219. if (!(node = create_cluster_info(cluster))) {
  220. return false;
  221. }
  222. }
  223. if (!bh_hash_map_insert(node->thread_info_map,
  224. (void *)(uintptr_t)thread_info->handle,
  225. thread_info)) {
  226. return false;
  227. }
  228. return true;
  229. }
  230. static ThreadInfoNode*
  231. get_thread_info(wasm_exec_env_t exec_env, uint32 handle)
  232. {
  233. WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
  234. ClusterInfoNode *info = get_cluster_info(cluster);
  235. return bh_hash_map_find(info->thread_info_map, (void *)(uintptr_t)handle);
  236. }
  237. static uint32
  238. allocate_handle()
  239. {
  240. uint32 id;
  241. os_mutex_lock(&pthread_global_lock);
  242. id = handle_id++;
  243. os_mutex_unlock(&pthread_global_lock);
  244. return id;
  245. }
  246. static void*
  247. pthread_start_routine(void *arg)
  248. {
  249. wasm_exec_env_t exec_env = (wasm_exec_env_t)arg;
  250. wasm_exec_env_t parent_exec_env;
  251. wasm_module_inst_t module_inst = get_module_inst(exec_env);
  252. ThreadRoutineArgs *routine_args = exec_env->thread_arg;
  253. ThreadInfoNode *info_node = routine_args->info_node;
  254. uint32 argv[1];
  255. parent_exec_env = info_node->parent_exec_env;
  256. os_mutex_lock(&parent_exec_env->wait_lock);
  257. info_node->exec_env = exec_env;
  258. info_node->u.thread = exec_env->handle;
  259. if (!append_thread_info_node(info_node)) {
  260. wasm_runtime_deinstantiate_internal(module_inst, true);
  261. delete_thread_info_node(info_node);
  262. os_cond_signal(&parent_exec_env->wait_cond);
  263. os_mutex_unlock(&parent_exec_env->wait_lock);
  264. return NULL;
  265. }
  266. info_node->status = THREAD_RUNNING;
  267. os_cond_signal(&parent_exec_env->wait_cond);
  268. os_mutex_unlock(&parent_exec_env->wait_lock);
  269. if (!validate_native_addr(routine_args->arg, sizeof(uint32))) {
  270. /* If there are exceptions, copy the exception to
  271. all other instance in this cluster */
  272. wasm_cluster_spread_exception(exec_env);
  273. wasm_runtime_deinstantiate_internal(module_inst, true);
  274. delete_thread_info_node(info_node);
  275. return NULL;
  276. }
  277. argv[0] = addr_native_to_app(routine_args->arg);
  278. if(!wasm_runtime_call_indirect(exec_env,
  279. routine_args->elem_index,
  280. 1, argv)) {
  281. wasm_cluster_spread_exception(exec_env);
  282. }
  283. /* routine exit, destroy instance */
  284. wasm_runtime_deinstantiate_internal(module_inst, true);
  285. info_node->status = THREAD_EXIT;
  286. delete_thread_info_node(info_node);
  287. return (void *)(uintptr_t)argv[0];
  288. }
  289. static int
  290. pthread_create_wrapper(wasm_exec_env_t exec_env,
  291. uint32 *thread, /* thread_handle */
  292. const void *attr, /* not supported */
  293. uint32 elem_index, /* entry function */
  294. void *arg) /* arguments buffer */
  295. {
  296. wasm_module_t module = get_module(exec_env);
  297. wasm_module_inst_t new_module_inst = NULL;
  298. ThreadInfoNode *info_node = NULL;
  299. ThreadRoutineArgs *routine_args = NULL;
  300. uint32 thread_handle;
  301. int32 ret = -1;
  302. #if WASM_ENABLE_LIBC_WASI != 0
  303. wasm_module_inst_t module_inst = get_module_inst(exec_env);
  304. WASIContext *wasi_ctx = get_wasi_ctx(module_inst);
  305. #endif
  306. if (!(new_module_inst =
  307. wasm_runtime_instantiate_internal(module, true, 8192, 0,
  308. NULL, 0)))
  309. return -1;
  310. #if WASM_ENABLE_LIBC_WASI != 0
  311. if (wasi_ctx)
  312. wasm_runtime_set_wasi_ctx(new_module_inst, wasi_ctx);
  313. #endif
  314. if (!(info_node = wasm_runtime_malloc(sizeof(ThreadInfoNode))))
  315. goto fail;
  316. memset(info_node, 0, sizeof(ThreadInfoNode));
  317. thread_handle = allocate_handle();
  318. info_node->parent_exec_env = exec_env;
  319. info_node->handle = thread_handle;
  320. info_node->type = T_THREAD;
  321. info_node->status = THREAD_INIT;
  322. if (!(routine_args = wasm_runtime_malloc(sizeof(ThreadRoutineArgs))))
  323. goto fail;
  324. routine_args->arg = arg;
  325. routine_args->elem_index = elem_index;
  326. routine_args->info_node = info_node;
  327. routine_args->module_inst = new_module_inst;
  328. os_mutex_lock(&exec_env->wait_lock);
  329. ret = wasm_cluster_create_thread(exec_env, new_module_inst,
  330. pthread_start_routine,
  331. (void *)routine_args);
  332. if (ret != 0) {
  333. os_mutex_unlock(&exec_env->wait_lock);
  334. goto fail;
  335. }
  336. /* Wait for the thread routine to assign the exec_env to
  337. thread_info_node, otherwise the exec_env in the thread
  338. info node may be NULL in the next pthread API call */
  339. os_cond_wait(&exec_env->wait_cond, &exec_env->wait_lock);
  340. os_mutex_unlock(&exec_env->wait_lock);
  341. if (thread)
  342. *thread = thread_handle;
  343. return 0;
  344. fail:
  345. if (new_module_inst)
  346. wasm_runtime_deinstantiate_internal(new_module_inst, true);
  347. if (info_node)
  348. wasm_runtime_free(info_node);
  349. if (routine_args)
  350. wasm_runtime_free(routine_args);
  351. return ret;
  352. }
  353. static int32
  354. pthread_join_wrapper(wasm_exec_env_t exec_env, uint32 thread,
  355. int32 retval_offset) /* void **retval */
  356. {
  357. uint32 *ret;
  358. int32 join_ret;
  359. void **retval;
  360. ThreadInfoNode *node;
  361. wasm_module_inst_t module_inst;
  362. wasm_exec_env_t target_exec_env;
  363. node = get_thread_info(exec_env, thread);
  364. if (!node) {
  365. /* The thread has exited, return 0 to app */
  366. return 0;
  367. }
  368. target_exec_env = node->exec_env;
  369. bh_assert(target_exec_env != NULL);
  370. module_inst = get_module_inst(target_exec_env);
  371. /* validate addr before join thread, otherwise
  372. the module_inst may be freed */
  373. if (!validate_app_addr(retval_offset, sizeof(uint32))) {
  374. /* Join failed, but we don't want to terminate all threads,
  375. do not spread exception here */
  376. wasm_runtime_set_exception(module_inst, NULL);
  377. return -1;
  378. }
  379. retval = (void **)addr_app_to_native(retval_offset);
  380. join_ret = wasm_cluster_join_thread(target_exec_env, (void **)&ret);
  381. if (retval_offset != 0)
  382. *retval = (void*)ret;
  383. return join_ret;
  384. }
  385. static int32
  386. pthread_detach_wrapper(wasm_exec_env_t exec_env, uint32 thread)
  387. {
  388. ThreadInfoNode *node;
  389. wasm_exec_env_t target_exec_env;
  390. node = get_thread_info(exec_env, thread);
  391. if (!node)
  392. return 0;
  393. target_exec_env = node->exec_env;
  394. bh_assert(target_exec_env != NULL);
  395. return wasm_cluster_detach_thread(target_exec_env);
  396. }
  397. static int32
  398. pthread_cancel_wrapper(wasm_exec_env_t exec_env, uint32 thread)
  399. {
  400. ThreadInfoNode *node;
  401. wasm_exec_env_t target_exec_env;
  402. node = get_thread_info(exec_env, thread);
  403. if (!node)
  404. return 0;
  405. target_exec_env = node->exec_env;
  406. bh_assert(target_exec_env != NULL);
  407. return wasm_cluster_cancel_thread(target_exec_env);
  408. }
  409. static int32
  410. pthread_self_wrapper(wasm_exec_env_t exec_env)
  411. {
  412. ThreadRoutineArgs *args = get_thread_arg(exec_env);
  413. /* If thread_arg is NULL, it's the exec_env of the main thread,
  414. return id 0 to app */
  415. if (!args)
  416. return 0;
  417. return args->info_node->handle;
  418. }
  419. static void
  420. pthread_exit_wrapper(wasm_exec_env_t exec_env, int32 retval_offset)
  421. {
  422. wasm_module_inst_t module_inst = get_module_inst(exec_env);
  423. ThreadRoutineArgs *args = get_thread_arg(exec_env);
  424. /* Currently exit main thread is not allowed */
  425. if (!args)
  426. return;
  427. /* routine exit, destroy instance */
  428. wasm_runtime_deinstantiate_internal(module_inst, true);
  429. delete_thread_info_node(args->info_node);
  430. wasm_cluster_exit_thread(exec_env, (void *)(uintptr_t)retval_offset);
  431. }
  432. static int32
  433. pthread_mutex_init_wrapper(wasm_exec_env_t exec_env, uint32 *mutex, void *attr)
  434. {
  435. korp_mutex *pmutex;
  436. ThreadInfoNode *info_node;
  437. if (!(pmutex = wasm_runtime_malloc(sizeof(korp_mutex)))) {
  438. return -1;
  439. }
  440. if (os_mutex_init(pmutex) != 0) {
  441. goto fail1;
  442. }
  443. if (!(info_node = wasm_runtime_malloc(sizeof(ThreadInfoNode))))
  444. goto fail2;
  445. memset(info_node, 0, sizeof(ThreadInfoNode));
  446. info_node->exec_env = exec_env;
  447. info_node->handle = allocate_handle();
  448. info_node->type = T_MUTEX;
  449. info_node->u.mutex = pmutex;
  450. info_node->status = MUTEX_CREATED;
  451. if (!append_thread_info_node(info_node))
  452. goto fail3;
  453. /* Return the mutex handle to app */
  454. if (mutex)
  455. *(uint32*)mutex = info_node->handle;
  456. return 0;
  457. fail3:
  458. delete_thread_info_node(info_node);
  459. fail2:
  460. os_mutex_destroy(pmutex);
  461. fail1:
  462. wasm_runtime_free(pmutex);
  463. return -1;
  464. }
  465. static int32
  466. pthread_mutex_lock_wrapper(wasm_exec_env_t exec_env, uint32 *mutex)
  467. {
  468. ThreadInfoNode* info_node = get_thread_info(exec_env, *mutex);
  469. if (!info_node || info_node->type != T_MUTEX)
  470. return -1;
  471. return os_mutex_lock(info_node->u.mutex);
  472. }
  473. static int32
  474. pthread_mutex_unlock_wrapper(wasm_exec_env_t exec_env, uint32 *mutex)
  475. {
  476. ThreadInfoNode* info_node = get_thread_info(exec_env, *mutex);
  477. if (!info_node || info_node->type != T_MUTEX)
  478. return -1;
  479. return os_mutex_unlock(info_node->u.mutex);
  480. }
  481. static int32
  482. pthread_mutex_destroy_wrapper(wasm_exec_env_t exec_env, uint32 *mutex)
  483. {
  484. int32 ret_val;
  485. ThreadInfoNode* info_node = get_thread_info(exec_env, *mutex);
  486. if (!info_node || info_node->type != T_MUTEX)
  487. return -1;
  488. ret_val = os_mutex_destroy(info_node->u.mutex);
  489. info_node->status = MUTEX_DESTROYED;
  490. delete_thread_info_node(info_node);
  491. return ret_val;
  492. }
  493. static int32
  494. pthread_cond_init_wrapper(wasm_exec_env_t exec_env, uint32 *cond, void *attr)
  495. {
  496. korp_cond *pcond;
  497. ThreadInfoNode *info_node;
  498. if (!(pcond = wasm_runtime_malloc(sizeof(korp_cond)))) {
  499. return -1;
  500. }
  501. if (os_cond_init(pcond) != 0) {
  502. goto fail1;
  503. }
  504. if (!(info_node = wasm_runtime_malloc(sizeof(ThreadInfoNode))))
  505. goto fail2;
  506. memset(info_node, 0, sizeof(ThreadInfoNode));
  507. info_node->exec_env = exec_env;
  508. info_node->handle = allocate_handle();
  509. info_node->type = T_COND;
  510. info_node->u.cond = pcond;
  511. info_node->status = COND_CREATED;
  512. if (!append_thread_info_node(info_node))
  513. goto fail3;
  514. /* Return the cond handle to app */
  515. if (cond)
  516. *(uint32*)cond = info_node->handle;
  517. return 0;
  518. fail3:
  519. delete_thread_info_node(info_node);
  520. fail2:
  521. os_cond_destroy(pcond);
  522. fail1:
  523. wasm_runtime_free(pcond);
  524. return -1;
  525. }
  526. static int32
  527. pthread_cond_wait_wrapper(wasm_exec_env_t exec_env, uint32 *cond, uint32 *mutex)
  528. {
  529. ThreadInfoNode *cond_info_node, *mutex_info_node;
  530. cond_info_node = get_thread_info(exec_env, *cond);
  531. if (!cond_info_node || cond_info_node->type != T_COND)
  532. return -1;
  533. mutex_info_node = get_thread_info(exec_env, *mutex);
  534. if (!mutex_info_node || mutex_info_node->type != T_MUTEX)
  535. return -1;
  536. return os_cond_wait(cond_info_node->u.cond, mutex_info_node->u.mutex);
  537. }
  538. /* Currently we don't support struct timespec in built-in libc,
  539. so the pthread_cond_timedwait use useconds instead
  540. */
  541. static int32
  542. pthread_cond_timedwait_wrapper(wasm_exec_env_t exec_env, uint32 *cond,
  543. uint32 *mutex, uint32 useconds)
  544. {
  545. ThreadInfoNode *cond_info_node, *mutex_info_node;
  546. cond_info_node = get_thread_info(exec_env, *cond);
  547. if (!cond_info_node || cond_info_node->type != T_COND)
  548. return -1;
  549. mutex_info_node = get_thread_info(exec_env, *mutex);
  550. if (!mutex_info_node || mutex_info_node->type != T_MUTEX)
  551. return -1;
  552. return os_cond_reltimedwait(cond_info_node->u.cond,
  553. mutex_info_node->u.mutex, useconds);
  554. }
  555. static int32
  556. pthread_cond_signal_wrapper(wasm_exec_env_t exec_env, uint32 *cond)
  557. {
  558. ThreadInfoNode* info_node = get_thread_info(exec_env, *cond);
  559. if (!info_node || info_node->type != T_COND)
  560. return -1;
  561. return os_cond_signal(info_node->u.cond);
  562. }
  563. static int32
  564. pthread_cond_destroy_wrapper(wasm_exec_env_t exec_env, uint32 *cond)
  565. {
  566. int32 ret_val;
  567. ThreadInfoNode* info_node = get_thread_info(exec_env, *cond);
  568. if (!info_node || info_node->type != T_COND)
  569. return -1;
  570. ret_val = os_cond_destroy(info_node->u.cond);
  571. info_node->status = COND_DESTROYED;
  572. delete_thread_info_node(info_node);
  573. return ret_val;
  574. }
  575. #define REG_NATIVE_FUNC(func_name, signature) \
  576. { #func_name, func_name##_wrapper, signature, NULL }
  577. static NativeSymbol native_symbols_lib_pthread[] = {
  578. REG_NATIVE_FUNC(pthread_create, "(**i*)i"),
  579. REG_NATIVE_FUNC(pthread_join, "(ii)i"),
  580. REG_NATIVE_FUNC(pthread_detach, "(i)i"),
  581. REG_NATIVE_FUNC(pthread_cancel, "(i)i"),
  582. REG_NATIVE_FUNC(pthread_self, "()i"),
  583. REG_NATIVE_FUNC(pthread_exit, "(i)"),
  584. REG_NATIVE_FUNC(pthread_mutex_init, "(**)i"),
  585. REG_NATIVE_FUNC(pthread_mutex_lock, "(*)i"),
  586. REG_NATIVE_FUNC(pthread_mutex_unlock, "(*)i"),
  587. REG_NATIVE_FUNC(pthread_mutex_destroy, "(*)i"),
  588. REG_NATIVE_FUNC(pthread_cond_init, "(**)i"),
  589. REG_NATIVE_FUNC(pthread_cond_wait, "(**)i"),
  590. REG_NATIVE_FUNC(pthread_cond_timedwait, "(**i)i"),
  591. REG_NATIVE_FUNC(pthread_cond_signal, "(*)i"),
  592. REG_NATIVE_FUNC(pthread_cond_destroy, "(*)i"),
  593. };
  594. uint32
  595. get_lib_pthread_export_apis(NativeSymbol **p_lib_pthread_apis)
  596. {
  597. *p_lib_pthread_apis = native_symbols_lib_pthread;
  598. return sizeof(native_symbols_lib_pthread) / sizeof(NativeSymbol);
  599. }