mirror of
https://github.com/mkxp-z/mkxp-z.git
synced 2025-08-23 15:23:44 +02:00
179 lines
7.8 KiB
C
179 lines
7.8 KiB
C
/*
|
|
** ruby-bindings.h
|
|
**
|
|
** This file is part of mkxp.
|
|
**
|
|
** Copyright (C) 2013 - 2021 Amaryllis Kulla <ancurio@mapleshrine.eu>
|
|
**
|
|
** mkxp is free software: you can redistribute it and/or modify
|
|
** it under the terms of the GNU General Public License as published by
|
|
** the Free Software Foundation, either version 2 of the License, or
|
|
** (at your option) any later version.
|
|
**
|
|
** mkxp is distributed in the hope that it will be useful,
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
** GNU General Public License for more details.
|
|
**
|
|
** You should have received a copy of the GNU General Public License
|
|
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/* This file contains bindings that expose low-level functionality of the Ruby VM to the outside of the sandbox it's running in. They are used by sandbox-bindgen. */
|
|
|
|
#ifndef SANDBOX_RUBY_BINDINGS_H
|
|
#define SANDBOX_RUBY_BINDINGS_H
|
|
|
|
#include <limits.h>
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include "wasm/asyncify.h"
|
|
#include "wasm/fiber.h"
|
|
#include "wasm/machine.h"
|
|
#include "wasm/setjmp.h"
|
|
|
|
#define MKXP_SANDBOX_API __attribute__((__visibility__("default")))
|
|
|
|
MKXP_SANDBOX_API struct __rb_wasm_asyncify_jmp_buf mkxp_sandbox_async_buf;
|
|
MKXP_SANDBOX_API void (*mkxp_sandbox_fiber_entry_point)(void *, void *) = NULL;
|
|
MKXP_SANDBOX_API void *mkxp_sandbox_fiber_arg0 = NULL;
|
|
MKXP_SANDBOX_API void *mkxp_sandbox_fiber_arg1 = NULL;
|
|
MKXP_SANDBOX_API char mkxp_sandbox_cwd[PATH_MAX] = {0};
|
|
|
|
/* This function should be called immediately after initializing the sandbox to perform initialization, before calling any other functions.
|
|
* The arguments to this function are the Ruby GC parameters.
|
|
* Each one can be set to 0 to leave the corresponding GC parameters at the default value, or to anything else to set the parameter to the given value. */
|
|
MKXP_SANDBOX_API void mkxp_sandbox_init(size_t heap_free_slots, double growth_factor, size_t growth_max_slots, double heap_free_slots_min_ratio, double heap_free_slots_goal_ratio, double heap_free_slots_max_ratio, double uncollectible_wb_unprotected_objects_limit_ratio, double oldobject_limit_factor, size_t malloc_limit_min, size_t malloc_limit_max, double malloc_limit_growth_factor, size_t oldmalloc_limit_min, size_t oldmalloc_limit_max, double oldmalloc_limit_growth_factor) {
|
|
void __wasm_call_ctors(void); /* Defined by the LLVM linker */
|
|
__wasm_call_ctors();
|
|
|
|
void async_buf_init(struct __rb_wasm_asyncify_jmp_buf *); /* Defined in wasm/setjmp.c in Ruby source code */
|
|
async_buf_init(&mkxp_sandbox_async_buf);
|
|
|
|
if (heap_free_slots != 0) gc_params.heap_free_slots = heap_free_slots;
|
|
if (growth_factor != 0) gc_params.growth_factor = growth_factor;
|
|
if (growth_max_slots != 0) gc_params.growth_max_slots = growth_max_slots;
|
|
if (heap_free_slots_min_ratio != 0) gc_params.heap_free_slots_min_ratio = heap_free_slots_min_ratio;
|
|
if (heap_free_slots_goal_ratio != 0) gc_params.heap_free_slots_goal_ratio = heap_free_slots_goal_ratio;
|
|
if (heap_free_slots_max_ratio != 0) gc_params.heap_free_slots_max_ratio = heap_free_slots_max_ratio;
|
|
if (uncollectible_wb_unprotected_objects_limit_ratio != 0) gc_params.uncollectible_wb_unprotected_objects_limit_ratio = uncollectible_wb_unprotected_objects_limit_ratio;
|
|
if (oldobject_limit_factor != 0) gc_params.oldobject_limit_factor = oldobject_limit_factor;
|
|
if (malloc_limit_min != 0) gc_params.malloc_limit_min = malloc_limit_min;
|
|
if (malloc_limit_max != 0) gc_params.malloc_limit_max = malloc_limit_max;
|
|
if (malloc_limit_growth_factor != 0) gc_params.malloc_limit_growth_factor = malloc_limit_growth_factor;
|
|
if (oldmalloc_limit_min != 0) gc_params.oldmalloc_limit_min = oldmalloc_limit_min;
|
|
if (oldmalloc_limit_max != 0) gc_params.oldmalloc_limit_max = oldmalloc_limit_max;
|
|
if (oldmalloc_limit_growth_factor != 0) gc_params.oldmalloc_limit_growth_factor = oldmalloc_limit_growth_factor;
|
|
}
|
|
|
|
/* Exposes the `malloc()` function. */
|
|
MKXP_SANDBOX_API void *mkxp_sandbox_malloc(size_t size) {
|
|
return malloc(size);
|
|
}
|
|
|
|
/* Exposes the `free()` function. */
|
|
MKXP_SANDBOX_API void mkxp_sandbox_free(void *ptr) {
|
|
free(ptr);
|
|
}
|
|
|
|
/* The offset of the `data` field within a `struct RTypedData`. */
|
|
MKXP_SANDBOX_API size_t mkxp_sandbox_rtypeddata_data_offset = offsetof(struct RTypedData, data);
|
|
|
|
/* Calls the `dmark()` function from a `struct RTypedData *` on a given memory location. */
|
|
MKXP_SANDBOX_API void mkxp_sandbox_rtypeddata_dmark(struct RTypedData *data, void *ptr) {
|
|
if (data->type->function.dmark != NULL) {
|
|
data->type->function.dmark(ptr);
|
|
}
|
|
}
|
|
|
|
/* Calls the `dfree()` function from a `struct RTypedData *` on a given memory location. */
|
|
MKXP_SANDBOX_API void mkxp_sandbox_rtypeddata_dfree(struct RTypedData *data, void *ptr) {
|
|
if (data->type->function.dfree != NULL) {
|
|
data->type->function.dfree(ptr);
|
|
}
|
|
}
|
|
|
|
/* Calls the `dsize()` function from a `struct RTypedData *` on a given memory location. */
|
|
MKXP_SANDBOX_API size_t mkxp_sandbox_rtypeddata_dsize(struct RTypedData *data, const void *ptr) {
|
|
if (data->type->function.dsize != NULL) {
|
|
return data->type->function.dsize(ptr);
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* Calls the `dcompact()` function from a `struct RTypedData *` on a given memory location. */
|
|
MKXP_SANDBOX_API void mkxp_sandbox_rtypeddata_dcompact(struct RTypedData *data, void *ptr) {
|
|
if (data->type->function.dcompact != NULL) {
|
|
data->type->function.dcompact(ptr);
|
|
}
|
|
}
|
|
|
|
/* Calls `chdir()` and returns whether or not the call succeeded. */
|
|
MKXP_SANDBOX_API bool mkxp_sandbox_chdir(const char *path) {
|
|
return chdir(path) == 0;
|
|
}
|
|
|
|
/* Calls `getcwd()` on `mkxp_sandbox_cwd` and returns whether or not the call succeeded. */
|
|
MKXP_SANDBOX_API bool mkxp_sandbox_getcwd(void) {
|
|
return getcwd(mkxp_sandbox_cwd, PATH_MAX) != NULL;
|
|
}
|
|
|
|
/* This function drives Ruby's asynchronous runtime. It's based on the `rb_wasm_rt_start()` function from wasm/runtime.c in the Ruby source code.
|
|
* After calling any function that starts with `rb_` or `ruby_` other than `ruby_sysinit()`, you need to call `mkxp_sandbox_yield()`.
|
|
* If `mkxp_sandbox_yield()` returns false, you may proceed as usual.
|
|
* However, if it returns true, then you need to call the `rb_`/`ruby_` function again with the same arguments
|
|
* and then call `mkxp_sandbox_yield()` again, and repeat until `mkxp_sandbox_yield()` returns false. */
|
|
MKXP_SANDBOX_API bool mkxp_sandbox_yield(void) {
|
|
static bool new_fiber_started = false;
|
|
|
|
void *asyncify_buf;
|
|
bool unwound = false;
|
|
|
|
extern void *rb_asyncify_unwind_buf; /* Defined in wasm/setjmp.c in Ruby source code */
|
|
|
|
while (1) {
|
|
if (unwound) {
|
|
if (mkxp_sandbox_fiber_entry_point != NULL) {
|
|
mkxp_sandbox_fiber_entry_point(mkxp_sandbox_fiber_arg0, mkxp_sandbox_fiber_arg1);
|
|
} else {
|
|
return true;
|
|
}
|
|
} else {
|
|
unwound = true;
|
|
}
|
|
|
|
if (rb_asyncify_unwind_buf == NULL) {
|
|
break;
|
|
}
|
|
|
|
asyncify_stop_unwind();
|
|
|
|
if ((asyncify_buf = rb_wasm_handle_jmp_unwind()) != NULL) {
|
|
asyncify_start_rewind(asyncify_buf);
|
|
continue;
|
|
}
|
|
if ((asyncify_buf = rb_wasm_handle_scan_unwind()) != NULL) {
|
|
asyncify_start_rewind(asyncify_buf);
|
|
continue;
|
|
}
|
|
|
|
asyncify_buf = rb_wasm_handle_fiber_unwind(&mkxp_sandbox_fiber_entry_point, &mkxp_sandbox_fiber_arg0, &mkxp_sandbox_fiber_arg1, &new_fiber_started);
|
|
if (asyncify_buf != NULL) {
|
|
asyncify_start_rewind(asyncify_buf);
|
|
continue;
|
|
} else if (new_fiber_started) {
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
mkxp_sandbox_fiber_entry_point = NULL;
|
|
new_fiber_started = false;
|
|
return false;
|
|
}
|
|
|
|
#endif /* SANDBOX_RUBY_BINDINGS_H */
|