Keep FastCGI available during restarts

This commit is contained in:
udo
2026-07-16 22:00:08 +00:00
parent 93c701c6c7
commit caffb3f404
16 changed files with 192 additions and 41 deletions
+19
View File
@@ -145,6 +145,25 @@ module lives in the configured writable cache root rather than beside the
possibly root-owned deployed `core.wasm`; freshness still uses the deployed possibly root-owned deployed `core.wasm`; freshness still uses the deployed
artifact's metadata. artifact's metadata.
Packaged deployments use systemd socket activation for FastCGI. The socket unit
owns `/run/uce/fastcgi.sock`; UCE validates and adopts the single named listener
after exec. The listener therefore remains connectable and queues requests while
the service and its post-fork workers restart. Direct launches without systemd
activation retain the existing configured Unix/TCP listener behavior.
On termination the parent asks render workers to close their listeners, finish
accepted connections within the bounded worker drain interval, and only then
exits. This prevents an accepted FastCGI request from being reset at handoff;
the socket unit queues later connections for the replacement workers.
The graceful signal handler belongs to the parent and render workers. Generic
`task()` children restore default termination signals after fork so
`task_kill()` and `server_stop()` retain their immediate stop contract.
Epoch interruption measures uninterrupted guest CPU segments. The common
hostcall membrane re-arms the store deadline after every native call, excluding
blocking I/O, process waits, hashing, and other host work without weakening a
guest loop that makes no hostcalls. Keeping this at the membrane also covers new
hostcalls without per-import timeout bookkeeping.
`request_perf()` reports worker module-cache hits and misses and divides a miss `request_perf()` reports worker module-cache hits and misses and divides a miss
into artifact lookup, wasm read, custom-section parse, serialized-module into artifact lookup, wasm read, custom-section parse, serialized-module
deserialization or wasm compilation, and immutable import classification. This deserialization or wasm compilation, and immutable import classification. This
+2 -1
View File
@@ -4,7 +4,8 @@ set -e
if command -v systemctl >/dev/null 2>&1; then if command -v systemctl >/dev/null 2>&1; then
systemctl daemon-reload >/dev/null 2>&1 || true systemctl daemon-reload >/dev/null 2>&1 || true
if [ "$1" = "configure" ]; then if [ "$1" = "configure" ]; then
systemctl enable uce.service >/dev/null 2>&1 || true systemctl enable uce.socket uce.service >/dev/null 2>&1 || true
systemctl start uce.socket >/dev/null 2>&1 || true
systemctl restart uce.service >/dev/null 2>&1 || true systemctl restart uce.service >/dev/null 2>&1 || true
fi fi
fi fi
+1 -1
View File
@@ -3,7 +3,7 @@ set -e
if [ "$1" = "remove" ] || [ "$1" = "deconfigure" ]; then if [ "$1" = "remove" ] || [ "$1" = "deconfigure" ]; then
if command -v systemctl >/dev/null 2>&1; then if command -v systemctl >/dev/null 2>&1; then
systemctl disable --now uce.service >/dev/null 2>&1 || true systemctl disable --now uce.service uce.socket >/dev/null 2>&1 || true
fi fi
fi fi
+3 -4
View File
@@ -1,7 +1,8 @@
[Unit] [Unit]
Description=UCE FastCGI Runtime Description=UCE FastCGI Runtime
After=network-online.target mariadb.service memcached.service After=network-online.target mariadb.service memcached.service uce.socket
Wants=network-online.target Wants=network-online.target
Requires=uce.socket
[Service] [Service]
Type=simple Type=simple
@@ -10,12 +11,10 @@ RuntimeDirectory=uce
StateDirectory=uce StateDirectory=uce
CacheDirectory=uce CacheDirectory=uce
ExecStartPre=/usr/bin/mkdir -p /var/cache/uce/work /var/lib/uce/uploads /var/lib/uce/sessions ExecStartPre=/usr/bin/mkdir -p /var/cache/uce/work /var/lib/uce/uploads /var/lib/uce/sessions
ExecStartPre=/usr/bin/rm -f /run/uce/fastcgi.sock
ExecStart=/usr/lib/uce/bin/uce_fastcgi.linux.bin ExecStart=/usr/lib/uce/bin/uce_fastcgi.linux.bin
ExecStopPost=/usr/bin/rm -f /run/uce/fastcgi.sock
Restart=always Restart=always
RestartSec=2 RestartSec=2
TimeoutStopSec=15 TimeoutStopSec=30
KillMode=mixed KillMode=mixed
StandardOutput=journal StandardOutput=journal
StandardError=journal StandardError=journal
+15
View File
@@ -0,0 +1,15 @@
[Unit]
Description=UCE FastCGI socket
[Socket]
ListenStream=/run/uce/fastcgi.sock
FileDescriptorName=fastcgi
SocketUser=www-data
SocketGroup=www-data
SocketMode=0660
DirectoryMode=0755
Backlog=100
Service=uce.service
[Install]
WantedBy=sockets.target
+1
View File
@@ -205,6 +205,7 @@ bundle_wasmtime "$STAGE_DIR"
write_packaged_settings "$STAGE_DIR/etc/uce/settings.cfg" "$WEBROOT" write_packaged_settings "$STAGE_DIR/etc/uce/settings.cfg" "$WEBROOT"
install -m 0644 "$DEB_ASSET_DIR/uce.service" "$STAGE_DIR/lib/systemd/system/uce.service" install -m 0644 "$DEB_ASSET_DIR/uce.service" "$STAGE_DIR/lib/systemd/system/uce.service"
install -m 0644 "$DEB_ASSET_DIR/uce.socket" "$STAGE_DIR/lib/systemd/system/uce.socket"
install -m 0644 "$DEB_ASSET_DIR/conffiles" "$DEBIAN_DIR/conffiles" install -m 0644 "$DEB_ASSET_DIR/conffiles" "$DEBIAN_DIR/conffiles"
install -m 0755 "$DEB_ASSET_DIR/postinst" "$DEBIAN_DIR/postinst" install -m 0755 "$DEB_ASSET_DIR/postinst" "$DEBIAN_DIR/postinst"
install -m 0755 "$DEB_ASSET_DIR/prerm" "$DEBIAN_DIR/prerm" install -m 0755 "$DEB_ASSET_DIR/prerm" "$DEBIAN_DIR/prerm"
+5 -2
View File
@@ -179,6 +179,7 @@ bundle_wasi_sdk "$STAGE_DIR"
bundle_wasmtime "$STAGE_DIR" bundle_wasmtime "$STAGE_DIR"
write_packaged_settings "$STAGE_DIR/etc/uce/settings.cfg" "$WEBROOT" write_packaged_settings "$STAGE_DIR/etc/uce/settings.cfg" "$WEBROOT"
install -m 0644 "$REPO_ROOT/scripts/deb/uce.service" "$STAGE_DIR/usr/lib/systemd/system/uce.service" install -m 0644 "$REPO_ROOT/scripts/deb/uce.service" "$STAGE_DIR/usr/lib/systemd/system/uce.service"
install -m 0644 "$REPO_ROOT/scripts/deb/uce.socket" "$STAGE_DIR/usr/lib/systemd/system/uce.socket"
( (
cd "$STAGE_DIR" cd "$STAGE_DIR"
@@ -225,13 +226,14 @@ cp -a %{_builddir}/$PACKAGE_NAME-$VERSION/. %{buildroot}/
%post %post
if command -v systemctl >/dev/null 2>&1; then if command -v systemctl >/dev/null 2>&1; then
systemctl daemon-reload >/dev/null 2>&1 || true systemctl daemon-reload >/dev/null 2>&1 || true
systemctl enable uce.service >/dev/null 2>&1 || true systemctl enable uce.socket uce.service >/dev/null 2>&1 || true
systemctl start uce.socket >/dev/null 2>&1 || true
systemctl restart uce.service >/dev/null 2>&1 || true systemctl restart uce.service >/dev/null 2>&1 || true
fi fi
%preun %preun
if [ "\$1" = "0" ] && command -v systemctl >/dev/null 2>&1; then if [ "\$1" = "0" ] && command -v systemctl >/dev/null 2>&1; then
systemctl disable --now uce.service >/dev/null 2>&1 || true systemctl disable --now uce.service uce.socket >/dev/null 2>&1 || true
fi fi
%postun %postun
@@ -245,6 +247,7 @@ fi
%config(noreplace) /etc/uce/settings.cfg %config(noreplace) /etc/uce/settings.cfg
/usr/lib/uce /usr/lib/uce
/usr/lib/systemd/system/uce.service /usr/lib/systemd/system/uce.service
/usr/lib/systemd/system/uce.socket
$WEBROOT $WEBROOT
%dir /var/cache/uce %dir /var/cache/uce
%dir /var/lib/uce %dir /var/lib/uce
+1
View File
@@ -73,4 +73,5 @@ if [[ "$action" == "run" ]]; then
scripts/test_mysql_epoch_refresh.sh scripts/test_mysql_epoch_refresh.sh
scripts/test_mysql_persistent_pool.sh scripts/test_mysql_persistent_pool.sh
scripts/test_log_timeliness.sh scripts/test_log_timeliness.sh
scripts/test_socket_activation.sh
fi fi
+3 -4
View File
@@ -1,7 +1,8 @@
[Unit] [Unit]
Description=UCE FastCGI Runtime Description=UCE FastCGI Runtime
After=network-online.target mariadb.service memcached.service After=network-online.target mariadb.service memcached.service uce.socket
Wants=network-online.target Wants=network-online.target
Requires=uce.socket
[Service] [Service]
Type=simple Type=simple
@@ -10,13 +11,11 @@ RuntimeDirectory=uce
StateDirectory=uce StateDirectory=uce
CacheDirectory=uce CacheDirectory=uce
ExecStartPre=/usr/bin/mkdir -p /var/cache/uce/work /var/lib/uce/uploads /var/lib/uce/sessions ExecStartPre=/usr/bin/mkdir -p /var/cache/uce/work /var/lib/uce/uploads /var/lib/uce/sessions
ExecStartPre=/usr/bin/rm -f /run/uce/fastcgi.sock
ExecStartPre=/usr/bin/bash /Code/uce.openfu.com/uce/scripts/build_linux.sh ExecStartPre=/usr/bin/bash /Code/uce.openfu.com/uce/scripts/build_linux.sh
ExecStart=/Code/uce.openfu.com/uce/bin/uce_fastcgi.linux.bin ExecStart=/Code/uce.openfu.com/uce/bin/uce_fastcgi.linux.bin
ExecStopPost=/usr/bin/rm -f /run/uce/fastcgi.sock
Restart=always Restart=always
RestartSec=2 RestartSec=2
TimeoutStopSec=15 TimeoutStopSec=30
KillMode=mixed KillMode=mixed
StandardOutput=journal StandardOutput=journal
StandardError=journal StandardError=journal
+15
View File
@@ -0,0 +1,15 @@
[Unit]
Description=UCE FastCGI socket
[Socket]
ListenStream=/run/uce/fastcgi.sock
FileDescriptorName=fastcgi
SocketUser=www-data
SocketGroup=www-data
SocketMode=0660
DirectoryMode=0755
Backlog=100
Service=uce.service
[Install]
WantedBy=sockets.target
+38
View File
@@ -0,0 +1,38 @@
#!/usr/bin/env bash
set -euo pipefail
service_name="${UCE_TEST_SERVICE:-uce.service}"
socket_name="${UCE_TEST_SOCKET_SERVICE:-uce.socket}"
http_host="${UCE_TEST_HTTP_HOST:-uce.openfu.com}"
http_path="${UCE_TEST_HTTP_PATH:-/info/}"
requests="${UCE_TEST_RESTART_REQUESTS:-100}"
statuses=$(mktemp)
trap 'rm -f "$statuses"' EXIT
systemctl is-active --quiet "$socket_name"
systemctl is-active --quiet "$service_name"
socket_path=$(systemctl show -p Listen --value "$socket_name" | sed -n 's/ \+(Stream)$//p')
[[ -S "$socket_path" ]]
inode_before=$(stat -c %i "$socket_path")
(
for ((i = 0; i < requests; i++)); do
curl -sS --max-time 15 -o /dev/null -w '%{http_code}\n' \
-H "Host: $http_host" "http://127.0.0.1${http_path}"
done
) >"$statuses" &
load_pid=$!
sleep 0.05
systemctl restart "$service_name"
wait "$load_pid"
inode_after=$(stat -c %i "$socket_path")
[[ "$inode_after" = "$inode_before" ]]
[[ $(wc -l <"$statuses") -eq "$requests" ]]
if [[ $(grep -c '^200$' "$statuses") -ne "$requests" ]]; then
sort "$statuses" | uniq -c >&2
exit 1
fi
systemctl is-active --quiet "$socket_name"
systemctl is-active --quiet "$service_name"
echo "socket activation restart passed across $requests HTTP requests"
+16 -2
View File
@@ -206,7 +206,6 @@ FastCGIServer::shutdown()
{ {
printf("Closing server socket %i\n", *it); printf("Closing server socket %i\n", *it);
close(*it); close(*it);
sleep(1);
} }
for (std::vector<std::string>::iterator it = listen_unlink.begin(); for (std::vector<std::string>::iterator it = listen_unlink.begin();
@@ -223,7 +222,6 @@ FastCGIServer::shutdown()
delete it->second; delete it->second;
} }
sleep(1);
server_sockets.clear(); server_sockets.clear();
} }
@@ -264,6 +262,22 @@ FastCGIServer::listen(unsigned tcp_port)
return(listen(tcp_port, "0.0.0.0")); return(listen(tcp_port, "0.0.0.0"));
} }
int
FastCGIServer::adopt_listener(int socket_handle, char type)
{
int accepting = 0;
socklen_t accepting_size = sizeof(accepting);
if(socket_handle < 0 || getsockopt(socket_handle, SOL_SOCKET, SO_ACCEPTCONN,
&accepting, &accepting_size) != 0 || !accepting)
throw std::runtime_error("inherited descriptor is not a listening socket");
set_socket_nonblocking(socket_handle);
server_sockets.push_back(socket_handle);
server_socket_types[socket_handle] = type;
printf("(P) adopted #%i inherited %s listener\n", socket_handle,
type == 'F' ? "FastCGI" : "server");
return(socket_handle);
}
int int
FastCGIServer::listen(unsigned tcp_port, const std::string& bind_address) FastCGIServer::listen(unsigned tcp_port, const std::string& bind_address)
{ {
+1
View File
@@ -57,6 +57,7 @@ public:
int listen_http(unsigned tcp_port, const std::string& bind_address); int listen_http(unsigned tcp_port, const std::string& bind_address);
int listen_cli(const std::string& local_path); int listen_cli(const std::string& local_path);
int listen(const std::string& local_path); int listen(const std::string& local_path);
int adopt_listener(int socket_handle, char type = 'F');
void process(int timeout_ms = -1); // timeout_ms<0 blocks forever void process(int timeout_ms = -1); // timeout_ms<0 blocks forever
void process_forever(); void process_forever();
+6
View File
@@ -1549,6 +1549,12 @@ pid_t task(String key, std::function<void()> exec_after_spawn, u64 timeout)
{ {
close_locked_file(lock_fd); close_locked_file(lock_fd);
my_pid = getpid(); my_pid = getpid();
// The FastCGI worker handles termination to drain accepted requests.
// Generic task children do not run that drain loop, so inheriting those
// handlers would turn task_kill(SIGTERM) into a no-op.
signal(SIGTERM, SIG_DFL);
signal(SIGINT, SIG_DFL);
signal(SIGHUP, SIG_DFL);
signal(SIGALRM, SIG_DFL); signal(SIGALRM, SIG_DFL);
if(timeout > 0) if(timeout > 0)
alarm(timeout); alarm(timeout);
+57 -13
View File
@@ -699,15 +699,7 @@ volatile bool termination_signal_received = false;
void on_terminate(int sig) void on_terminate(int sig)
{ {
if(termination_signal_received)
return;
termination_signal_received = true; termination_signal_received = true;
if(getpid() != parent_pid)
exit(1);
printf("Terminating... PID %i:%i\n", getpid(), parent_pid);
wasm_backend_shutdown();
server.shutdown();
exit(1);
} }
void clear_shared_unit_cache(ServerState& state) void clear_shared_unit_cache(ServerState& state)
@@ -1069,7 +1061,7 @@ void run_ws_broker()
ws_broker.listen(server_state.config["WS_BROKER_SOCKET_PATH"]); ws_broker.listen(server_state.config["WS_BROKER_SOCKET_PATH"]);
chmod(server_state.config["WS_BROKER_SOCKET_PATH"].c_str(), S_IRWXU | S_IRGRP | S_IWGRP); chmod(server_state.config["WS_BROKER_SOCKET_PATH"].c_str(), S_IRWXU | S_IRGRP | S_IWGRP);
} }
for(;;) while(!termination_signal_received)
{ {
ws_broker.process(50); ws_broker.process(50);
ws_broker_drain_outbound(ws_broker_outbound_timeout_seconds); ws_broker_drain_outbound(ws_broker_outbound_timeout_seconds);
@@ -1254,7 +1246,7 @@ void run_proactive_compiler()
} }
next_scan_at = time_precise(); next_scan_at = time_precise();
for(;;) while(!termination_signal_received)
{ {
try try
{ {
@@ -1397,10 +1389,21 @@ void listen_for_connections()
printf("(P) wasm worker ready: PID %i in %.3f ms\n", getpid(), wasm_ms); printf("(P) wasm worker ready: PID %i in %.3f ms\n", getpid(), wasm_ms);
else else
fprintf(stderr, "(!) wasm worker initialization failed: PID %i in %.3f ms: %s\n", getpid(), wasm_ms, wasm_error.c_str()); fprintf(stderr, "(!) wasm worker initialization failed: PID %i in %.3f ms: %s\n", getpid(), wasm_ms, wasm_error.c_str());
for(;;) while(!termination_signal_received)
{ {
server.process(-1); server.process(-1);
} }
close_inherited_server_sockets();
f64 drain_deadline = time_precise() + (f64)to_u64(server_state.config["WORKER_DRAIN_TIMEOUT_SECONDS"], 10);
while(!server.client_sockets.empty() && time_precise() < drain_deadline)
server.process(100);
if(!server.client_sockets.empty())
fprintf(stderr, "(!) worker PID %i drain deadline reached with %zu client connections\n",
getpid(), server.client_sockets.size());
else
printf("(P) worker PID %i drained cleanly\n", getpid());
wasm_backend_shutdown();
exit(server.client_sockets.empty() ? 0 : 1);
} }
mode_t configured_socket_mode(String value, mode_t fallback) mode_t configured_socket_mode(String value, mode_t fallback)
@@ -1424,6 +1427,25 @@ void chmod_configured_socket(String path, String mode_value, mode_t fallback)
fprintf(stderr, "(!) Could not chmod socket %s to %04o: %s\n", path.c_str(), (unsigned int)mode, strerror(errno)); fprintf(stderr, "(!) Could not chmod socket %s to %04o: %s\n", path.c_str(), (unsigned int)mode, strerror(errno));
} }
int systemd_fastcgi_listener()
{
const char* listen_pid = getenv("LISTEN_PID");
const char* listen_fds = getenv("LISTEN_FDS");
if(!listen_pid || !listen_fds)
return(-1);
if(to_u64(listen_pid, 0) != (u64)getpid())
return(-1);
if(to_u64(listen_fds, 0) != 1)
throw std::runtime_error("UCE requires exactly one systemd FastCGI listener");
const char* names = getenv("LISTEN_FDNAMES");
if(names && names[0] != '\0' && String(names) != "fastcgi")
throw std::runtime_error("systemd listener must be named fastcgi");
unsetenv("LISTEN_PID");
unsetenv("LISTEN_FDS");
unsetenv("LISTEN_FDNAMES");
return(3);
}
StringMap redacted_server_config_for_log(const StringMap& config) StringMap redacted_server_config_for_log(const StringMap& config)
{ {
StringMap redacted = config; StringMap redacted = config;
@@ -1443,13 +1465,16 @@ void init_base_process()
server_state.config = make_server_settings(); server_state.config = make_server_settings();
server_state.config["COMPILER_SYS_PATH"] = cwd_get(); server_state.config["COMPILER_SYS_PATH"] = cwd_get();
printf("Compiler base path: %s\n", server_state.config["COMPILER_SYS_PATH"].c_str()); printf("Compiler base path: %s\n", server_state.config["COMPILER_SYS_PATH"].c_str());
int inherited_fastcgi = systemd_fastcgi_listener();
if(inherited_fastcgi >= 0)
server.adopt_listener(inherited_fastcgi, 'F');
if(server_state.config["FCGI_PORT"] != "") if(server_state.config["FCGI_PORT"] != "")
server.listen(int_val(server_state.config["FCGI_PORT"])); server.listen(int_val(server_state.config["FCGI_PORT"]));
printf("%s\n", var_dump(redacted_server_config_for_log(server_state.config)).c_str()); printf("%s\n", var_dump(redacted_server_config_for_log(server_state.config)).c_str());
if(server_state.config["FCGI_SOCKET_PATH"] != "") if(inherited_fastcgi < 0 && server_state.config["FCGI_SOCKET_PATH"] != "")
{ {
server.listen(server_state.config["FCGI_SOCKET_PATH"]); server.listen(server_state.config["FCGI_SOCKET_PATH"]);
chmod_configured_socket(server_state.config["FCGI_SOCKET_PATH"], server_state.config["FCGI_SOCKET_MODE"], 0666); chmod_configured_socket(server_state.config["FCGI_SOCKET_PATH"], server_state.config["FCGI_SOCKET_MODE"], 0666);
@@ -1469,7 +1494,9 @@ void init_base_process()
mkdir(server_state.config["SESSION_PATH"]); mkdir(server_state.config["SESSION_PATH"]);
signal(SIGCHLD, on_child_exit); signal(SIGCHLD, on_child_exit);
signal(SIGTERM, on_terminate);
signal(SIGINT, on_terminate); signal(SIGINT, on_terminate);
signal(SIGHUP, on_terminate);
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
srand(time()); srand(time());
} }
@@ -1489,7 +1516,7 @@ int main(int argc, char** argv)
ensure_proactive_compiler(); ensure_proactive_compiler();
ensure_ws_broker(); ensure_ws_broker();
for(;;) while(!termination_signal_received)
{ {
if(!proactive_compiler_alive()) if(!proactive_compiler_alive())
proactive_compiler_pid = 0; proactive_compiler_pid = 0;
@@ -1512,5 +1539,22 @@ int main(int argc, char** argv)
sleep(1); sleep(1);
} }
printf("(P) draining %zu workers before shutdown\n", workers.size());
for(auto& worker : workers)
kill(worker.first, SIGTERM);
if(proactive_compiler_pid > 0)
kill(proactive_compiler_pid, SIGTERM);
if(ws_broker_pid > 0)
kill(ws_broker_pid, SIGTERM);
f64 drain_deadline = time_precise() + (f64)to_u64(server_state.config["WORKER_DRAIN_TIMEOUT_SECONDS"], 10);
while(!workers.empty() && time_precise() < drain_deadline)
{
on_child_exit(0);
usleep(10000);
}
for(auto& worker : workers)
kill(worker.first, SIGKILL);
server.shutdown();
return 0; return 0;
} }
+9 -14
View File
@@ -2106,6 +2106,11 @@ private:
auto profiled = [self, callback, profile_name](Caller caller, Span<const Val> args, Span<Val> results) mutable -> Result<std::monostate, Trap> { auto profiled = [self, callback, profile_name](Caller caller, Span<const Val> args, Span<Val> results) mutable -> Result<std::monostate, Trap> {
auto started = std::chrono::steady_clock::now(); auto started = std::chrono::steady_clock::now();
auto result = callback(caller, args, results); auto result = callback(caller, args, results);
// Epoch interruption limits guest CPU, not time spent in native I/O,
// process management, hashing, or other host work. Re-arm at the one
// membrane every hostcall crosses so newly added blocking imports
// cannot silently consume the next guest segment's budget.
caller.context().set_epoch_deadline(self->worker.cfg.epoch_deadline_ticks);
if(profile_name != "uce_host_request_perf") if(profile_name != "uce_host_request_perf")
{ {
u64 elapsed = (u64)std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - started).count(); u64 elapsed = (u64)std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - started).count();
@@ -2288,9 +2293,9 @@ private:
if(mod == "env" && name == "uce_host_crypto_equal") if(mod == "env" && name == "uce_host_crypto_equal")
return(add([self](Caller, Span<const Val> args, Span<Val> results) -> Result<std::monostate, Trap> { String a,b; self->hostcall_read(args[0].i32(), args[1].i32(), a); self->hostcall_read(args[2].i32(), args[3].i32(), b); results[0]=Val((int32_t)(crypto_equal_native(a,b)?1:0)); return(std::monostate()); })); return(add([self](Caller, Span<const Val> args, Span<Val> results) -> Result<std::monostate, Trap> { String a,b; self->hostcall_read(args[0].i32(), args[1].i32(), a); self->hostcall_read(args[2].i32(), args[3].i32(), b); results[0]=Val((int32_t)(crypto_equal_native(a,b)?1:0)); return(std::monostate()); }));
if(mod == "env" && name == "uce_host_password_hash") if(mod == "env" && name == "uce_host_password_hash")
return(add([self](Caller caller, Span<const Val> args, Span<Val> results) -> Result<std::monostate, Trap> { String password; self->hostcall_read(args[0].i32(), args[1].i32(), password); String out=password_hash_native(password); u32 cap=(u32)args[3].i32(); int32_t buf=args[2].i32(); if(buf&&cap>=out.size()) self->hostcall_write(buf,out); caller.context().set_epoch_deadline(self->worker.cfg.epoch_deadline_ticks); results[0]=Val((int32_t)out.size()); return(std::monostate()); })); return(add([self](Caller, Span<const Val> args, Span<Val> results) -> Result<std::monostate, Trap> { String password; self->hostcall_read(args[0].i32(), args[1].i32(), password); String out=password_hash_native(password); u32 cap=(u32)args[3].i32(); int32_t buf=args[2].i32(); if(buf&&cap>=out.size()) self->hostcall_write(buf,out); results[0]=Val((int32_t)out.size()); return(std::monostate()); }));
if(mod == "env" && name == "uce_host_password_verify") if(mod == "env" && name == "uce_host_password_verify")
return(add([self](Caller caller, Span<const Val> args, Span<Val> results) -> Result<std::monostate, Trap> { String password,encoded; self->hostcall_read(args[0].i32(), args[1].i32(), password); self->hostcall_read(args[2].i32(), args[3].i32(), encoded); bool valid=password_verify_native(password,encoded); caller.context().set_epoch_deadline(self->worker.cfg.epoch_deadline_ticks); results[0]=Val((int32_t)(valid?1:0)); return(std::monostate()); })); return(add([self](Caller, Span<const Val> args, Span<Val> results) -> Result<std::monostate, Trap> { String password,encoded; self->hostcall_read(args[0].i32(), args[1].i32(), password); self->hostcall_read(args[2].i32(), args[3].i32(), encoded); bool valid=password_verify_native(password,encoded); results[0]=Val((int32_t)(valid?1:0)); return(std::monostate()); }));
if(mod == "env" && name == "uce_host_password_needs_rehash") if(mod == "env" && name == "uce_host_password_needs_rehash")
return(add([self](Caller, Span<const Val> args, Span<Val> results) -> Result<std::monostate, Trap> { String encoded; self->hostcall_read(args[0].i32(), args[1].i32(), encoded); results[0]=Val((int32_t)(password_needs_rehash_native(encoded)?1:0)); return(std::monostate()); })); return(add([self](Caller, Span<const Val> args, Span<Val> results) -> Result<std::monostate, Trap> { String encoded; self->hostcall_read(args[0].i32(), args[1].i32(), encoded); results[0]=Val((int32_t)(password_needs_rehash_native(encoded)?1:0)); return(std::monostate()); }));
if(mod == "env" && name == "uce_host_log") if(mod == "env" && name == "uce_host_log")
@@ -2316,7 +2321,6 @@ private:
} }
if(buf != 0 && cap >= out.size()) if(buf != 0 && cap >= out.size())
self->hostcall_write(buf, out); self->hostcall_write(buf, out);
caller.context().set_epoch_deadline(self->worker.cfg.epoch_deadline_ticks);
results[0] = Val((int32_t)out.size()); results[0] = Val((int32_t)out.size());
return(std::monostate()); return(std::monostate());
})); }));
@@ -2324,7 +2328,7 @@ private:
return(add([self](Caller caller, Span<const Val> args, Span<Val> results) -> Result<std::monostate, Trap> { return(add([self](Caller caller, Span<const Val> args, Span<Val> results) -> Result<std::monostate, Trap> {
String encoded; self->hostcall_read(args[0].i32(), args[1].i32(), encoded); u32 cap=(u32)args[3].i32(); int32_t buf=args[2].i32(); String out; String stage_key="http:"+encoded; String encoded; self->hostcall_read(args[0].i32(), args[1].i32(), encoded); u32 cap=(u32)args[3].i32(); int32_t buf=args[2].i32(); String out; String stage_key="http:"+encoded;
if(!self->hostcall_staged(stage_key,out)) { DValue req,response; String err; if(ucb_decode(encoded,req,&err)) response=uce_http_request_value(req); else response["error"]="http_request decode failed: "+err; out=ucb_encode(response); if(buf==0) self->hostcall_stage(stage_key,out); } if(!self->hostcall_staged(stage_key,out)) { DValue req,response; String err; if(ucb_decode(encoded,req,&err)) response=uce_http_request_value(req); else response["error"]="http_request decode failed: "+err; out=ucb_encode(response); if(buf==0) self->hostcall_stage(stage_key,out); }
if(buf&&cap>=out.size()) self->hostcall_write(buf,out); caller.context().set_epoch_deadline(self->worker.cfg.epoch_deadline_ticks); results[0]=Val((int32_t)out.size()); return(std::monostate()); if(buf&&cap>=out.size()) self->hostcall_write(buf,out); results[0]=Val((int32_t)out.size()); return(std::monostate());
})); }));
if(mod == "env" && name == "uce_host_http_request_async") if(mod == "env" && name == "uce_host_http_request_async")
return(add([self](Caller, Span<const Val> args, Span<Val> results) -> Result<std::monostate, Trap> { String encoded; self->hostcall_read(args[0].i32(), args[1].i32(), encoded); DValue req; String err; u64 id=0; if(ucb_decode(encoded,req,&err)) id=uce_http_spawn_spec(req); results[0]=Val((int64_t)id); return(std::monostate()); })); return(add([self](Caller, Span<const Val> args, Span<Val> results) -> Result<std::monostate, Trap> { String encoded; self->hostcall_read(args[0].i32(), args[1].i32(), encoded); DValue req; String err; u64 id=0; if(ucb_decode(encoded,req,&err)) id=uce_http_spawn_spec(req); results[0]=Val((int64_t)id); return(std::monostate()); }));
@@ -2335,7 +2339,6 @@ private:
String out; String stage_key="shell_dv:"+encoded; String out; String stage_key="shell_dv:"+encoded;
if(!self->hostcall_staged(stage_key,out)) { DValue spec, response; String err; if(ucb_decode(encoded,spec,&err)) response=uce_shell_exec_spec(spec); else response["error"]="shell_exec spec decode failed: "+err; out=ucb_encode(response); if(buf==0) self->hostcall_stage(stage_key,out); } if(!self->hostcall_staged(stage_key,out)) { DValue spec, response; String err; if(ucb_decode(encoded,spec,&err)) response=uce_shell_exec_spec(spec); else response["error"]="shell_exec spec decode failed: "+err; out=ucb_encode(response); if(buf==0) self->hostcall_stage(stage_key,out); }
if(buf&&cap>=out.size()) self->hostcall_write(buf,out); if(buf&&cap>=out.size()) self->hostcall_write(buf,out);
caller.context().set_epoch_deadline(self->worker.cfg.epoch_deadline_ticks);
results[0]=Val((int32_t)out.size()); return(std::monostate()); results[0]=Val((int32_t)out.size()); return(std::monostate());
})); }));
if(mod == "env" && name == "uce_host_shell_spawn") if(mod == "env" && name == "uce_host_shell_spawn")
@@ -2347,7 +2350,7 @@ private:
if(mod == "env" && name == "uce_host_job_result") if(mod == "env" && name == "uce_host_job_result")
return(add([self](Caller, Span<const Val> args, Span<Val> results) -> Result<std::monostate, Trap> { String out=ucb_encode(uce_job_result_value((u64)args[0].i64(), 100)); u32 cap=(u32)args[2].i32(); int32_t buf=args[1].i32(); if(buf&&cap>=out.size()) self->hostcall_write(buf,out); results[0]=Val((int32_t)out.size()); return(std::monostate()); })); return(add([self](Caller, Span<const Val> args, Span<Val> results) -> Result<std::monostate, Trap> { String out=ucb_encode(uce_job_result_value((u64)args[0].i64(), 100)); u32 cap=(u32)args[2].i32(); int32_t buf=args[1].i32(); if(buf&&cap>=out.size()) self->hostcall_write(buf,out); results[0]=Val((int32_t)out.size()); return(std::monostate()); }));
if(mod == "env" && name == "uce_host_job_await") if(mod == "env" && name == "uce_host_job_await")
return(add([self](Caller caller, Span<const Val> args, Span<Val> results) -> Result<std::monostate, Trap> { u64 timeout=std::min<u64>((u64)args[1].i64(), 30000); String out=ucb_encode(uce_job_result_value((u64)args[0].i64(), timeout)); u32 cap=(u32)args[3].i32(); int32_t buf=args[2].i32(); if(buf&&cap>=out.size()) self->hostcall_write(buf,out); caller.context().set_epoch_deadline(self->worker.cfg.epoch_deadline_ticks); results[0]=Val((int32_t)out.size()); return(std::monostate()); })); return(add([self](Caller, Span<const Val> args, Span<Val> results) -> Result<std::monostate, Trap> { u64 timeout=std::min<u64>((u64)args[1].i64(), 30000); String out=ucb_encode(uce_job_result_value((u64)args[0].i64(), timeout)); u32 cap=(u32)args[3].i32(); int32_t buf=args[2].i32(); if(buf&&cap>=out.size()) self->hostcall_write(buf,out); results[0]=Val((int32_t)out.size()); return(std::monostate()); }));
if(mod == "env" && name == "uce_host_job_cancel") if(mod == "env" && name == "uce_host_job_cancel")
return(add([](Caller, Span<const Val> args, Span<Val> results) -> Result<std::monostate, Trap> { results[0]=Val((int32_t)(uce_job_cancel_value((u64)args[0].i64())?1:0)); return(std::monostate()); })); return(add([](Caller, Span<const Val> args, Span<Val> results) -> Result<std::monostate, Trap> { results[0]=Val((int32_t)(uce_job_cancel_value((u64)args[0].i64())?1:0)); return(std::monostate()); }));
if(mod == "env" && name == "uce_host_path_real") if(mod == "env" && name == "uce_host_path_real")
@@ -2823,7 +2826,6 @@ private:
} }
if(buf != 0 && cap >= out.size()) if(buf != 0 && cap >= out.size())
self->hostcall_write(buf, out); self->hostcall_write(buf, out);
caller.context().set_epoch_deadline(self->worker.cfg.epoch_deadline_ticks);
results[0] = Val((int32_t)out.size()); results[0] = Val((int32_t)out.size());
return(std::monostate()); return(std::monostate());
})); }));
@@ -2922,7 +2924,6 @@ private:
} }
if(buf != 0 && cap >= out.size()) if(buf != 0 && cap >= out.size())
self->hostcall_write(buf, out); self->hostcall_write(buf, out);
caller.context().set_epoch_deadline(self->worker.cfg.epoch_deadline_ticks);
results[0] = Val((int32_t)out.size()); results[0] = Val((int32_t)out.size());
return(std::monostate()); return(std::monostate());
})); }));
@@ -3033,7 +3034,6 @@ private:
} }
if(buf != 0 && cap >= out.size()) if(buf != 0 && cap >= out.size())
self->hostcall_write(buf, out); self->hostcall_write(buf, out);
caller.context().set_epoch_deadline(self->worker.cfg.epoch_deadline_ticks);
results[0] = Val((int32_t)out.size()); results[0] = Val((int32_t)out.size());
return(std::monostate()); return(std::monostate());
})); }));
@@ -3074,7 +3074,6 @@ private:
context->resources.sockets.push_back(fd); context->resources.sockets.push_back(fd);
} }
results[0] = Val((int64_t)(fd > 0 ? fd : 0)); results[0] = Val((int64_t)(fd > 0 ? fd : 0));
caller.context().set_epoch_deadline(self->worker.cfg.epoch_deadline_ticks);
return(std::monostate()); return(std::monostate());
})); }));
if(mod == "env" && name == "uce_host_socket_close") if(mod == "env" && name == "uce_host_socket_close")
@@ -3115,7 +3114,6 @@ private:
} }
if(buf != 0 && cap >= out.size()) if(buf != 0 && cap >= out.size())
self->hostcall_write(buf, out); self->hostcall_write(buf, out);
caller.context().set_epoch_deadline(self->worker.cfg.epoch_deadline_ticks);
results[0] = Val((int32_t)out.size()); results[0] = Val((int32_t)out.size());
return(std::monostate()); return(std::monostate());
})); }));
@@ -3208,7 +3206,6 @@ private:
unsigned int remaining = ::sleep((unsigned int)(usec / 1000000ull)); unsigned int remaining = ::sleep((unsigned int)(usec / 1000000ull));
if(remaining != 0) if(remaining != 0)
{ {
caller.context().set_epoch_deadline(self->worker.cfg.epoch_deadline_ticks);
results[0] = Val((int32_t)remaining); results[0] = Val((int32_t)remaining);
return(std::monostate()); return(std::monostate());
} }
@@ -3216,7 +3213,6 @@ private:
} }
if(usec > 0) if(usec > 0)
::usleep((useconds_t)usec); ::usleep((useconds_t)usec);
caller.context().set_epoch_deadline(self->worker.cfg.epoch_deadline_ticks);
results[0] = Val((int32_t)0); results[0] = Val((int32_t)0);
return(std::monostate()); return(std::monostate());
})); }));
@@ -3275,7 +3271,6 @@ private:
self->hostcall_write(args[6].i32(), resolved); self->hostcall_write(args[6].i32(), resolved);
} }
results[0] = Val(slot); results[0] = Val(slot);
caller.context().set_epoch_deadline(self->worker.cfg.epoch_deadline_ticks);
return(std::monostate()); return(std::monostate());
})); }));