writeonce/runtime/src/builtin.h
shoney.arickathil d30ad04bd9 fix: a stopping program stops (executable plan, Task 4)
- blocking stdlib calls that PARK (net.accept, socket read/write,
  time.sleep, a child wait) no longer restart the syscall when the
  stop flag is set on an interruption: a server sitting in accept
  ignored SIGTERM and only `kill -9` ended it
- a stop is NOT a trap -- builtin.h's WO_SYS_STOPPED carries no error
  record and no catch handler sees it (`try` must not swallow
  SIGTERM); the VM unwinds the whole stack through the same drop
  machinery an uncaught trap uses, so nothing leaks on the way out
- wo_vm_call gained a third outcome (1 = stopped); the CLI maps it to
  the status the program's own `return 0` would have given, and a
  regular-file read keeps its plain EINTR retry -- it does not park
- an ASSIGNMENT was not an ownership boundary: `api_key =
  j.mcp.apiKey` moved the field pointer into the local, so the local
  aliased the record and the first unwind freed the same string twice
  (SIGSEGV in class_free). `let` copied a Text place, assignment now
  does too -- the same double free was latent on the normal exit path,
  hidden by the order the compiler happens to emit drops in
- log-watcher-accept is 7 checks: the seventh is the stop itself, with
  the hard kill demoted to a fallback whose use is the failure
- measured under ASan: mcp parked, mcp after traffic, watch and run
  all exit rc 0 with zero leaks; SIGINT behaves as SIGTERM
- gates: oop-accept ALL CRITERIA MET, oop-e2e 71/0, woc-test 565/0,
  wovm-test green, log-watcher 7/0

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 23:58:21 +02:00

28 lines
1.3 KiB
C

/* builtin.h — runtime services bytecode can't express (spec §3/§5):
* now/print/print_int/words plus the container bridge to cont.c. One
* dispatcher: takes the VM, the current frame's registers, and the
* instruction; 0 = ok, else a WO_T_* trap code with *msg set. */
#ifndef WO_BUILTIN_H
#define WO_BUILTIN_H
#include "vm.h"
/* Not a trap code: the stop flag (SIGTERM/SIGINT, armed by `env.stopping`)
* was set when a BLOCKING call was interrupted, so the call does not restart
* the syscall — it hands this back and the VM ends the program with it. A
* service parked in `accept` otherwise never observes the flag and only
* `kill -9` ends it. Negative so it cannot collide with a WO_T_* code, and
* deliberately NOT catchable: `try` must not be able to swallow a stop. */
#define WO_SYS_STOPPED (-2)
int wo_builtin(wo_vm *vm, uint64_t *R, uint32_t ins, const char **msg);
/* The systems stdlib's OS half (runtime/src/sysio.c): same contract as
* wo_builtin above — 0 on success, a WO_T_* code with *msg set on failure.
* wo_builtin dispatches every id at or above WO_B_SYS_FIRST here. */
int wo_builtin_sys(wo_vm *vm, uint64_t *R, uint32_t ins, const char **msg);
/* json.encode / json.decode (runtime/src/json.c), same contract again. */
int wo_builtin_json(wo_vm *vm, uint64_t *R, uint32_t ins, const char **msg);
#endif /* WO_BUILTIN_H */