Implement save state serialization for WASI file descriptors in libretro builds

This commit is contained in:
刘皓 2025-05-23 23:59:29 -04:00
parent 057b6dc95d
commit e957af931c
No known key found for this signature in database
GPG key ID: 7901753DB465B711
5 changed files with 57 additions and 7 deletions

View file

@ -125,6 +125,10 @@ sandbox::~sandbox() {
wasm2c_ruby_free(RB); wasm2c_ruby_free(RB);
} }
bool sandbox::sandbox_serialize_fdtable(void *&data, wasm_size_t &max_size) const {
return wasi->sandbox_serialize(data, max_size);
}
Movie *sandbox::get_movie_from_main_thread() { Movie *sandbox::get_movie_from_main_thread() {
return movie.load(std::memory_order_relaxed); // No need for synchronization because we always set the movie from the main thread return movie.load(std::memory_order_relaxed); // No need for synchronization because we always set the movie from the main thread
} }

View file

@ -63,6 +63,7 @@ namespace mkxp_sandbox {
inline struct mkxp_sandbox::bindings *operator->() noexcept { return &*bindings; } inline struct mkxp_sandbox::bindings *operator->() noexcept { return &*bindings; }
sandbox(); sandbox();
~sandbox(); ~sandbox();
bool sandbox_serialize_fdtable(void *&data, wasm_size_t &max_size) const;
Movie *get_movie_from_main_thread(); Movie *get_movie_from_main_thread();
Movie *get_movie_from_audio_thread(); Movie *get_movie_from_audio_thread();
void set_movie(Movie *new_movie); void set_movie(Movie *new_movie);

View file

@ -28,6 +28,7 @@
#include "core.h" #include "core.h"
#include "wasi.h" #include "wasi.h"
#include "binding-base.h" #include "binding-base.h"
#include "sandbox-serial-util.h"
using namespace mkxp_sandbox; using namespace mkxp_sandbox;
@ -36,11 +37,11 @@ static inline size_t strlen_safe(const char *str, size_t max_length) {
return ptr == nullptr ? max_length : ptr - str; return ptr == nullptr ? max_length : ptr - str;
} }
struct fs_dir *wasi_file_entry::dir_handle() { struct fs_dir *wasi_file_entry::dir_handle() const noexcept {
return (struct fs_dir *)handle; return (struct fs_dir *)handle;
} }
struct FileSystem::File *wasi_file_entry::file_handle() { struct FileSystem::File *wasi_file_entry::file_handle() const noexcept {
return (struct FileSystem::File *)handle; return (struct FileSystem::File *)handle;
} }
@ -128,6 +129,42 @@ const char *wasi_t::str(wasm_ptr_t address) const noexcept {
return sandbox_str(*ruby, address); return sandbox_str(*ruby, address);
} }
bool wasi_t::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const {
if (!::sandbox_serialize((wasm_size_t)fdtable.size(), data, max_size)) return false;
wasm_size_t num_free_handles = 0;
for (const struct wasi_file_entry &entry : fdtable) {
if (entry.type == wasi_fd_type::FSDIR) {
if (num_free_handles > 0) {
if (!::sandbox_serialize((uint8_t)0, data, max_size)) return false;
if (!::sandbox_serialize(num_free_handles, data, max_size)) return false;
num_free_handles = 0;
}
if (!::sandbox_serialize((uint8_t)1, data, max_size)) return false;
if (!::sandbox_serialize(entry.dir_handle()->path, data, max_size)) return false;
if (!::sandbox_serialize(entry.dir_handle()->root->path, data, max_size)) return false;
} else if (entry.type == wasi_fd_type::FSFILE) {
if (num_free_handles > 0) {
if (!::sandbox_serialize((uint8_t)0, data, max_size)) return false;
if (!::sandbox_serialize(num_free_handles, data, max_size)) return false;
num_free_handles = 0;
}
if (!::sandbox_serialize((uint8_t)2, data, max_size)) return false;
if (!::sandbox_serialize(entry.file_handle()->path(), data, max_size)) return false;
} else {
++num_free_handles;
}
}
if (num_free_handles > 0) {
if (!::sandbox_serialize((uint8_t)0, data, max_size)) return false;
if (!::sandbox_serialize(num_free_handles, data, max_size)) return false;
num_free_handles = 0;
}
return true;
}
extern "C" uint32_t w2c_wasi__snapshot__preview1_args_get(wasi_t *wasi, wasm_ptr_t argv, wasm_ptr_t argv_buf) { extern "C" uint32_t w2c_wasi__snapshot__preview1_args_get(wasi_t *wasi, wasm_ptr_t argv, wasm_ptr_t argv_buf) {
return WASI_ESUCCESS; return WASI_ESUCCESS;
} }

