diff --git a/core/iwasm/common/wasm_exec_env.h b/core/iwasm/common/wasm_exec_env.h index ea2fafd680..86ad1c3e1b 100644 --- a/core/iwasm/common/wasm_exec_env.h +++ b/core/iwasm/common/wasm_exec_env.h @@ -98,6 +98,8 @@ typedef struct WASMExecEnv { /* used to support debugger */ korp_mutex wait_lock; korp_cond wait_cond; + /* the count of threads which are joining current thread */ + uint32 wait_count; #endif #if WASM_ENABLE_DEBUG_INTERP != 0 diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h index 297d0c50c0..560fdeb009 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h @@ -441,47 +441,100 @@ _Static_assert(sizeof(void *) != 4 || _Static_assert(sizeof(void *) != 8 || _Alignof(__wasi_iovec_t) == 8, "non-wasi data layout"); +/** + * The contents of a `subscription` when type is `eventtype::clock`. + */ +typedef struct __wasi_subscription_clock_t { + /** + * The clock against which to compare the timestamp. + */ + __wasi_clockid_t clock_id; + + uint8_t __paddings1[4]; + + /** + * The absolute or relative timestamp. + */ + __wasi_timestamp_t timeout; + + /** + * The amount of time that the implementation may wait additionally + * to coalesce with other events. + */ + __wasi_timestamp_t precision; + + /** + * Flags specifying whether the timeout is absolute or relative + */ + __wasi_subclockflags_t flags; + + uint8_t __paddings2[4]; + +} __wasi_subscription_clock_t __attribute__((aligned(8))); + +_Static_assert(sizeof(__wasi_subscription_clock_t) == 32, "witx calculated size"); +_Static_assert(_Alignof(__wasi_subscription_clock_t) == 8, "witx calculated align"); +_Static_assert(offsetof(__wasi_subscription_clock_t, clock_id) == 0, "witx calculated offset"); +_Static_assert(offsetof(__wasi_subscription_clock_t, timeout) == 8, "witx calculated offset"); +_Static_assert(offsetof(__wasi_subscription_clock_t, precision) == 16, "witx calculated offset"); +_Static_assert(offsetof(__wasi_subscription_clock_t, flags) == 24, "witx calculated offset"); + +/** + * The contents of a `subscription` when type is type is + * `eventtype::fd_read` or `eventtype::fd_write`. + */ +typedef struct __wasi_subscription_fd_readwrite_t { + /** + * The file descriptor on which to wait for it to become ready for reading or writing. + */ + __wasi_fd_t fd; + +} __wasi_subscription_fd_readwrite_t; + +_Static_assert(sizeof(__wasi_subscription_fd_readwrite_t) == 4, "witx calculated size"); +_Static_assert(_Alignof(__wasi_subscription_fd_readwrite_t) == 4, "witx calculated align"); +_Static_assert(offsetof(__wasi_subscription_fd_readwrite_t, fd) == 0, "witx calculated offset"); + +/** + * The contents of a `subscription`. + */ +typedef union __wasi_subscription_u_u_t { + __wasi_subscription_clock_t clock; + __wasi_subscription_fd_readwrite_t fd_readwrite; +} __wasi_subscription_u_u_t ; + +typedef struct __wasi_subscription_u_t { + __wasi_eventtype_t type; + __wasi_subscription_u_u_t u; +} __wasi_subscription_u_t __attribute__((aligned(8))); + +_Static_assert(sizeof(__wasi_subscription_u_t) == 40, "witx calculated size"); +_Static_assert(_Alignof(__wasi_subscription_u_t) == 8, "witx calculated align"); +_Static_assert(offsetof(__wasi_subscription_u_t, u) == 8, "witx calculated union offset"); +_Static_assert(sizeof(__wasi_subscription_u_u_t) == 32, "witx calculated union size"); +_Static_assert(_Alignof(__wasi_subscription_u_u_t) == 8, "witx calculated union align"); + +/** + * Subscription to an event. + */ typedef struct __wasi_subscription_t { + /** + * User-provided value that is attached to the subscription in the + * implementation and returned through `event::userdata`. + */ __wasi_userdata_t userdata; - __wasi_eventtype_t type; - uint8_t __paddings[7]; - union __wasi_subscription_u { - struct __wasi_subscription_u_clock_t { - __wasi_userdata_t identifier; - __wasi_clockid_t clock_id; - uint8_t __paddings1[4]; - __wasi_timestamp_t timeout; - __wasi_timestamp_t precision; - __wasi_subclockflags_t flags; - uint8_t __paddings2[6]; - } clock; - struct __wasi_subscription_u_fd_readwrite_t { - __wasi_fd_t fd; - } fd_readwrite; - } u; -} __wasi_subscription_t __attribute__((aligned(8))); -_Static_assert( - offsetof(__wasi_subscription_t, userdata) == 0, "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_subscription_t, type) == 8, "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_subscription_t, u.clock.identifier) == 16, - "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_subscription_t, u.clock.clock_id) == 24, - "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_subscription_t, u.clock.timeout) == 32, "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_subscription_t, u.clock.precision) == 40, - "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_subscription_t, u.clock.flags) == 48, "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_subscription_t, u.fd_readwrite.fd) == 16, - "non-wasi data layout"); -_Static_assert(sizeof(__wasi_subscription_t) == 56, "non-wasi data layout"); -_Static_assert(_Alignof(__wasi_subscription_t) == 8, "non-wasi data layout"); + + /** + * The type of the event to which to subscribe, and its contents + */ + __wasi_subscription_u_t u; + +} __wasi_subscription_t; + +_Static_assert(sizeof(__wasi_subscription_t) == 48, "witx calculated size"); +_Static_assert(_Alignof(__wasi_subscription_t) == 8, "witx calculated align"); +_Static_assert(offsetof(__wasi_subscription_t, userdata) == 0, "witx calculated offset"); +_Static_assert(offsetof(__wasi_subscription_t, u) == 8, "witx calculated offset"); #if defined(WASMTIME_SSP_WASI_API) #define WASMTIME_SSP_SYSCALL_NAME(name) \ diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c index 94eb0024cb..7e01f85ca8 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c @@ -2418,19 +2418,19 @@ wasmtime_ssp_poll_oneoff( size_t *nevents) NO_LOCK_ANALYSIS { // Sleeping. - if (nsubscriptions == 1 && in[0].type == __WASI_EVENTTYPE_CLOCK) { + if (nsubscriptions == 1 && in[0].u.type == __WASI_EVENTTYPE_CLOCK) { out[0] = (__wasi_event_t){ .userdata = in[0].userdata, - .type = in[0].type, + .type = in[0].u.type, }; #if CONFIG_HAS_CLOCK_NANOSLEEP clockid_t clock_id; - if (convert_clockid(in[0].u.clock.clock_id, &clock_id)) { + if (convert_clockid(in[0].u.u.clock.clock_id, &clock_id)) { struct timespec ts; - convert_timestamp(in[0].u.clock.timeout, &ts); + convert_timestamp(in[0].u.u.clock.timeout, &ts); int ret = clock_nanosleep( clock_id, - (in[0].u.clock.flags & __WASI_SUBSCRIPTION_CLOCK_ABSTIME) != 0 + (in[0].u.u.clock.flags & __WASI_SUBSCRIPTION_CLOCK_ABSTIME) != 0 ? TIMER_ABSTIME : 0, &ts, NULL); @@ -2441,9 +2441,9 @@ wasmtime_ssp_poll_oneoff( out[0].error = __WASI_ENOTSUP; } #else - switch (in[0].u.clock.clock_id) { + switch (in[0].u.u.clock.clock_id) { case __WASI_CLOCK_MONOTONIC: - if ((in[0].u.clock.flags & __WASI_SUBSCRIPTION_CLOCK_ABSTIME) + if ((in[0].u.u.clock.flags & __WASI_SUBSCRIPTION_CLOCK_ABSTIME) != 0) { // TODO(ed): Implement. fputs("Unimplemented absolute sleep on monotonic clock\n", @@ -2454,12 +2454,12 @@ wasmtime_ssp_poll_oneoff( // Perform relative sleeps on the monotonic clock also using // nanosleep(). This is incorrect, but good enough for now. struct timespec ts; - convert_timestamp(in[0].u.clock.timeout, &ts); + convert_timestamp(in[0].u.u.clock.timeout, &ts); nanosleep(&ts, NULL); } break; case __WASI_CLOCK_REALTIME: - if ((in[0].u.clock.flags & __WASI_SUBSCRIPTION_CLOCK_ABSTIME) + if ((in[0].u.u.clock.flags & __WASI_SUBSCRIPTION_CLOCK_ABSTIME) != 0) { // Sleeping to an absolute point in time can only be done // by waiting on a condition variable. @@ -2473,7 +2473,8 @@ wasmtime_ssp_poll_oneoff( return -1; } mutex_lock(&mutex); - cond_timedwait(&cond, &mutex, in[0].u.clock.timeout, true); + cond_timedwait(&cond, &mutex, in[0].u.u.clock.timeout, + true); mutex_unlock(&mutex); mutex_destroy(&mutex); cond_destroy(&cond); @@ -2481,7 +2482,7 @@ wasmtime_ssp_poll_oneoff( else { // Relative sleeps can be done using nanosleep(). struct timespec ts; - convert_timestamp(in[0].u.clock.timeout, &ts); + convert_timestamp(in[0].u.u.clock.timeout, &ts); nanosleep(&ts, NULL); } break; @@ -2519,18 +2520,18 @@ wasmtime_ssp_poll_oneoff( const __wasi_subscription_t *clock_subscription = NULL; for (size_t i = 0; i < nsubscriptions; ++i) { const __wasi_subscription_t *s = &in[i]; - switch (s->type) { + switch (s->u.type) { case __WASI_EVENTTYPE_FD_READ: case __WASI_EVENTTYPE_FD_WRITE: { __wasi_errno_t error = - fd_object_get_locked(&fos[i], ft, s->u.fd_readwrite.fd, + fd_object_get_locked(&fos[i], ft, s->u.u.fd_readwrite.fd, __WASI_RIGHT_POLL_FD_READWRITE, 0); if (error == 0) { // Proper file descriptor on which we can poll(). pfds[i] = (struct pollfd){ .fd = fd_number(fos[i]), - .events = s->type == __WASI_EVENTTYPE_FD_READ + .events = s->u.type == __WASI_EVENTTYPE_FD_READ ? POLLRDNORM : POLLWRNORM, }; @@ -2542,14 +2543,14 @@ wasmtime_ssp_poll_oneoff( out[(*nevents)++] = (__wasi_event_t){ .userdata = s->userdata, .error = error, - .type = s->type, + .type = s->u.type, }; } break; } case __WASI_EVENTTYPE_CLOCK: if (clock_subscription == NULL - && (s->u.clock.flags & __WASI_SUBSCRIPTION_CLOCK_ABSTIME) + && (s->u.u.clock.flags & __WASI_SUBSCRIPTION_CLOCK_ABSTIME) == 0) { // Relative timeout. fos[i] = NULL; @@ -2565,7 +2566,7 @@ wasmtime_ssp_poll_oneoff( out[(*nevents)++] = (__wasi_event_t){ .userdata = s->userdata, .error = __WASI_ENOSYS, - .type = s->type, + .type = s->u.type, }; break; } @@ -2579,7 +2580,7 @@ wasmtime_ssp_poll_oneoff( timeout = 0; } else if (clock_subscription != NULL) { - __wasi_timestamp_t ts = clock_subscription->u.clock.timeout / 1000000; + __wasi_timestamp_t ts = clock_subscription->u.u.clock.timeout / 1000000; timeout = ts > INT_MAX ? -1 : (int)ts; } else { @@ -2603,7 +2604,7 @@ wasmtime_ssp_poll_oneoff( for (size_t i = 0; i < nsubscriptions; ++i) { if (pfds[i].fd >= 0) { __wasi_filesize_t nbytes = 0; - if (in[i].type == __WASI_EVENTTYPE_FD_READ) { + if (in[i].u.type == __WASI_EVENTTYPE_FD_READ) { int l; if (ioctl(fd_number(fos[i]), FIONREAD, &l) == 0) nbytes = (__wasi_filesize_t)l; @@ -2622,7 +2623,7 @@ wasmtime_ssp_poll_oneoff( #else .error = __WASI_EBADF, #endif - .type = in[i].type, + .type = in[i].u.type, }; } else if ((pfds[i].revents & POLLERR) != 0) { @@ -2630,14 +2631,14 @@ wasmtime_ssp_poll_oneoff( out[(*nevents)++] = (__wasi_event_t){ .userdata = in[i].userdata, .error = __WASI_EIO, - .type = in[i].type, + .type = in[i].u.type, }; } else if ((pfds[i].revents & POLLHUP) != 0) { // End-of-file. out[(*nevents)++] = (__wasi_event_t){ .userdata = in[i].userdata, - .type = in[i].type, + .type = in[i].u.type, .u.fd_readwrite.nbytes = nbytes, .u.fd_readwrite.flags = __WASI_EVENT_FD_READWRITE_HANGUP, @@ -2647,7 +2648,7 @@ wasmtime_ssp_poll_oneoff( // Read or write possible. out[(*nevents)++] = (__wasi_event_t){ .userdata = in[i].userdata, - .type = in[i].type, + .type = in[i].u.type, .u.fd_readwrite.nbytes = nbytes, }; } diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.c b/core/iwasm/libraries/thread-mgr/thread_manager.c index f6987c0c8b..8db457c275 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.c +++ b/core/iwasm/libraries/thread-mgr/thread_manager.c @@ -625,16 +625,69 @@ wasm_cluster_set_debug_inst(WASMCluster *cluster, WASMDebugInstance *inst) #endif /* end of WASM_ENABLE_DEBUG_INTERP */ +/* Check whether the exec_env is in one of all clusters, the caller + should add lock to the cluster list before calling us */ +static bool +clusters_have_exec_env(WASMExecEnv *exec_env) +{ + WASMCluster *cluster = bh_list_first_elem(cluster_list); + WASMExecEnv *node; + + while (cluster) { + node = bh_list_first_elem(&cluster->exec_env_list); + + while (node) { + if (node == exec_env) { + bh_assert(exec_env->cluster == cluster); + return true; + } + node = bh_list_elem_next(node); + } + + cluster = bh_list_elem_next(cluster); + } + + return false; +} + int32 wasm_cluster_join_thread(WASMExecEnv *exec_env, void **ret_val) { - return os_thread_join(exec_env->handle, ret_val); + korp_tid handle; + + os_mutex_lock(&cluster_list_lock); + if (!clusters_have_exec_env(exec_env)) { + /* Invalid thread or the thread has exited */ + if (ret_val) + *ret_val = NULL; + os_mutex_unlock(&cluster_list_lock); + return 0; + } + exec_env->wait_count++; + handle = exec_env->handle; + os_mutex_unlock(&cluster_list_lock); + return os_thread_join(handle, ret_val); } int32 wasm_cluster_detach_thread(WASMExecEnv *exec_env) { - return os_thread_detach(exec_env->handle); + int32 ret = 0; + + os_mutex_lock(&cluster_list_lock); + if (!clusters_have_exec_env(exec_env)) { + /* Invalid thread or the thread has exited */ + os_mutex_unlock(&cluster_list_lock); + return 0; + } + if (exec_env->wait_count == 0) { + /* Only detach current thread when there is no other thread + joining it, otherwise let the system resources for the + thread be released after joining */ + ret = os_thread_detach(exec_env->handle); + } + os_mutex_unlock(&cluster_list_lock); + return ret; } void @@ -680,6 +733,14 @@ wasm_cluster_exit_thread(WASMExecEnv *exec_env, void *retval) int32 wasm_cluster_cancel_thread(WASMExecEnv *exec_env) { + os_mutex_lock(&cluster_list_lock); + if (!clusters_have_exec_env(exec_env)) { + /* Invalid thread or the thread has exited */ + os_mutex_unlock(&cluster_list_lock); + return 0; + } + os_mutex_unlock(&cluster_list_lock); + /* Set the termination flag */ #if WASM_ENABLE_DEBUG_INTERP != 0 wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TERM); diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.h b/core/iwasm/libraries/thread-mgr/thread_manager.h index e99efc99c9..2d4962a2c1 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.h +++ b/core/iwasm/libraries/thread-mgr/thread_manager.h @@ -19,6 +19,7 @@ extern "C" { #if WASM_ENABLE_DEBUG_INTERP != 0 typedef struct WASMDebugInstance WASMDebugInstance; #endif + typedef struct WASMCluster { struct WASMCluster *next; diff --git a/core/shared/platform/common/posix/posix_thread.c b/core/shared/platform/common/posix/posix_thread.c index 1e7e4f3750..4a20c10a08 100644 --- a/core/shared/platform/common/posix/posix_thread.c +++ b/core/shared/platform/common/posix/posix_thread.c @@ -326,10 +326,18 @@ os_thread_get_stack_boundary() #elif defined(__APPLE__) || defined(__NuttX__) if ((addr = (uint8 *)pthread_get_stackaddr_np(self))) { stack_size = pthread_get_stacksize_np(self); + + /** + * Check whether stack_addr is the base or end of the stack, + * change it to the base if it is the end of stack. + */ + if (addr <= (uint8 *)&stack_size) + addr = addr + stack_size; + if (stack_size > max_stack_size) - addr -= max_stack_size; - else - addr -= stack_size; + stack_size = max_stack_size; + + addr -= stack_size; /* Reserved 1 guard page at least for safety */ addr += page_size; }