The merged build's stdout is a 64K pipe back into the daemon's own process, and the accept loop is the only thing reading it -- which it is not doing while serve is answering a request. The two five-second waits for a frame boundary now drain the pipe on every tick, so a program stopped inside fwrite is one the daemon lets go rather than one it waits out and then accuses of not calling agent/poll. drain and not take: the text stays in the buffer until with_output puts it on the reply, which is where the output an evaluation caused belongs. And the drain sits beside the sleep rather than inside the select, because a readable pipe would make the tick free and count the timeout out in a fraction of it. dev-chatty.flan prints 4K a frame, which is the only fixture here that fills the pipe at all; without the drain it fails in 5.1s with the old sentence.
42 lines
2.0 KiB
Plaintext
42 lines
2.0 KiB
Plaintext
;;;; A program that prints far more than a pipe holds, for the one failure a
|
|
;;;; quiet fixture cannot reach.
|
|
;;;;
|
|
;;;; In a merged `flan dev' the program's stdout is a 64K pipe back into the
|
|
;;;; same process, and the only thing reading it is the daemon's accept loop —
|
|
;;;; which is not running while the daemon is answering a request. Every other
|
|
;;;; fixture here prints a line or two per frame, so the pipe never fills and
|
|
;;;; the arrangement looks sound. This one prints 4K per frame, which fills 64K
|
|
;;;; in sixteen frames: less time than a module takes to build. By the time an
|
|
;;;; evaluation is delivered the game thread is stopped inside fwrite, and it
|
|
;;;; stays there until somebody reads — so a daemon that waits for a frame
|
|
;;;; boundary without draining waits for one that cannot arrive, and then says
|
|
;;;; the program is not calling (agent/poll).
|
|
;;;;
|
|
;;;; It is calling it. See lib/dev.ml's [eval_expr], which drains every tick.
|
|
(import agent "vendor:agent")
|
|
|
|
;;; Counted so that an evaluation has something of the program's own to read,
|
|
;;; and so a transcript can be checked for progress rather than only for text.
|
|
(defvar frames i64)
|
|
|
|
(defn chatter [] i64
|
|
;; Sixty-four lines of sixty-three characters and a newline: 4096 bytes a
|
|
;; frame, written through the line buffer flan_rt.c asks for, so each line
|
|
;; is its own write and the block happens in the middle of a frame rather
|
|
;; than at a flush somewhere else.
|
|
(dotimes [i 64]
|
|
(println "..............................................................."))
|
|
(set frames (+ frames 1))
|
|
frames)
|
|
|
|
(defn main [] i32
|
|
(agent/start "/tmp/flan-dev-chatty-fallback.sock")
|
|
;; 24000 for dev-repl.flan's reason: the test closes the connection when it
|
|
;; is done and the daemon takes the program with it, so the count only has
|
|
;; to outlast the checks. A program that reached its last frame mid-test
|
|
;; would fail honestly and for the wrong reason.
|
|
(dotimes [i 24000]
|
|
(chatter)
|
|
(agent/wait 1))
|
|
0)
|