process.fnl (2537B)
1 (local ll (require :lualinux)) 2 (local { : find-executable } (require :anoia.fs)) 3 (import-macros { : define-tests : expect : expect= } :anoia.assert) 4 5 (macro errno-check [x] 6 `(match ,x 7 val# val# 8 (nil errno#) (assert nil (.. "system call failed, errno=" errno#)) 9 )) 10 11 (fn popen2 [pname argv envp] 12 (case (ll.pipe2) 13 (cin-s cin-d) 14 (match (ll.pipe2) 15 (cout-s cout-d) 16 (let [(pid err) (ll.fork)] 17 (if (not pid) (error (.. "error: " err)) 18 (= pid 0) 19 (do 20 (ll.close cin-d) 21 (ll.close cout-s) 22 (ll.dup2 cin-s 0) 23 (ll.dup2 cout-d 1) 24 (ll.dup2 cout-d 2) 25 (ll.execve pname argv envp) 26 (error "execve failed")) 27 (> pid 0) 28 (do 29 (ll.close cin-s) 30 (ll.close cout-d))) 31 (values pid cin-d cout-s)) 32 (nil err) (error (.. "popen pipe out: " err))) 33 (nil err) (error (.. "popen pipe in: " err)))) 34 35 (fn spawn [pname argv envp callback] 36 (let [(pid in out) (popen2 pname argv envp) 37 pollfds [ 38 (bor (lshift in 32) (lshift 4 16)) 39 (bor (lshift out 32) (lshift 1 16)) 40 ]] 41 (while (or (> (. pollfds 1) 0) (> (. pollfds 2) 0)) 42 (ll.poll pollfds) 43 (if 44 (> (band (. pollfds 2) 0x11) 0) ; POLLIN | POLLHUP 45 (if (not (callback :out out)) (tset pollfds 2 (lshift -1 32))) 46 47 (> (band (. pollfds 1) 4) 0) ; POLLOUT 48 (if (not (callback :in in)) (tset pollfds 1 (lshift -1 32))) 49 )) 50 51 (match (ll.waitpid pid) 52 (0 status) false 53 (pid status) (rshift (band status 0xff00) 8) 54 (nil errno) (error (.. "waitpid: " errno))))) 55 56 57 (define-tests 58 (var buf "4 * 6\n") ;; spawn bc to multiply two numbers 59 (let [out [] 60 p (spawn 61 (assert (find-executable "bc" (os.getenv "PATH"))) 62 ["bc"] 63 (ll.environ) 64 (fn [stream fd] 65 (match stream 66 :out (let [b (ll.read fd)] 67 (table.insert out b) 68 (> (# b) 0)) 69 :in (if (> (# buf) 0) 70 (let [bytes (ll.write fd buf)] 71 (set buf (string.sub buf (+ bytes 1) -1)) 72 true) 73 (do 74 (ll.close fd) 75 false)) 76 :err (assert nil (ll.read fd)))))] 77 (expect= (table.concat out) "24\n")) 78 ) 79 80 81 { 82 : popen2 83 : spawn 84 }