View file

@ -181,8 +181,8 @@ struct wasi_file_entry {
// The file/directory handle that the file descriptor corresponds to. The exact type of this handle depends on the type of file descriptor. // The file/directory handle that the file descriptor corresponds to. The exact type of this handle depends on the type of file descriptor.
void *handle; void *handle;
struct fs_dir *dir_handle(); struct fs_dir *dir_handle() const noexcept;
struct FileSystem::File *file_handle(); struct FileSystem::File *file_handle() const noexcept;
}; };
typedef struct w2c_wasi__snapshot__preview1 { typedef struct w2c_wasi__snapshot__preview1 {
@ -230,6 +230,8 @@ typedef struct w2c_wasi__snapshot__preview1 {
template <typename T> void arycpy(mkxp_sandbox::wasm_ptr_t dst_address, const T *src, mkxp_sandbox::wasm_size_t num_elements) const noexcept { template <typename T> void arycpy(mkxp_sandbox::wasm_ptr_t dst_address, const T *src, mkxp_sandbox::wasm_size_t num_elements) const noexcept {
mkxp_sandbox::sandbox_arycpy(*ruby, dst_address, src, num_elements); mkxp_sandbox::sandbox_arycpy(*ruby, dst_address, src, num_elements);
} }
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const;
} wasi_t; } wasi_t;
#endif /* MKXPZ_SANDBOX_WASI_H */ #endif /* MKXPZ_SANDBOX_WASI_H */

View file

@ -1639,10 +1639,12 @@ extern "C" RETRO_API bool retro_serialize(void *data, size_t len) {
if (!Graphics::sandbox_serialize_movie(sb().get_movie_from_main_thread(), data, max_size)) return false; if (!Graphics::sandbox_serialize_movie(sb().get_movie_from_main_thread(), data, max_size)) return false;
} }
// TODO: write the file descriptor table // Write the open WASI file descriptors
if (!sb().sandbox_serialize_fdtable(data, max_size)) return false;
// Write each object // Write the number of objects, then each object
OBJECTS_BEGIN; OBJECTS_BEGIN;
if (!sandbox_serialize((wasm_size_t)sb()->get_objects().size(), data, max_size)) OBJECTS_END_FAIL;
wasm_size_t num_free_objects = 0; wasm_size_t num_free_objects = 0;
for (const auto &object : sb()->get_objects()) { for (const auto &object : sb()->get_objects()) {
if (object.typenum == 0) { if (object.typenum == 0) {
@ -1665,7 +1667,10 @@ extern "C" RETRO_API bool retro_serialize(void *data, size_t len) {
num_free_objects = 0; num_free_objects = 0;
} }
// Write each extra object that was found during serialization of the normal objects // Write the number of extra objects that were found during serialization of the normal objects, then each such object
if (max_size < sizeof(wasm_size_t)) OBJECTS_END_FAIL;
wasm_size_t *num_extra_objects_ptr = (wasm_size_t *)data;
ADVANCE(sizeof(wasm_size_t));
for (size_t i = 0; i < extra_objects.size(); ++i) { // More items can be added to this vector during iteration for (size_t i = 0; i < extra_objects.size(); ++i) { // More items can be added to this vector during iteration
const void *ptr = std::get<0>(extra_objects[i]); const void *ptr = std::get<0>(extra_objects[i]);
wasm_size_t typenum = std::get<1>(extra_objects[i]); wasm_size_t typenum = std::get<1>(extra_objects[i]);
@ -1683,6 +1688,7 @@ extern "C" RETRO_API bool retro_serialize(void *data, size_t len) {
if (!sandbox_serialize(num_free_objects, data, max_size)) OBJECTS_END_FAIL; if (!sandbox_serialize(num_free_objects, data, max_size)) OBJECTS_END_FAIL;
num_free_objects = 0; num_free_objects = 0;
} }
*num_extra_objects_ptr = (wasm_size_t)extra_objects.size();
OBJECTS_END; OBJECTS_END;
std::memset(data, 0, max_size); std::memset(data, 0, max_size);