| 709 |
709 |
|
assert_eq!(sequence.output(), ["Module is unknown"]);
|
| 710 |
710 |
|
}
|
| 711 |
711 |
|
|
|
712 |
+ |
// Writing a command's stdin used to happen on the render thread, before
|
|
713 |
+ |
// the pump threads existed. A child that writes before it reads fills its
|
|
714 |
+ |
// stdout pipe and stops, so the write blocked against a child that would
|
|
715 |
+ |
// never read, and the readers that would have unblocked it had not been
|
|
716 |
+ |
// started yet. Safe today only because the one secret is about a hundred
|
|
717 |
+ |
// bytes against a 64 KiB pipe buffer, which is a bound nothing states.
|
|
718 |
+ |
//
|
|
719 |
+ |
// Driven on its own thread because the failure is a deadlock: without this
|
|
720 |
+ |
// the test would hang the suite rather than fail it.
|
|
721 |
+ |
#[test]
|
|
722 |
+ |
fn a_stdin_larger_than_the_pipe_buffer_does_not_deadlock() {
|
|
723 |
+ |
// Both sides past 64 KiB, so neither fits in a buffer.
|
|
724 |
+ |
let stdin = "x".repeat(256 * 1024);
|
|
725 |
+ |
let (done, finished) = channel();
|
|
726 |
+ |
|
|
727 |
+ |
thread::spawn(move || {
|
|
728 |
+ |
let mut log = CommandLog::new();
|
|
729 |
+ |
let mut sequence = Sequence::new(vec![Stage::Run(
|
|
730 |
+ |
Invocation::new("sh")
|
|
731 |
+ |
.args(["-c", "seq 1 20000; cat >/dev/null; echo read-it-all"])
|
|
732 |
+ |
.stdin(Secret::new(stdin)),
|
|
733 |
+ |
)]);
|
|
734 |
+ |
drive(&mut sequence, &mut log);
|
|
735 |
+ |
let _ = done.send(sequence.output().last().cloned());
|
|
736 |
+ |
});
|
|
737 |
+ |
|
|
738 |
+ |
match finished.recv_timeout(Duration::from_secs(30)) {
|
|
739 |
+ |
Ok(last) => assert_eq!(last.as_deref(), Some("read-it-all")),
|
|
740 |
+ |
Err(_) => panic!("writing stdin deadlocked against the child's stdout"),
|
|
741 |
+ |
}
|
|
742 |
+ |
}
|
|
743 |
+ |
|
| 712 |
744 |
|
// A resolver that cannot make sense of the output fails the sequence with
|
| 713 |
745 |
|
// its own message, rather than letting a later command fail obscurely.
|
| 714 |
746 |
|
#[test]
|