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
|
#include <sys/types.h>
#include <unistd.h>
#include "sysdeps.h"
#include "unix.h"
#include "sig.h"
#include "selfpipe.h"
static int fds[2] = { -1, -1 };
/** Catch a signal and write it to the self-pipe.
*
* This routine can be used with sig_*_catch() to send other signals
* through the self-pipe.
*/
void selfpipe_catch_signal(int signal)
{
char c = signal;
write(fds[1], &c, 1);
}
/** Set up a self-pipe for catching child exit events.
*
* This function opens up a pipe within the program used to safely
* handle exiting child processes. Every time a child exits, a single
* byte is written to the pipe. The resulting file descriptor is
* statically assigned, so do not call this function more than once
* within a single program. The file descriptor is set to non-blocking
* mode to prevent blocking when reading from it.
*
* To use the file descriptor, use either \c poll or \c select to
* determine when it is readable. When it becomes readable, read the
* data written to it (and throw it away), and use \c wait or equivalent
* to catch the \c exit value from the child process(es).
*
* \return -1 if an error occurred, otherwise the return value is the
* file descriptor opened for reading.
*/
int selfpipe_init(void)
{
if (pipe(fds) == -1) return -1;
if (!nonblock_on(fds[0])
|| !cloexec_on(fds[0])
|| !nonblock_on(fds[1])
|| !cloexec_on(fds[1])) {
close(fds[0]);
close(fds[1]);
return -1;
}
sig_child_catch(selfpipe_catch_signal);
return fds[0];
}
/** Shut down the self-pipe. */
void selfpipe_close(void)
{
close(fds[0]);
close(fds[1]);
sig_child_default();
}
#ifdef SELFTEST_MAIN
#include <errno.h>
#include <signal.h>
void puti(const char* word, long i)
{
obuf_put2s(&outbuf, word, ": ");
obuf_puti(&outbuf, i);
obuf_endl(&outbuf);
}
MAIN
{
int buf;
int fd = selfpipe_init();
pid_t pid = getpid();
puti("FD[0] >= 0", fds[0] >= 0);
puti("FD[1] >= 0", fds[1] >= 0);
puti("FD[0] != FD[1]", fds[0] != fds[1]);
puti("Returned FD == FD[0]", fd == fds[0]);
puti("read before SIGCHLD", read(fd, &buf, sizeof buf));
puti("errno is EAGAIN", errno == EAGAIN);
kill(pid, SIGCHLD);
puti("read after SIGCHLD", read(fd, &buf, sizeof buf));
puti("second read", read(fd, &buf, sizeof buf));
kill(pid, SIGCHLD);
kill(pid, SIGCHLD);
puti("read after two SIGCHLDs", read(fd, &buf, sizeof buf));
puti("second read", read(fd, &buf, sizeof buf));
selfpipe_close();
puti("read after close", read(fd, &buf, sizeof buf));
puti("errno is EBADF", errno == EBADF);
}
#endif
#ifdef SELFTEST_EXP
FD[0] >= 0: 1
FD[1] >= 0: 1
FD[0] != FD[1]: 1
Returned FD == FD[0]: 1
read before SIGCHLD: -1
errno is EAGAIN: 1
read after SIGCHLD: 1
second read: -1
read after two SIGCHLDs: 2
second read: -1
read after close: -1
errno is EBADF: 1
#endif
|