fixed a bug where sub processes would become zombies because the master process caught SIGCHLD but did not wait()

This commit is contained in:
Gerhard Rieger 2008-02-01 23:38:16 +01:00
parent 1f5165b765
commit 3b3b004ff8
4 changed files with 84 additions and 1 deletions

View file

@ -22,6 +22,11 @@ corrections:
ABSTRACT-CONNECT, ABSTRACT-CLIENT, SOCKSA, SOCKS4A
(thanks to Fernanda G Weiden for reporting this problem)
fixed a bug where sub processes would become zombies because the master
process caught SIGCHLD but did not wait(). this affected addresses
UDP-RECVFROM, IP-RECVFROM, UNIX-RECVFROM, ABSTRACT-RECVFROM
(thanks to Evan Borgstrom for reporting this problem)
corrected some print statements and variable names
make uninstall did not uninstall procan

View file

@ -1 +1 @@
"1.6.0.0+execpty+servres+fd_setsize+udp_sigchld1"
"1.6.0.0+execpty+servres+fd_setsize+udp_sigchld"

50
test.sh
View file

@ -8029,6 +8029,56 @@ PORT=$((PORT+1))
N=$((N+1))
# there was a bug with udp-recvfrom and fork: terminating sub processes became
# zombies because the master process did caught SIGCHLD but did not wait()
NAME=UDP4RECVFROM_SIGCHLD
case "$TESTS" in
*%functions%*|*%ip4%*|*%udp%*|*%dgram%*|*%$NAME%*)
TEST="$NAME: test if UDP4-RECVFROM child becomes zombie"
# idea: run a udp-recvfrom process with fork and -T. Sent it one packet, so a
# sub process is forked off. Make some transfer and wait until the -T timeout
# is over. Now check for the child process: if it is zombie the test failed.
# Correct is that child process terminated
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
tdiff="$td/test$N.diff"
tsl=$PORT
ts="$LOCALHOST:$tsl"
da=$(date)
CMD1="$SOCAT $opts -T 0.5 UDP4-RECVFROM:$tsl,reuseaddr,fork PIPE"
CMD2="$SOCAT $opts - UDP4-SENDTO:$ts"
printf "test $F_n $TEST... " $N
$CMD1 >"$tf" 2>"${te}1" &
pid1=$!
waitudp4port $tsl 1
echo "$da" |$CMD2 >>"$tf" 2>>"${te}2"
rc2=$?
sleep 1
#read -p ">"
l="$(childprocess $pid1)"
kill $pid1 2>/dev/null; wait
if [ $rc2 -ne 0 ]; then
$PRINTF "$NO_RESULT\n" # already handled in test UDP4DGRAM
numCANT=$((numCANT+1))
elif ! echo "$da" |diff - "$tf" >"$tdiff"; then
$PRINTF "$NO_RESULT\n" # already handled in test UDP4DGRAMM
numCANT=$((numCANT+1))
elif $(isdefunct "$l"); then
$PRINTF "$FAILED: $SOCAT:\n"
echo "$CMD1 &"
echo "$CMD2"
cat "${te}1" "${te}2"
numFAIL=$((numFAIL+1))
else
$PRINTF "$OK\n"
if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi
numOK=$((numOK+1))
fi ;;
esac
PORT=$((PORT+1))
N=$((N+1))
echo "summary: $((N-1)) tests; $numOK ok, $numFAIL failed, $numCANT could not be performed"
if [ "$numFAIL" -gt 0 ]; then

View file

@ -512,9 +512,37 @@ int _xioopen_dgram_sendto(/* them is already in xfd->peersa */
static pid_t xio_waitingfor;
static bool xio_hashappened;
void xiosigaction_hasread(int signum, siginfo_t *siginfo, void *ucontext) {
pid_t pid;
int _errno;
int status = 0;
bool wassig = false;
Debug5("xiosigaction_hasread(%d, {%d,%d,%d,"F_pid"}, )",
signum, siginfo->si_signo, siginfo->si_errno, siginfo->si_code,
siginfo->si_pid);
_errno = errno;
do {
pid = Waitpid(-1, &status, WNOHANG);
if (pid == 0) {
Msg(wassig?E_INFO:E_WARN,
"waitpid(-1, {}, WNOHANG): no child has exited");
Info("childdied() finished");
errno = _errno;
return;
} else if (pid < 0 && errno == ECHILD) {
Msg1(wassig?E_INFO:E_WARN,
"waitpid(-1, {}, WNOHANG): %s", strerror(errno));
Info("childdied() finished");
errno = _errno;
return;
}
wassig = true;
if (pid < 0) {
Warn2("waitpid(-1, {%d}, WNOHANG): %s", status, strerror(errno));
Info("childdied() finished");
errno = _errno;
return;
}
} while (1);
if (xio_waitingfor == siginfo->si_pid) {
xio_hashappened = true;
}