File: selfpipe.c

package info (click to toggle)
bglibs 2.04%2Bdfsg-8
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 3,468 kB
  • sloc: ansic: 15,821; perl: 674; sh: 63; makefile: 29
file content (107 lines) | stat: -rw-r--r-- 2,841 bytes parent folder | download | duplicates (3)
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