A client that leaves before its reply arrives, which used to kill the daemon
Eight hit-and-run connections against the robustness daemon, then a check that the session is still there and still knows what it installed. Fails with 'killed by SIGPIPE' against the parent of this commit.
This commit is contained in:
parent
fbafee4957
commit
4074eb7b7f
@ -3044,11 +3044,66 @@ let () =
|
|||||||
| None -> fail "(probe-one) produced no value")
|
| None -> fail "(probe-one) produced no value")
|
||||||
| Some r -> fail "(probe-one): %s %s" (status r) (message r)
|
| Some r -> fail "(probe-one): %s %s" (status r) (message r)
|
||||||
| None -> ());
|
| None -> ());
|
||||||
|
(* ── An editor that leaves before its reply does ──────────────── *)
|
||||||
|
(* The failure this closes was a flake in test_emacs, and it read like
|
||||||
|
nothing it was: two break-loop checks failing, and then
|
||||||
|
"cannot reconnect: Connection refused" on a socket path that plainly
|
||||||
|
existed. A write into a socket whose reader has gone is SIGPIPE, and
|
||||||
|
SIGPIPE's default action is to kill the process — which in the merged
|
||||||
|
build is the program, the compiler and the listener at once, and
|
||||||
|
leaves the socket file behind for the next client to be refused on.
|
||||||
|
It is not a contrived shape: reconnecting tears the old connection
|
||||||
|
down, and a reply already on its way out lands in the gap.
|
||||||
|
|
||||||
|
[c] is closed first because the daemon serves one connection at a
|
||||||
|
time: a second one would sit in the backlog until this one ended, and
|
||||||
|
then there would be no reply in flight to lose. *)
|
||||||
|
(try Unix.close c with Unix.Unix_error _ -> ());
|
||||||
|
let hit_and_run () =
|
||||||
|
let s = Unix.socket Unix.PF_UNIX Unix.SOCK_STREAM 0 in
|
||||||
|
(try
|
||||||
|
Unix.connect s (Unix.ADDR_UNIX rsock);
|
||||||
|
Wire.send s "(:op \"describe\")"
|
||||||
|
with Unix.Unix_error _ -> ());
|
||||||
|
(try Unix.close s with Unix.Unix_error _ -> ())
|
||||||
|
in
|
||||||
|
(* Several, because the first write into a freshly closed socket can
|
||||||
|
still land in a buffer nobody will read; the second is the one that
|
||||||
|
is refused. *)
|
||||||
|
for _ = 1 to 8 do hit_and_run (); ignore (Unix.select [] [] [] 0.02) done;
|
||||||
|
let c =
|
||||||
|
match Unix.waitpid [ Unix.WNOHANG ] rpid with
|
||||||
|
| 0, _ -> Some (connect rsock)
|
||||||
|
| _, st ->
|
||||||
|
(* Named rather than numbered, because [WSIGNALED] carries OCaml's
|
||||||
|
own signal numbering and "signal -8" would send the next reader
|
||||||
|
to the wrong page. SIGPIPE is the answer this check expects to
|
||||||
|
see when it fails. *)
|
||||||
|
fail "an editor that left before its reply did ended the daemon (%s)"
|
||||||
|
(match st with
|
||||||
|
| Unix.WEXITED n -> Printf.sprintf "exit %d" n
|
||||||
|
| Unix.WSIGNALED n when n = Sys.sigpipe -> "killed by SIGPIPE"
|
||||||
|
| Unix.WSIGNALED n -> Printf.sprintf "signal %d" n
|
||||||
|
| Unix.WSTOPPED n -> Printf.sprintf "stopped on %d" n);
|
||||||
|
None
|
||||||
|
| exception Unix.Unix_error _ -> Some (connect rsock)
|
||||||
|
in
|
||||||
|
(match c with
|
||||||
|
| None -> ()
|
||||||
|
| Some c ->
|
||||||
|
(match Wire.parse (Wire.send c "(:op \"describe\")"; Wire.recv c) with
|
||||||
|
| r ->
|
||||||
|
if not (contains_sub (Form.to_string (Option.get (Wire.field r "fns")))
|
||||||
|
"probe-one")
|
||||||
|
then fail "the session lost track of the program after a client left"
|
||||||
|
| exception e ->
|
||||||
|
fail "the session did not answer after a client left: %s"
|
||||||
|
(Printexc.to_string e));
|
||||||
(try
|
(try
|
||||||
ignore (Wire.send c "(:op \"close\")");
|
ignore (Wire.send c "(:op \"close\")");
|
||||||
ignore (Wire.recv c)
|
ignore (Wire.recv c)
|
||||||
with _ -> ());
|
with _ -> ());
|
||||||
(try Unix.close c with Unix.Unix_error _ -> ())
|
(try Unix.close c with Unix.Unix_error _ -> ()))
|
||||||
end;
|
end;
|
||||||
(try Unix.kill rpid Sys.sigkill with Unix.Unix_error _ -> ());
|
(try Unix.kill rpid Sys.sigkill with Unix.Unix_error _ -> ());
|
||||||
(try ignore (Unix.waitpid [] rpid) with Unix.Unix_error _ -> ());
|
(try ignore (Unix.waitpid [] rpid) with Unix.Unix_error _ -> ());
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user