diff --git a/include/proxy-wasm/exports.h b/include/proxy-wasm/exports.h index e81997e3..db809223 100644 --- a/include/proxy-wasm/exports.h +++ b/include/proxy-wasm/exports.h @@ -174,7 +174,7 @@ Word wasi_unstable_path_filestat_set_times(Word, Word, Word, Word, uint64_t, uin Word wasi_unstable_path_link(Word, Word, Word, Word, Word, Word); Word wasi_unstable_path_readlink(Word, Word, Word, Word, Word, Word); Word wasi_unstable_path_remove_directory(Word, Word, Word); -Word wasi_unstable_path_rename(Word, Word, Word, Word, Word); +Word wasi_unstable_path_rename(Word, Word, Word, Word, Word, Word); Word wasi_unstable_path_symlink(Word, Word, Word, Word); Word wasi_unstable_path_unlink_file(Word, Word, Word); Word wasi_unstable_sock_accept(Word, Word, Word); @@ -211,15 +211,17 @@ Word wasi_unstable_path_filestat_get(Word fd, Word flags, Word path, Word path_l #define FOR_ALL_WASI_FUNCTIONS(_f) \ _f(fd_write) _f(fd_read) _f(fd_seek) _f(fd_close) _f(fd_fdstat_get) _f(fd_fdstat_set_flags) \ - _f(fd_fdstat_set_rights) _f(environ_get) _f(environ_sizes_get) _f(args_get) _f(args_sizes_get) \ - _f(clock_time_get) _f(clock_res_get) _f(fd_advise) _f(fd_allocate) _f(fd_datasync) \ - _f(fd_filestat_set_size) _f(fd_filestat_set_times) _f(fd_pread) _f(fd_pwrite) \ - _f(fd_readdir) _f(fd_renumber) _f(fd_sync) _f(fd_tell) _f(path_create_directory) \ - _f(path_filestat_set_times) _f(path_link) _f(path_readlink) _f(path_remove_directory) \ - _f(path_rename) _f(path_symlink) _f(path_unlink_file) _f(sock_accept) \ - _f(sock_recv) _f(sock_send) _f(sock_shutdown) _f(random_get) _f(sched_yield) \ - _f(poll_oneoff) _f(proc_exit) _f(path_open) _f(fd_prestat_get) \ - _f(fd_prestat_dir_name) _f(path_filestat_get) _f(fd_filestat_get) + _f(fd_fdstat_set_rights) _f(environ_get) _f(environ_sizes_get) _f(args_get) \ + _f(args_sizes_get) _f(clock_time_get) _f(clock_res_get) _f(fd_advise) _f(fd_allocate) \ + _f(fd_datasync) _f(fd_filestat_set_size) _f(fd_filestat_set_times) _f(fd_pread) \ + _f(fd_pwrite) _f(fd_readdir) _f(fd_renumber) _f(fd_sync) _f(fd_tell) \ + _f(path_create_directory) _f(path_filestat_set_times) _f(path_link) \ + _f(path_readlink) _f(path_remove_directory) _f(path_rename) \ + _f(path_symlink) _f(path_unlink_file) _f(sock_accept) _f(sock_recv) \ + _f(sock_send) _f(sock_shutdown) _f(random_get) _f(sched_yield) \ + _f(poll_oneoff) _f(proc_exit) _f(path_open) \ + _f(fd_prestat_get) _f(fd_prestat_dir_name) \ + _f(path_filestat_get) _f(fd_filestat_get) // Helpers to generate a stub to pass to VM, in place of a restricted proxy-wasm capability. #define _CREATE_PROXY_WASM_STUB(_fn) \ diff --git a/include/proxy-wasm/wasm.h b/include/proxy-wasm/wasm.h index 9aad384b..95d7a5b7 100644 --- a/include/proxy-wasm/wasm.h +++ b/include/proxy-wasm/wasm.h @@ -85,6 +85,10 @@ class WasmBase : public std::enable_shared_from_this { bool isFailed() { return failed_ != FailState::Ok; } FailState fail_state() { return failed_; } + // Rebuild state management + bool shouldRebuild() const { return should_rebuild_; } + void setShouldRebuild(bool should_rebuild) { should_rebuild_ = should_rebuild; } + const std::string &vm_configuration() const; const std::string &moduleBytecode() const { return module_bytecode_; } @@ -317,6 +321,7 @@ class WasmBase : public std::enable_shared_from_this { std::string vm_configuration_; bool stop_iteration_ = false; FailState failed_ = FailState::Ok; // Wasm VM fatal error. + bool should_rebuild_ = false; // Wasm VM rebuild flag. // Plugin Stats/Metrics uint32_t next_counter_metric_id_ = static_cast(MetricType::Counter); @@ -360,8 +365,8 @@ class WasmHandleBase : public std::enable_shared_from_this { recover_vm_callback_ = std::move(f); } - // Recover the wasm vm and generate a new wasm handle - bool doRecover(std::shared_ptr &new_handle) { + // Rebuild the wasm vm and generate a new wasm handle + bool rebuild(std::shared_ptr &new_handle) { assert(new_handle == nullptr); if (recover_vm_callback_ == nullptr) { return true; @@ -414,18 +419,22 @@ class PluginHandleBase : public std::enable_shared_from_this { recover_plugin_callback_ = std::move(f); } - // Recover the wasm plugin and generate a new plugin handle - bool doRecover(std::shared_ptr &new_handle) { + // Rebuild the wasm plugin and generate a new plugin handle + bool rebuild(std::shared_ptr &new_handle) { assert(new_handle == nullptr); if (recover_plugin_callback_ == nullptr) { return true; } std::shared_ptr new_wasm_handle; - if (!wasm_handle_->doRecover(new_wasm_handle)) { + if (!wasm_handle_->rebuild(new_wasm_handle)) { + std::cerr << "wasmHandle rebuild failed" + << "\n"; return false; } new_handle = recover_plugin_callback_(new_wasm_handle); if (!new_handle) { + std::cerr << "pluginHandle rebuild failed" + << "\n"; return false; } return true; diff --git a/src/exports.cc b/src/exports.cc index 0c8837ec..7876cc7a 100644 --- a/src/exports.cc +++ b/src/exports.cc @@ -966,7 +966,7 @@ Word wasi_unstable_clock_time_get(Word clock_id, uint64_t /*precision*/, Word wasi_unstable_clock_res_get(Word clock_id, Word result_resolution_uint64_ptr) { uint64_t result = 0; auto *context = contextOrEffectiveContext(); - + switch (clock_id) { case 0 /* realtime */: case 1 /* monotonic */: @@ -978,65 +978,70 @@ Word wasi_unstable_clock_res_get(Word clock_id, Word result_resolution_uint64_pt // process_cputime_id and thread_cputime_id are not supported yet. return 58; // __WASI_ENOTSUP } - + if (!context->wasm()->setDatatype(result_resolution_uint64_ptr, result)) { return 21; // __WASI_EFAULT } return 0; // __WASI_ESUCCESS } -// __wasi_errno_t __wasi_fd_advise(__wasi_fd_t fd, __wasi_filesize_t offset, __wasi_filesize_t len, __wasi_advice_t advice); +// __wasi_errno_t __wasi_fd_advise(__wasi_fd_t fd, __wasi_filesize_t offset, __wasi_filesize_t len, +// __wasi_advice_t advice); Word wasi_unstable_fd_advise(Word fd, uint64_t offset, uint64_t len, Word advice) { - // fd_advise is used to provide advice about the expected behavior of the application with respect to a file. - // Since we don't have a real file system in proxy-wasm, we can just return success without doing anything. - // This is similar to how other file-related functions are implemented in this codebase. - - // We could check if fd is valid (e.g., stdout/stderr), but since this is just a hint and not required - // for correctness, we'll just return success for any fd. - + // fd_advise is used to provide advice about the expected behavior of the application with respect + // to a file. Since we don't have a real file system in proxy-wasm, we can just return success + // without doing anything. This is similar to how other file-related functions are implemented in + // this codebase. + + // We could check if fd is valid (e.g., stdout/stderr), but since this is just a hint and not + // required for correctness, we'll just return success for any fd. + return 0; // __WASI_ESUCCESS } -// __wasi_errno_t __wasi_fd_allocate(__wasi_fd_t fd, __wasi_filesize_t offset, __wasi_filesize_t len); +// __wasi_errno_t __wasi_fd_allocate(__wasi_fd_t fd, __wasi_filesize_t offset, __wasi_filesize_t +// len); Word wasi_unstable_fd_allocate(Word fd, uint64_t offset, uint64_t len) { // fd_allocate is used to ensure that space is allocated for a file. - // Since we don't have a real file system in proxy-wasm, we can just return success without doing anything. - // This is similar to how other file-related functions are implemented in this codebase. - + // Since we don't have a real file system in proxy-wasm, we can just return success without doing + // anything. This is similar to how other file-related functions are implemented in this codebase. + // We only support stdout and stderr in proxy-wasm, which don't need allocation if (fd != 1 /* stdout */ && fd != 2 /* stderr */) { return 8; // __WASI_ERRNO_BADF - Bad file descriptor } - + return 0; // __WASI_ESUCCESS } // __wasi_errno_t __wasi_fd_datasync(__wasi_fd_t fd); Word wasi_unstable_fd_datasync(Word fd) { // fd_datasync is used to synchronize the data of a file to disk. - // Since we don't have a real file system in proxy-wasm, we can just return success for stdout/stderr - // and an error for other file descriptors. - + // Since we don't have a real file system in proxy-wasm, we can just return success for + // stdout/stderr and an error for other file descriptors. + // We only support stdout and stderr in proxy-wasm if (fd != 1 /* stdout */ && fd != 2 /* stderr */) { return 8; // __WASI_ERRNO_BADF - Bad file descriptor } - + // For stdout and stderr, there's no need to sync as they're handled by the host system return 0; // __WASI_ESUCCESS } -// __wasi_errno_t __wasi_fd_fdstat_set_rights(__wasi_fd_t fd, __wasi_rights_t fs_rights_base, __wasi_rights_t fs_rights_inheriting); -Word wasi_unstable_fd_fdstat_set_rights(Word fd, uint64_t fs_rights_base, uint64_t fs_rights_inheriting) { +// __wasi_errno_t __wasi_fd_fdstat_set_rights(__wasi_fd_t fd, __wasi_rights_t fs_rights_base, +// __wasi_rights_t fs_rights_inheriting); +Word wasi_unstable_fd_fdstat_set_rights(Word fd, uint64_t fs_rights_base, + uint64_t fs_rights_inheriting) { // fd_fdstat_set_rights is used to adjust the rights associated with a file descriptor. - // Since we don't have a real file system in proxy-wasm, we can just return success for stdout/stderr - // and an error for other file descriptors. - + // Since we don't have a real file system in proxy-wasm, we can just return success for + // stdout/stderr and an error for other file descriptors. + // We only support stdout and stderr in proxy-wasm if (fd != 1 /* stdout */ && fd != 2 /* stderr */) { return 8; // __WASI_ERRNO_BADF - Bad file descriptor } - + // For stdout and stderr, we don't actually change any rights, but we can pretend it succeeded // This is similar to how other file-related functions are implemented in this codebase return 0; // __WASI_ESUCCESS @@ -1045,58 +1050,63 @@ Word wasi_unstable_fd_fdstat_set_rights(Word fd, uint64_t fs_rights_base, uint64 // __wasi_errno_t __wasi_fd_filestat_set_size(__wasi_fd_t fd, __wasi_filesize_t size); Word wasi_unstable_fd_filestat_set_size(Word fd, uint64_t size) { // fd_filestat_set_size is used to adjust the size of a file, similar to ftruncate. - // Since we don't have a real file system in proxy-wasm, we can just return success for stdout/stderr - // and an error for other file descriptors. - + // Since we don't have a real file system in proxy-wasm, we can just return success for + // stdout/stderr and an error for other file descriptors. + // We only support stdout and stderr in proxy-wasm if (fd != 1 /* stdout */ && fd != 2 /* stderr */) { return 8; // __WASI_ERRNO_BADF - Bad file descriptor } - + // For stdout and stderr, we don't actually change any size, but we can pretend it succeeded // This is similar to how other file-related functions are implemented in this codebase return 0; // __WASI_ESUCCESS } -// __wasi_errno_t __wasi_fd_filestat_set_times(__wasi_fd_t fd, __wasi_timestamp_t atim, __wasi_timestamp_t mtim, __wasi_fstflags_t fst_flags); +// __wasi_errno_t __wasi_fd_filestat_set_times(__wasi_fd_t fd, __wasi_timestamp_t atim, +// __wasi_timestamp_t mtim, __wasi_fstflags_t fst_flags); Word wasi_unstable_fd_filestat_set_times(Word fd, uint64_t atim, uint64_t mtim, Word fst_flags) { // fd_filestat_set_times is used to set the access and modification times of a file. - // Since we don't have a real file system in proxy-wasm, we can just return success for stdout/stderr - // and an error for other file descriptors. - + // Since we don't have a real file system in proxy-wasm, we can just return success for + // stdout/stderr and an error for other file descriptors. + // We only support stdout and stderr in proxy-wasm if (fd != 1 /* stdout */ && fd != 2 /* stderr */) { return 8; // __WASI_ERRNO_BADF - Bad file descriptor } - + // For stdout and stderr, we don't actually change any times, but we can pretend it succeeded // This is similar to how other file-related functions are implemented in this codebase return 0; // __WASI_ESUCCESS } -// __wasi_errno_t __wasi_fd_pread(__wasi_fd_t fd, const __wasi_iovec_t *iovs, size_t iovs_len, __wasi_filesize_t offset, __wasi_size_t *retptr0); -Word wasi_unstable_fd_pread(Word fd, Word iovs_ptr, Word iovs_len, uint64_t offset, Word nread_ptr) { +// __wasi_errno_t __wasi_fd_pread(__wasi_fd_t fd, const __wasi_iovec_t *iovs, size_t iovs_len, +// __wasi_filesize_t offset, __wasi_size_t *retptr0); +Word wasi_unstable_fd_pread(Word fd, Word iovs_ptr, Word iovs_len, uint64_t offset, + Word nread_ptr) { // fd_pread is used to read from a file descriptor at a given offset. // Since we don't have a real file system in proxy-wasm, we can just return an error. // This is similar to how fd_read is implemented in this codebase. - + // We don't support reading from any files in proxy-wasm return 52; // __WASI_ERRNO_ENOSYS - Function not implemented } -// __wasi_errno_t __wasi_fd_pwrite(__wasi_fd_t fd, const __wasi_ciovec_t *iovs, size_t iovs_len, __wasi_filesize_t offset, __wasi_size_t *retptr0); -Word wasi_unstable_fd_pwrite(Word fd, Word iovs_ptr, Word iovs_len, uint64_t offset, Word nwritten_ptr) { +// __wasi_errno_t __wasi_fd_pwrite(__wasi_fd_t fd, const __wasi_ciovec_t *iovs, size_t iovs_len, +// __wasi_filesize_t offset, __wasi_size_t *retptr0); +Word wasi_unstable_fd_pwrite(Word fd, Word iovs_ptr, Word iovs_len, uint64_t offset, + Word nwritten_ptr) { auto *context = contextOrEffectiveContext(); - + // fd_pwrite is used to write to a file descriptor at a given offset. // In proxy-wasm, we only support writing to stdout and stderr, and we don't support offsets. // We'll implement this similar to fd_write but return an error for non-stdout/stderr fds. - + // Check if fd is stdout or stderr if (fd != 1 /* stdout */ && fd != 2 /* stderr */) { return 8; // __WASI_ERRNO_BADF - Bad file descriptor } - + // For stdout and stderr, we'll just ignore the offset and write the data // This is similar to how fd_write is implemented in this codebase Word nwritten(0); @@ -1104,41 +1114,43 @@ Word wasi_unstable_fd_pwrite(Word fd, Word iovs_ptr, Word iovs_len, uint64_t off if (result != 0) { // __WASI_ESUCCESS return result; } - + if (!context->wasmVm()->setWord(nwritten_ptr, Word(nwritten))) { return 21; // __WASI_EFAULT } - + return 0; // __WASI_ESUCCESS } -// __wasi_errno_t __wasi_fd_readdir(__wasi_fd_t fd, uint8_t *buf, __wasi_size_t buf_len, __wasi_dircookie_t cookie, __wasi_size_t *retptr0); -Word wasi_unstable_fd_readdir(Word fd, Word buf_ptr, Word buf_len, uint64_t cookie, Word nread_ptr) { +// __wasi_errno_t __wasi_fd_readdir(__wasi_fd_t fd, uint8_t *buf, __wasi_size_t buf_len, +// __wasi_dircookie_t cookie, __wasi_size_t *retptr0); +Word wasi_unstable_fd_readdir(Word fd, Word buf_ptr, Word buf_len, uint64_t cookie, + Word nread_ptr) { auto *context = contextOrEffectiveContext(); - + // fd_readdir is used to read directory entries from a directory. // Since we don't have a real file system in proxy-wasm, we can just return an error. - + // Set the number of bytes read to 0 if (!context->wasmVm()->setWord(nread_ptr, Word(0))) { return 21; // __WASI_EFAULT } - + // Return ENOTDIR (Not a directory) error return 20; // __WASI_ENOTDIR } // __wasi_errno_t __wasi_fd_renumber(__wasi_fd_t fd, __wasi_fd_t to); Word wasi_unstable_fd_renumber(Word fd, Word to) { - // fd_renumber is used to atomically replace a file descriptor by renumbering another file descriptor. - // In proxy-wasm, we only support stdout and stderr, which are fixed file descriptors. - + // fd_renumber is used to atomically replace a file descriptor by renumbering another file + // descriptor. In proxy-wasm, we only support stdout and stderr, which are fixed file descriptors. + // Check if both file descriptors are valid (stdout or stderr) - if ((fd != 1 /* stdout */ && fd != 2 /* stderr */) || + if ((fd != 1 /* stdout */ && fd != 2 /* stderr */) || (to != 1 /* stdout */ && to != 2 /* stderr */)) { return 8; // __WASI_ERRNO_BADF - Bad file descriptor } - + // We don't actually support renumbering stdout and stderr, so return an error return 58; // __WASI_ENOTSUP - Not supported } @@ -1146,14 +1158,14 @@ Word wasi_unstable_fd_renumber(Word fd, Word to) { // __wasi_errno_t __wasi_fd_sync(__wasi_fd_t fd); Word wasi_unstable_fd_sync(Word fd) { // fd_sync is used to synchronize a file's in-core state with the storage device. - // Since we don't have a real file system in proxy-wasm, we can just return success for stdout/stderr - // and an error for other file descriptors. - + // Since we don't have a real file system in proxy-wasm, we can just return success for + // stdout/stderr and an error for other file descriptors. + // We only support stdout and stderr in proxy-wasm if (fd != 1 /* stdout */ && fd != 2 /* stderr */) { return 8; // __WASI_ERRNO_BADF - Bad file descriptor } - + // For stdout and stderr, there's no need to sync as they're handled by the host system return 0; // __WASI_ESUCCESS } @@ -1161,20 +1173,20 @@ Word wasi_unstable_fd_sync(Word fd) { // __wasi_errno_t __wasi_fd_tell(__wasi_fd_t fd, __wasi_filesize_t *retptr0); Word wasi_unstable_fd_tell(Word fd, Word retptr0) { auto *context = contextOrEffectiveContext(); - + // fd_tell is used to get the current offset of a file descriptor. // Since we don't have a real file system in proxy-wasm, we can just return an error. - + // We only support stdout and stderr in proxy-wasm, which don't support seeking if (fd != 1 /* stdout */ && fd != 2 /* stderr */) { return 8; // __WASI_ERRNO_BADF - Bad file descriptor } - + // For stdout and stderr, we'll just return 0 as the offset if (!context->wasm()->setDatatype(retptr0, uint64_t(0))) { return 21; // __WASI_EFAULT } - + return 0; // __WASI_ESUCCESS } @@ -1182,38 +1194,44 @@ Word wasi_unstable_fd_tell(Word fd, Word retptr0) { Word wasi_unstable_path_create_directory(Word fd, Word path_ptr, Word path_len) { // path_create_directory is used to create a directory. // Since we don't have a real file system in proxy-wasm, we can just return an error. - + return 58; // __WASI_ENOTSUP - Not supported } -// __wasi_errno_t __wasi_path_filestat_set_times(__wasi_fd_t fd, __wasi_lookupflags_t flags, const char *path, __wasi_timestamp_t atim, __wasi_timestamp_t mtim, __wasi_fstflags_t fst_flags); -Word wasi_unstable_path_filestat_set_times(Word fd, Word flags, Word path_ptr, Word path_len, uint64_t atim, uint64_t mtim, Word fst_flags) { +// __wasi_errno_t __wasi_path_filestat_set_times(__wasi_fd_t fd, __wasi_lookupflags_t flags, const +// char *path, __wasi_timestamp_t atim, __wasi_timestamp_t mtim, __wasi_fstflags_t fst_flags); +Word wasi_unstable_path_filestat_set_times(Word fd, Word flags, Word path_ptr, Word path_len, + uint64_t atim, uint64_t mtim, Word fst_flags) { // path_filestat_set_times is used to set the access and modification times of a file by path. // Since we don't have a real file system in proxy-wasm, we can just return an error. - + return 58; // __WASI_ENOTSUP - Not supported } -// __wasi_errno_t __wasi_path_link(__wasi_fd_t old_fd, __wasi_lookupflags_t old_flags, const char *old_path, __wasi_fd_t new_fd, const char *new_path); -Word wasi_unstable_path_link(Word old_fd, Word old_flags, Word old_path_ptr, Word old_path_len, Word new_fd, Word new_path_ptr) { +// __wasi_errno_t __wasi_path_link(__wasi_fd_t old_fd, __wasi_lookupflags_t old_flags, const char +// *old_path, __wasi_fd_t new_fd, const char *new_path); +Word wasi_unstable_path_link(Word old_fd, Word old_flags, Word old_path_ptr, Word old_path_len, + Word new_fd, Word new_path_ptr) { // path_link is used to create a hard link. // Since we don't have a real file system in proxy-wasm, we can just return an error. - + return 58; // __WASI_ENOTSUP - Not supported } -// __wasi_errno_t __wasi_path_readlink(__wasi_fd_t fd, const char *path, uint8_t *buf, __wasi_size_t buf_len, __wasi_size_t *retptr0); -Word wasi_unstable_path_readlink(Word fd, Word path_ptr, Word path_len, Word buf_ptr, Word buf_len, Word retptr0) { +// __wasi_errno_t __wasi_path_readlink(__wasi_fd_t fd, const char *path, uint8_t *buf, __wasi_size_t +// buf_len, __wasi_size_t *retptr0); +Word wasi_unstable_path_readlink(Word fd, Word path_ptr, Word path_len, Word buf_ptr, Word buf_len, + Word retptr0) { auto *context = contextOrEffectiveContext(); - + // path_readlink is used to read the contents of a symbolic link. // Since we don't have a real file system in proxy-wasm, we can just return an error. - + // Set the number of bytes read to 0 if (!context->wasmVm()->setWord(retptr0, Word(0))) { return 21; // __WASI_EFAULT } - + return 58; // __WASI_ENOTSUP - Not supported } @@ -1221,15 +1239,17 @@ Word wasi_unstable_path_readlink(Word fd, Word path_ptr, Word path_len, Word buf Word wasi_unstable_path_remove_directory(Word fd, Word path_ptr, Word path_len) { // path_remove_directory is used to remove a directory. // Since we don't have a real file system in proxy-wasm, we can just return an error. - + return 58; // __WASI_ENOTSUP - Not supported } -// __wasi_errno_t __wasi_path_rename(__wasi_fd_t fd, const char *old_path, __wasi_fd_t new_fd, const char *new_path); -Word wasi_unstable_path_rename(Word fd, Word old_path_ptr, Word old_path_len, Word new_fd, Word new_path_ptr) { +// __wasi_errno_t __wasi_path_rename(__wasi_fd_t fd, const char *old_path, __wasi_fd_t new_fd, const +// char *new_path); +Word wasi_unstable_path_rename(Word fd, Word old_path_ptr, Word old_path_len, Word new_fd, + Word new_path_ptr, Word new_path_len) { // path_rename is used to rename a file or directory. // Since we don't have a real file system in proxy-wasm, we can just return an error. - + return 58; // __WASI_ENOTSUP - Not supported } @@ -1237,7 +1257,7 @@ Word wasi_unstable_path_rename(Word fd, Word old_path_ptr, Word old_path_len, Wo Word wasi_unstable_path_symlink(Word old_path_ptr, Word old_path_len, Word fd, Word new_path_ptr) { // path_symlink is used to create a symbolic link. // Since we don't have a real file system in proxy-wasm, we can just return an error. - + return 58; // __WASI_ENOTSUP - Not supported } @@ -1245,57 +1265,61 @@ Word wasi_unstable_path_symlink(Word old_path_ptr, Word old_path_len, Word fd, W Word wasi_unstable_path_unlink_file(Word fd, Word path_ptr, Word path_len) { // path_unlink_file is used to unlink a file. // Since we don't have a real file system in proxy-wasm, we can just return an error. - + return 58; // __WASI_ENOTSUP - Not supported } // __wasi_errno_t __wasi_sock_accept(__wasi_fd_t fd, __wasi_fdflags_t flags, __wasi_fd_t *retptr0); Word wasi_unstable_sock_accept(Word fd, Word flags, Word retptr0) { auto *context = contextOrEffectiveContext(); - + // sock_accept is used to accept a new connection on a socket. // Since we don't have socket support in proxy-wasm, we can just return an error. - + // Set the returned file descriptor to an invalid value if (!context->wasm()->setDatatype(retptr0, uint32_t(0))) { return 21; // __WASI_EFAULT } - + return 58; // __WASI_ENOTSUP - Not supported } -// __wasi_errno_t __wasi_sock_recv(__wasi_fd_t fd, const __wasi_iovec_t *ri_data, size_t ri_data_len, __wasi_riflags_t ri_flags, __wasi_size_t *retptr0, __wasi_roflags_t *retptr1); -Word wasi_unstable_sock_recv(Word fd, Word ri_data_ptr, Word ri_data_len, Word ri_flags, Word retptr0, Word retptr1) { +// __wasi_errno_t __wasi_sock_recv(__wasi_fd_t fd, const __wasi_iovec_t *ri_data, size_t +// ri_data_len, __wasi_riflags_t ri_flags, __wasi_size_t *retptr0, __wasi_roflags_t *retptr1); +Word wasi_unstable_sock_recv(Word fd, Word ri_data_ptr, Word ri_data_len, Word ri_flags, + Word retptr0, Word retptr1) { auto *context = contextOrEffectiveContext(); - + // sock_recv is used to receive data from a socket. // Since we don't have socket support in proxy-wasm, we can just return an error. - + // Set the number of bytes received to 0 if (!context->wasmVm()->setWord(retptr0, Word(0))) { return 21; // __WASI_EFAULT } - + // Set the output flags to 0 if (!context->wasm()->setDatatype(retptr1, uint16_t(0))) { return 21; // __WASI_EFAULT } - + return 58; // __WASI_ENOTSUP - Not supported } -// __wasi_errno_t __wasi_sock_send(__wasi_fd_t fd, const __wasi_ciovec_t *si_data, size_t si_data_len, __wasi_siflags_t si_flags, __wasi_size_t *retptr0); -Word wasi_unstable_sock_send(Word fd, Word si_data_ptr, Word si_data_len, Word si_flags, Word retptr0) { +// __wasi_errno_t __wasi_sock_send(__wasi_fd_t fd, const __wasi_ciovec_t *si_data, size_t +// si_data_len, __wasi_siflags_t si_flags, __wasi_size_t *retptr0); +Word wasi_unstable_sock_send(Word fd, Word si_data_ptr, Word si_data_len, Word si_flags, + Word retptr0) { auto *context = contextOrEffectiveContext(); - + // sock_send is used to send data on a socket. // Since we don't have socket support in proxy-wasm, we can just return an error. - + // Set the number of bytes sent to 0 if (!context->wasmVm()->setWord(retptr0, Word(0))) { return 21; // __WASI_EFAULT } - + return 58; // __WASI_ENOTSUP - Not supported } @@ -1303,7 +1327,7 @@ Word wasi_unstable_sock_send(Word fd, Word si_data_ptr, Word si_data_len, Word s Word wasi_unstable_sock_shutdown(Word fd, Word how) { // sock_shutdown is used to shut down part of a full-duplex connection. // Since we don't have socket support in proxy-wasm, we can just return an error. - + return 58; // __WASI_ENOTSUP - Not supported } diff --git a/src/wasm.cc b/src/wasm.cc index 44dc988e..00fb171f 100644 --- a/src/wasm.cc +++ b/src/wasm.cc @@ -252,6 +252,7 @@ WasmBase::WasmBase(std::unique_ptr wasm_vm, std::string_view vm_id, } WasmBase::~WasmBase() { + clearWasmInContext(); root_contexts_.clear(); pending_done_.clear(); pending_delete_.clear(); @@ -400,54 +401,54 @@ ContextBase *WasmBase::getRootContext(const std::shared_ptr &plugin, void WasmBase::startVm(ContextBase *root_context) { // wasi_snapshot_preview1.clock_time_get wasm_vm_->setRestrictedCallback( - true, {// logging (Proxy-Wasm) - "env.proxy_log", - // logging (stdout/stderr) - "wasi_unstable.fd_write", "wasi_snapshot_preview1.fd_write", - // args - "wasi_unstable.args_sizes_get", "wasi_snapshot_preview1.args_sizes_get", - "wasi_unstable.args_get", "wasi_snapshot_preview1.args_get", - // environment variables - "wasi_unstable.environ_sizes_get", "wasi_snapshot_preview1.environ_sizes_get", - "wasi_unstable.environ_get", "wasi_snapshot_preview1.environ_get", - // preopened files/directories - "wasi_unstable.fd_prestat_get", "wasi_snapshot_preview1.fd_prestat_get", - "wasi_unstable.fd_prestat_dir_name", "wasi_snapshot_preview1.fd_prestat_dir_name", - // time - "wasi_unstable.clock_time_get", "wasi_snapshot_preview1.clock_time_get", - "wasi_unstable.clock_res_get", "wasi_snapshot_preview1.clock_res_get", - // random - "wasi_unstable.random_get", "wasi_snapshot_preview1.random_get", - // Go runtime initialization - "wasi_unstable.fd_fdstat_get", "wasi_snapshot_preview1.fd_fdstat_get", - "wasi_unstable.fd_fdstat_set_flags", "wasi_snapshot_preview1.fd_fdstat_set_flags", - "wasi_unstable.fd_fdstat_set_rights", "wasi_snapshot_preview1.fd_fdstat_set_rights", - "wasi_unstable.path_filestat_get", "wasi_snapshot_preview1.path_filestat_get", - "wasi_unstable.fd_filestat_get", "wasi_snapshot_preview1.fd_filestat_get", - "wasi_unstable.fd_filestat_set_size", "wasi_snapshot_preview1.fd_filestat_set_size", - "wasi_unstable.fd_filestat_set_times", "wasi_snapshot_preview1.fd_filestat_set_times", - "wasi_unstable.fd_advise", "wasi_snapshot_preview1.fd_advise", - "wasi_unstable.fd_allocate", "wasi_snapshot_preview1.fd_allocate", - "wasi_unstable.fd_datasync", "wasi_snapshot_preview1.fd_datasync", - "wasi_unstable.fd_pread", "wasi_snapshot_preview1.fd_pread", - "wasi_unstable.fd_pwrite", "wasi_snapshot_preview1.fd_pwrite", - "wasi_unstable.fd_readdir", "wasi_snapshot_preview1.fd_readdir", - "wasi_unstable.fd_renumber", "wasi_snapshot_preview1.fd_renumber", - "wasi_unstable.fd_sync", "wasi_snapshot_preview1.fd_sync", - "wasi_unstable.fd_tell", "wasi_snapshot_preview1.fd_tell", - "wasi_unstable.path_create_directory", "wasi_snapshot_preview1.path_create_directory", - "wasi_unstable.path_filestat_set_times", "wasi_snapshot_preview1.path_filestat_set_times", - "wasi_unstable.path_link", "wasi_snapshot_preview1.path_link", - "wasi_unstable.path_readlink", "wasi_snapshot_preview1.path_readlink", - "wasi_unstable.path_remove_directory", "wasi_snapshot_preview1.path_remove_directory", - "wasi_unstable.path_rename", "wasi_snapshot_preview1.path_rename", - "wasi_unstable.path_symlink", "wasi_snapshot_preview1.path_symlink", - "wasi_unstable.path_unlink_file", "wasi_snapshot_preview1.path_unlink_file", - "wasi_unstable.poll_oneoff", "wasi_snapshot_preview1.poll_oneoff", - "wasi_unstable.sock_accept", "wasi_snapshot_preview1.sock_accept", - "wasi_unstable.sock_recv", "wasi_snapshot_preview1.sock_recv", - "wasi_unstable.sock_send", "wasi_snapshot_preview1.sock_send", - "wasi_unstable.sock_shutdown", "wasi_snapshot_preview1.sock_shutdown"}); + true, + {// logging (Proxy-Wasm) + "env.proxy_log", + // logging (stdout/stderr) + "wasi_unstable.fd_write", "wasi_snapshot_preview1.fd_write", + // args + "wasi_unstable.args_sizes_get", "wasi_snapshot_preview1.args_sizes_get", + "wasi_unstable.args_get", "wasi_snapshot_preview1.args_get", + // environment variables + "wasi_unstable.environ_sizes_get", "wasi_snapshot_preview1.environ_sizes_get", + "wasi_unstable.environ_get", "wasi_snapshot_preview1.environ_get", + // preopened files/directories + "wasi_unstable.fd_prestat_get", "wasi_snapshot_preview1.fd_prestat_get", + "wasi_unstable.fd_prestat_dir_name", "wasi_snapshot_preview1.fd_prestat_dir_name", + // time + "wasi_unstable.clock_time_get", "wasi_snapshot_preview1.clock_time_get", + "wasi_unstable.clock_res_get", "wasi_snapshot_preview1.clock_res_get", + // random + "wasi_unstable.random_get", "wasi_snapshot_preview1.random_get", + // Go runtime initialization + "wasi_unstable.fd_fdstat_get", "wasi_snapshot_preview1.fd_fdstat_get", + "wasi_unstable.fd_fdstat_set_flags", "wasi_snapshot_preview1.fd_fdstat_set_flags", + "wasi_unstable.fd_fdstat_set_rights", "wasi_snapshot_preview1.fd_fdstat_set_rights", + "wasi_unstable.path_filestat_get", "wasi_snapshot_preview1.path_filestat_get", + "wasi_unstable.fd_filestat_get", "wasi_snapshot_preview1.fd_filestat_get", + "wasi_unstable.fd_filestat_set_size", "wasi_snapshot_preview1.fd_filestat_set_size", + "wasi_unstable.fd_filestat_set_times", "wasi_snapshot_preview1.fd_filestat_set_times", + "wasi_unstable.fd_advise", "wasi_snapshot_preview1.fd_advise", "wasi_unstable.fd_allocate", + "wasi_snapshot_preview1.fd_allocate", "wasi_unstable.fd_datasync", + "wasi_snapshot_preview1.fd_datasync", "wasi_unstable.fd_pread", + "wasi_snapshot_preview1.fd_pread", "wasi_unstable.fd_pwrite", + "wasi_snapshot_preview1.fd_pwrite", "wasi_unstable.fd_readdir", + "wasi_snapshot_preview1.fd_readdir", "wasi_unstable.fd_renumber", + "wasi_snapshot_preview1.fd_renumber", "wasi_unstable.fd_sync", + "wasi_snapshot_preview1.fd_sync", "wasi_unstable.fd_tell", "wasi_snapshot_preview1.fd_tell", + "wasi_unstable.path_create_directory", "wasi_snapshot_preview1.path_create_directory", + "wasi_unstable.path_filestat_set_times", "wasi_snapshot_preview1.path_filestat_set_times", + "wasi_unstable.path_link", "wasi_snapshot_preview1.path_link", "wasi_unstable.path_readlink", + "wasi_snapshot_preview1.path_readlink", "wasi_unstable.path_remove_directory", + "wasi_snapshot_preview1.path_remove_directory", "wasi_unstable.path_rename", + "wasi_snapshot_preview1.path_rename", "wasi_unstable.path_symlink", + "wasi_snapshot_preview1.path_symlink", "wasi_unstable.path_unlink_file", + "wasi_snapshot_preview1.path_unlink_file", "wasi_unstable.poll_oneoff", + "wasi_snapshot_preview1.poll_oneoff", "wasi_unstable.sock_accept", + "wasi_snapshot_preview1.sock_accept", "wasi_unstable.sock_recv", + "wasi_snapshot_preview1.sock_recv", "wasi_unstable.sock_send", + "wasi_snapshot_preview1.sock_send", "wasi_unstable.sock_shutdown", + "wasi_snapshot_preview1.sock_shutdown"}); if (_initialize_) { // WASI reactor. _initialize_(root_context); @@ -655,35 +656,42 @@ void setWasmRecoverCallback(const std::string &vm_key, clone_factory]() -> std::shared_ptr { const auto base_handle = base_handle_for_copy.lock(); if (!base_handle) { - std::cerr << "Failed to get base_handle shared_ptr in setRecoverVmCallback" << std::endl; + std::cerr << "Failed to get base_handle shared_ptr in setRecoverVmCallback" + << "\n"; return nullptr; } const auto &integration = base_handle->wasm()->wasm_vm()->integration(); integration->trace("Start recover wasm_handle"); + + // Check if this is a proactive rebuild (shouldRebuild flag is set) + auto old_wasm_handle = wasm_handle_for_copy.lock(); + bool is_proactive_rebuild = (old_wasm_handle && old_wasm_handle->wasm()->shouldRebuild()); + auto it = local_wasms.find(vm_key); if (it != local_wasms.end()) { auto wasm_handle = it->second.lock(); - if (wasm_handle) { - integration->trace("Wasm handle already exists"); + if (wasm_handle && !is_proactive_rebuild) { + integration->trace("Wasm handle already exists, reuse for fail recovery"); return wasm_handle; } + // For proactive rebuild, force erase the cache to create new instance + integration->trace("Proactive rebuild: erase existing cache"); local_wasms.erase(vm_key); } removeStaleLocalCacheEntries(local_wasms, local_wasms_keys); - auto old_wasm_handle = wasm_handle_for_copy.lock(); - if (old_wasm_handle) { - // avoid the context use the stale wasm ptr - old_wasm_handle->wasm()->clearWasmInContext(); - } // Try to recover wasm vm auto new_handle = clone_factory(base_handle); if (!new_handle) { + std::cerr << "Failed to clone Base Wasm during recover" + << "\n"; base_handle->wasm()->fail(FailState::RecoverError, "Failed to clone Base Wasm during recover"); return nullptr; } if (!new_handle->wasm()->initialize()) { + std::cerr << "Failed to initialize Wasm code during recover" + << "\n"; base_handle->wasm()->fail(FailState::RecoverError, "Failed to initialize Wasm code during recover"); return nullptr; @@ -752,7 +760,7 @@ void setPluginRecoverCallback(const std::string &key, const auto base_handle = base_handle_for_copy.lock(); if (!base_handle) { std::cerr << "Failed to get base_handle shared_ptr in setRecoverPluginCallback" - << std::endl; + << "\n"; return nullptr; } const auto &integration = base_handle->wasm()->wasm_vm()->integration(); @@ -760,20 +768,31 @@ void setPluginRecoverCallback(const std::string &key, auto it = local_plugins.find(key); if (it != local_plugins.end()) { auto plugin_handle = it->second.lock(); - if (plugin_handle) { + // Check if the associated wasm needs rebuild + bool should_rebuild = (plugin_handle && plugin_handle->wasmHandle() && + plugin_handle->wasmHandle()->wasm() && + plugin_handle->wasmHandle()->wasm()->shouldRebuild()); + if (plugin_handle && !should_rebuild) { + integration->trace("Plugin handle already exists, reuse for fail recovery"); return plugin_handle; } + // For proactive rebuild, force erase the cache to create new instance + integration->trace("Proactive rebuild: erase existing plugin cache"); local_plugins.erase(key); } removeStaleLocalCacheEntries(local_plugins, local_plugins_keys); // Try to recover wasm plugin auto *plugin_context = wasm_handle->wasm()->start(plugin); if (plugin_context == nullptr) { + std::cerr << "Failed to start thread-local Wasm during recover" + << "\n"; base_handle->wasm()->fail(FailState::RecoverError, "Failed to start thread-local Wasm during recover"); return nullptr; } if (!wasm_handle->wasm()->configure(plugin_context, plugin)) { + std::cerr << "Failed to configure thread-local Wasm plugin during recover" + << "\n"; base_handle->wasm()->fail(FailState::RecoverError, "Failed to configure thread-local Wasm plugin during recover"); return nullptr; diff --git a/test/wasm_test.cc b/test/wasm_test.cc index 8410a42b..342dc4c5 100644 --- a/test/wasm_test.cc +++ b/test/wasm_test.cc @@ -170,7 +170,7 @@ TEST_P(TestVm, RecoverCrashedThreadLocalWasm) { // do recover. std::shared_ptr new_plugin_handle; - ASSERT_TRUE(plugin_handle->doRecover(new_plugin_handle)); + ASSERT_TRUE(plugin_handle->rebuild(new_plugin_handle)); // Verify recover success. ASSERT_FALSE(new_plugin_handle->wasm()->isFailed()); // Verify the pointer to WasmBase is different from the crashed one. @@ -181,7 +181,7 @@ TEST_P(TestVm, RecoverCrashedThreadLocalWasm) { ASSERT_TRUE(new_plugin_handle->wasm()->isFailed()); // Do recover again. std::shared_ptr new_plugin_handle2; - ASSERT_TRUE(new_plugin_handle->doRecover(new_plugin_handle2)); + ASSERT_TRUE(new_plugin_handle->rebuild(new_plugin_handle2)); // Verify recover again success. ASSERT_FALSE(new_plugin_handle2->wasm()->isFailed()); // Verify the pointer to WasmBase is different from the crashed one. @@ -213,7 +213,7 @@ TEST_P(TestVm, RecoverCrashedThreadLocalWasm) { ASSERT_NE(another_handle2->wasm(), new_plugin_handle2->wasm()); // Do recover again. std::shared_ptr new_plugin_handle3; - ASSERT_TRUE(new_plugin_handle2->doRecover(new_plugin_handle3)); + ASSERT_TRUE(new_plugin_handle2->rebuild(new_plugin_handle3)); // Verify the pointer to WasmBase is different from the crashed one. ASSERT_NE(new_plugin_handle3->wasm(), new_plugin_handle2->wasm()); @@ -222,7 +222,7 @@ TEST_P(TestVm, RecoverCrashedThreadLocalWasm) { ASSERT_TRUE(another_handle2->wasm()->isFailed()); // Do recover again std::shared_ptr new_another_handle2; - ASSERT_TRUE(another_handle2->doRecover(new_another_handle2)); + ASSERT_TRUE(another_handle2->rebuild(new_another_handle2)); // Verify the pointer to WasmBase is different from the crashed one. ASSERT_NE(new_another_handle2->wasm(), another_handle2->wasm()); @@ -238,7 +238,7 @@ TEST_P(TestVm, RecoverCrashedThreadLocalWasm) { ASSERT_NE(another_handle3->wasm(), new_another_handle2->wasm()); // Do recover again. std::shared_ptr new_another_handle3; - ASSERT_TRUE(new_another_handle2->doRecover(new_another_handle3)); + ASSERT_TRUE(new_another_handle2->rebuild(new_another_handle3)); // Recover should reuse the plugin handle ASSERT_EQ(new_another_handle3, another_handle3); }