115 lines
3.6 KiB
Plaintext
115 lines
3.6 KiB
Plaintext
## child processes: sys.popen / pwait / pkill / pclose over the handle table
|
|
|
|
fun chk(ok msg) {
|
|
if ok { printf "OK: %s\n" msg } \
|
|
else { printf "ERROR: %s\n" msg }
|
|
}
|
|
|
|
iosem := (core.sem-new)
|
|
tmo := (core.sem-new)
|
|
sg := (core.semgr-new)
|
|
core.semgr-add sg iosem
|
|
core.semgr-add sg tmo
|
|
|
|
fun waitin(h secs) {
|
|
| s |
|
|
core.sem-signal tmo secs 0
|
|
core.sem-signal-on-input iosem h
|
|
s := (core.semgr-wait sg)
|
|
core.sem-unsignal iosem
|
|
core.sem-unsignal tmo
|
|
if (eqv? s tmo) { return 0 } else { return 1 }
|
|
}
|
|
|
|
## read until data arrives, retrying on -1
|
|
fun rd(h buf) {
|
|
| n |
|
|
while true {
|
|
n := (sys.read h buf)
|
|
if (>= n 0) { return n }
|
|
if (= (waitin h 5) 0) { return -1 }
|
|
}
|
|
}
|
|
|
|
## reap without blocking the VM, waiting on a short timer between looks
|
|
fun reap(proc) {
|
|
| n k |
|
|
k := 0
|
|
while (< k 300) {
|
|
n := (sys.pwait proc)
|
|
if (not (= n 256)) { return n }
|
|
core.sem-signal tmo 0 20000000
|
|
core.semgr-wait sg
|
|
core.sem-unsignal tmo
|
|
k := (+ k 1)
|
|
}
|
|
return 256
|
|
}
|
|
|
|
buf := (core.basicNew ByteArray 64)
|
|
|
|
## --- stdout and the exit status ---
|
|
p := (sys.popen "printf abc; exit 3" "r")
|
|
chk (array? p) "sys.popen returns a handle array"
|
|
chk (integer? (core.basicAt p 0)) "slot 0 is the process handle"
|
|
chk (nil? (core.basicAt p 1)) "stdin is nil when 'w' was not requested"
|
|
chk (integer? (core.basicAt p 2)) "stdout is a handle when 'r' was requested"
|
|
chk (nil? (core.basicAt p 3)) "stderr is nil when 'e' was not requested"
|
|
chk (= (rd (core.basicAt p 2) buf) 3) "the child's stdout is readable"
|
|
chk (= (reap (core.basicAt p 0)) 3) "the exit status comes through"
|
|
sys.pclose (core.basicAt p 0)
|
|
|
|
## --- bidirectional: write to stdin, read stdout ---
|
|
p := (sys.popen "tr a-z A-Z" "rw")
|
|
inh := (core.basicAt p 1)
|
|
outh := (core.basicAt p 2)
|
|
chk (integer? inh) "stdin is a handle when 'w' was requested"
|
|
wb := (core.basicNew ByteArray 3)
|
|
core.basicAtPut wb 0 120
|
|
core.basicAtPut wb 1 121
|
|
core.basicAtPut wb 2 122
|
|
chk (= (sys.write inh wb) 3) "writing to the child's stdin works"
|
|
## closing the child's stdin must really send eof, or tr never flushes
|
|
sys.close inh
|
|
chk (= (rd outh buf) 3) "the child answered after stdin was closed"
|
|
chk (= (core.basicAt buf 0) 88) "the child transformed the data (x -> X)"
|
|
sys.pclose (core.basicAt p 0)
|
|
|
|
## --- stderr kept separate from stdout ---
|
|
p := (sys.popen "printf OUT; printf ERRR 1>&2" "re")
|
|
chk (= (rd (core.basicAt p 2) buf) 3) "stdout has its own stream"
|
|
chk (= (rd (core.basicAt p 3) buf) 4) "stderr has its own stream"
|
|
sys.pclose (core.basicAt p 0)
|
|
|
|
## --- a signalled child reports 256 + signo ---
|
|
p := (sys.popen "kill -TERM $$" "r")
|
|
chk (= (reap (core.basicAt p 0)) 271) "a signalled child reports 256 + SIGTERM"
|
|
sys.pclose (core.basicAt p 0)
|
|
|
|
## --- sys.pkill ---
|
|
p := (sys.popen "sleep 60" "r")
|
|
chk (= (sys.pwait (core.basicAt p 0)) 256) "a running child reports 256"
|
|
sys.pkill (core.basicAt p 0)
|
|
chk (= (reap (core.basicAt p 0)) 265) "after pkill the child reports 256 + SIGKILL"
|
|
sys.pclose (core.basicAt p 0)
|
|
|
|
## --- pclose tears the whole group down ---
|
|
p := (sys.popen "sleep 60" "r")
|
|
outh := (core.basicAt p 2)
|
|
sys.pclose (core.basicAt p 0)
|
|
chk true "pclose released the group"
|
|
|
|
## --- the exit handle ---
|
|
## it is muxable but carries no bytes. it exists only where the platform has
|
|
## pidfd_open(); elsewhere sys.popen answers nil for it, so guard the check
|
|
## rather than assuming Linux.
|
|
p := (sys.popen "true" "r")
|
|
xh := (core.basicAt p 4)
|
|
if (nil? xh) { printf "OK: no exit handle where the platform has no pidfd\n" } \
|
|
else {
|
|
raised := false
|
|
try { sys.read xh (core.basicNew ByteArray 4) } catch (e) { raised := true }
|
|
chk raised "the exit handle carries no bytes"
|
|
}
|
|
sys.pclose (core.basicAt p 0)
|