fix: harden wasm w7 entrypoint paths

This commit is contained in:
udo
2026-06-13 22:08:52 +00:00
parent d6421cb8f3
commit af6500d134
6 changed files with 71 additions and 15 deletions
+11 -4
View File
@@ -860,7 +860,14 @@ int handle_cli_complete(FastCGIRequest& request)
// wasm worker (whose traps are signal-based) can run directly.
String cli_unit = compiler_normalize_unit_path(&request, script_filename);
if(wasm_backend_should_handle(request, cli_unit))
wasm_backend_serve(request, cli_unit, wasm_kind::CLI);
{
String wasm_error = wasm_backend_serve(request, cli_unit, wasm_kind::CLI);
if(wasm_error != "")
{
request.set_status(500, "Internal Server Error");
print("UCE CLI wasm error: ", wasm_error, "\n");
}
}
else
compiler_invoke_cli(&request, script_filename);
}
@@ -976,9 +983,9 @@ int handle_complete(FastCGIRequest& request) {
else if(request.params["UCE_SERVE_HTTP"] == "1")
// W7c pending: the custom-server dispatcher is forked from a worker
// that already holds a live Wasmtime engine, so re-creating an engine
// in that child is unsafe (engine must not cross fork). The fix is to
// have the broker forward to the worker pool rather than render in the
// fork; until then serve_http renders natively.
// in that child currently hangs under the in-process dispatcher path.
// The fix is to have the broker forward to the worker pool rather than
// render in the fork; until then serve_http renders natively.
compiler_invoke_serve_http(&request, request.params["SCRIPT_FILENAME"], request.params["UCE_SERVE_HTTP_FUNCTION"]);
else if(wasm_backend_should_handle(request, entry_unit))
serve_via_wasm(entry_unit, wasm_kind::RENDER);
+14 -8
View File
@@ -22,7 +22,7 @@
// per forked worker process: one engine + compiled-core cache, one epoch ticker
static WasmWorker* g_wasm_worker = 0;
static std::thread g_wasm_epoch_ticker;
static std::thread* g_wasm_epoch_ticker = 0;
static std::atomic<bool> g_wasm_epoch_running(false);
static String g_wasm_init_error;
static bool g_wasm_init_attempted = false;
@@ -70,7 +70,7 @@ static String wasm_backend_ensure_started(Request* context)
g_wasm_epoch_running.store(true);
WasmWorker* worker = g_wasm_worker;
u64 period_ms = config_u64("WASM_EPOCH_PERIOD_MS", 50);
g_wasm_epoch_ticker = std::thread([worker, period_ms] {
g_wasm_epoch_ticker = new std::thread([worker, period_ms] {
while(g_wasm_epoch_running.load())
{
std::this_thread::sleep_for(std::chrono::milliseconds(period_ms));
@@ -249,8 +249,14 @@ String wasm_backend_serve(Request& request, const String& entry_unit, int32_t ki
// are usually killed, but a clean ager-out path should join the thread).
void wasm_backend_shutdown()
{
if(g_wasm_epoch_running.exchange(false) && g_wasm_epoch_ticker.joinable())
g_wasm_epoch_ticker.join();
if(g_wasm_epoch_ticker)
{
g_wasm_epoch_running.store(false);
if(g_wasm_epoch_ticker->joinable())
g_wasm_epoch_ticker->join();
delete g_wasm_epoch_ticker;
g_wasm_epoch_ticker = 0;
}
}
// A connection-broker child (the custom-server HTTP dispatcher, the websocket
@@ -260,14 +266,14 @@ void wasm_backend_shutdown()
// the ticker is a phantom and the engine state is unsafe. Reset the per-process
// statics so the child lazily initializes its own engine + ticker on first use.
// The inherited std::thread refers to a thread that does not exist in the child;
// placement-new it back to a default (non-joinable) state so the eventual
// re-assignment in ensure_started does not std::terminate on a "joinable" object,
// and so no join/detach touches the dead handle.
// discard the inherited pointer without touching the pointed-to object. Joining,
// deleting, or destroying a joinable std::thread after fork can terminate the
// child; the child will allocate its own ticker on first wasm use.
void wasm_backend_reset_after_fork()
{
g_wasm_worker = 0;
g_wasm_init_attempted = false;
g_wasm_init_error = "";
g_wasm_epoch_running.store(false);
new (&g_wasm_epoch_ticker) std::thread();
g_wasm_epoch_ticker = 0;
}