From 893ea066f78a159bebbe099edf7eee085fd200d9 Mon Sep 17 00:00:00 2001 From: Martijn Dekker Date: Sun, 10 Jul 2022 06:16:52 +0200 Subject: [PATCH] Fix race condition in coprocess test with external 'cat' The race is between '$cat |&' and 'kill $pid'. In between, there are only a variable assignment and two buffered writes, so there is nothing that waits for the external 'cat' to finish forking, execve'ing and initialising -- meaning there is no guarantee it is ready to catch SIGTERM. This explains the hang; 'cat' misses the signal, continues to initialise, and simply waits for more input. src/cmd/ksh93/tests/coprocess.sh: - Actually read from the /bin/cat coprocess and verify that it works. This has the beneficial side effect of ensuring it is fully loaded and initialised before SIGTERMing it. Resolves: https://github.com/ksh93/ksh/issues/132 --- src/cmd/ksh93/tests/coprocess.sh | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/cmd/ksh93/tests/coprocess.sh b/src/cmd/ksh93/tests/coprocess.sh index cd06024b3..e3ded3e96 100755 --- a/src/cmd/ksh93/tests/coprocess.sh +++ b/src/cmd/ksh93/tests/coprocess.sh @@ -215,15 +215,17 @@ do trap - TERM [[ $sleep_pid ]] && kill $sleep_pid -# TODO: The /bin/cat iteration of this test is known to hang intermittently on Debian and -# derived systems (such as Ubuntu). See: https://github.com/ksh93/ksh/issues/132 - trap 'sleep_pid=; kill $pid; warning "$cat coprocess 2 hung (known issue, help us fix it at )"' TERM + trap 'sleep_pid=; kill $pid; err_exit "$cat coprocess 2 hung"' TERM { sleep 5; kill $$; } & sleep_pid=$! $cat |& pid=$! - print foo >&p 2> /dev/null || err_exit "first write of foo to $cat coprocess failed" - print foo >&p 2> /dev/null || err_exit "second write of foo to coprocess failed" + print foo1 >&p 2> /dev/null || err_exit "first write to $cat coprocess failed" + print foo2 >&p 2> /dev/null || err_exit "second write to $cat coprocess failed" + # avoid race between '$cat |&' initialising and 'kill $pid': read from the coprocess + # before 'kill' so that $cat is known to be fully initialised and ready to catch SIGTERM + read <&p && [[ $REPLY == foo1 ]] || err_exit "first read from $cat coprocess failed" + read <&p && [[ $REPLY == foo2 ]] || err_exit "second read from $cat coprocess failed" kill $pid wait $pid 2> /dev/null trap - TERM