1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
|
/* $Id: xiosigchld.c,v 1.18 2005/03/13 12:20:43 gerhard Exp $ */
/* Copyright Gerhard Rieger 2001-2005 */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this is the source of the extended child signal handler */
#include "xiosysincludes.h"
#include "xioopen.h"
/*!! with socat, at most 4 exec children exist */
pid_t diedunknown1; /* child died before it is registered */
pid_t diedunknown2;
pid_t diedunknown3;
pid_t diedunknown4;
int xiosetsigchild(xiofile_t *xfd, int (*callback)(struct single *)) {
if (xfd->tag != XIO_TAG_DUAL) {
xfd->stream.sigchild = callback;
} else {
xfd->dual.stream[0]->stream.sigchild = callback;
xfd->dual.stream[1]->stream.sigchild = callback;
}
return 0;
}
/* exec'd child has died, perform appropriate changes to descriptor */
static int sigchld_stream(struct single *file) {
/*!! call back to application */
file->para.exec.pid = 0;
if (file->sigchild) {
return (*file->sigchild)(file);
}
return 0;
}
/* return 0 if socket is not responsible for deadchild */
static int xio_checkchild(xiofile_t *socket, int socknum, pid_t deadchild) {
int retval;
if (socket != NULL) {
if (socket->tag != XIO_TAG_DUAL) {
if ((socket->stream.howtoend == END_KILL ||
socket->stream.howtoend == END_CLOSE_KILL ||
socket->stream.howtoend == END_SHUTDOWN_KILL) &&
socket->stream.para.exec.pid == deadchild) {
Info2("exec'd process %d on socket %d terminated",
socket->stream.para.exec.pid, socknum);
sigchld_stream(&socket->stream);
return 1;
}
} else {
if (retval = xio_checkchild(socket->dual.stream[0], socknum, deadchild))
return retval;
else
return xio_checkchild(socket->dual.stream[1], socknum, deadchild);
}
}
return 0;
}
/* this is the signal handler for SIGCHLD */
/* the current socat/xio implementation knows two kinds of children:
exec/system addresses perform a fork: these children are registered and
there death influences the parents flow;
listen-socket with fork children: these children are "anonymous" and their
death does not effect the parent process (now; maybe we have a child
process counter later) */
void childdied(int signum) {
pid_t pid;
int _errno;
int status;
bool wassig = false;
int i;
_errno = errno; /* save current value; e.g., select() on Cygwin seems
to set it to EINTR _before_ handling the signal, and
then passes the value left by the signal handler to
the caller of select(), accept() etc. */
Info1("childdied(signum=%d)", signum);
do {
pid = Waitpid(-1, &status, WNOHANG);
if (pid == 0 || (pid < 0 && errno == ECHILD)) {
if (!wassig) {
Warn("waitpid(-1, {}, WNOHANG): no child process");
}
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;
}
/*! indent */
i = 0;
while (i < XIO_MAXSOCK) {
if (xio_checkchild(sock[i], i, pid)) break;
++i;
}
if (i == XIO_MAXSOCK) {
Info2("childdied(%d): cannot identify child %d", signum, pid);
if (diedunknown1 == 0) {
diedunknown1 = pid;
Debug("saving pid in diedunknown1");
} else if (diedunknown2 == 0) {
diedunknown2 = pid;
Debug("saving pid in diedunknown2");
} else if (diedunknown3 == 0) {
diedunknown3 = pid;
Debug("saving pid in diedunknown3");
} else {
diedunknown4 = pid;
Debug("saving pid in diedunknown4");
}
}
if (WIFEXITED(status)) {
if (WEXITSTATUS(status) == 0) {
Info2("waitpid(): child %d exited with status %d",
pid, WEXITSTATUS(status));
} else {
Warn2("waitpid(): child %d exited with status %d",
pid, WEXITSTATUS(status));
}
} else if (WIFSIGNALED(status)) {
Info2("waitpid(): child %d exited on signal %d",
pid, WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
Info2("waitpid(): child %d stopped on signal %d",
pid, WSTOPSIG(status));
} else {
Warn1("waitpid(): cannot determine status of child %d", pid);
}
#if !HAVE_SIGACTION
if (Signal(SIGCHLD, childdied) == SIG_ERR) {
Warn2("signal(SIGCHLD, %p): %s", childdied, strerror(errno));
}
#endif /* !HAVE_SIGACTION */
} while (1);
Info("childdied() finished");
errno = _errno;
}
|