+static void prefork_loop(void)
+{
+ struct rlimit rl;
+
+ if (getrlimit(RLIMIT_NOFILE, &rl))
+ err(EXIT_FAILURE, "getrlimit");
+ my_fd_max = rl.rlim_cur;
+ if (my_fd_max < 72)
+ warnx("W: RLIMIT_NOFILE=%ld too low\n", my_fd_max);
+ my_fd_max -= 64;
+ nworker_hwm = nworker;
+ worker_pids = (pid_t *)xcalloc(nworker, sizeof(pid_t));
+
+ start_workers();
+
+ while (alive || living_workers()) {
+ char sbuf[64];
+ ssize_t n = read(pipefds[0], &sbuf, sizeof(sbuf));
+ if (n < 0) {
+ if (errno == EINTR) continue;
+ err(EXIT_FAILURE, "read");
+ } else if (n == 0) {
+ errx(EXIT_FAILURE, "read EOF");
+ }
+ do_sigchld();
+ for (ssize_t i = 0; i < n; i++) {
+ switch (sbuf[i]) {
+ case '.': break; // do_sigchld already called
+ case '-': do_sigttou(); break;
+ case '+': do_sigttin(); break;
+ case '#': parent_reopen_logs(); break;
+ default: errx(EXIT_FAILURE, "BUG: c=%c", sbuf[i]);
+ }
+ }
+ }
+}
+
+static void xsetfl(int fd, int newflags)
+{
+ int fl = fcntl(fd, F_GETFL);
+ if (fl == -1) err(EXIT_FAILURE, "F_GETFL");
+ if (fcntl(fd, F_SETFL, fl | newflags))
+ err(EXIT_FAILURE, "F_SETFL");
+}
+
+static void dynfork_dispatch(void) // lei-only
+{
+ sigset_t old;
+ CHECK(int, 0, sigprocmask(SIG_SETMASK, &fullset, &old));
+ pid_t pid = fork();
+ if (pid < 0)
+ err(EXIT_FAILURE, "fork");
+ if (pid > 0) {
+ CHECK(int, 0, sigprocmask(SIG_SETMASK, &old, NULL));
+ return; // don't even care about the PID
+ }
+ if (pid == 0) {
+ xclose(pipefds[0]);
+ xclose(pipefds[1]);
+ XSIGNAL(SIGCHLD, SIG_DFL);
+ XSIGNAL(SIGTTIN, SIG_IGN);
+ XSIGNAL(SIGTTOU, SIG_IGN);
+ XSIGNAL(SIGUSR1, SIG_DFL);
+ XSIGNAL(SIGTERM, SIG_DFL);
+ (void)recv_once();
+ exit(0);
+ }
+}
+
+static void dynfork_check_sigs(void)
+{
+ char sbuf[64];
+ ssize_t n = read(pipefds[0], &sbuf, sizeof(sbuf));
+ if (n < 0) {
+ if (errno == EAGAIN) return; // spurious wakeup
+ err(EXIT_FAILURE, "read");
+ } else if (n == 0) {
+ errx(EXIT_FAILURE, "read EOF");
+ }
+ do_sigchld();
+ for (ssize_t i = 0; i < n; i++) {
+ switch (sbuf[i]) {
+ case '.': break; // do_sigchld already called
+ case '-': break; // ignore (TTOU|TTIN)
+ case '+': break;
+ case '#': reopen_logs(); break;
+ default: errx(EXIT_FAILURE, "BUG: c=%c", sbuf[i]);
+ }
+ }
+}
+
+static void dynfork_loop(void) // for lei
+{
+ struct pollfd pfd[2];
+ pfd[0].fd = sock_fd;
+ pfd[1].fd = pipefds[0];
+ pfd[0].events = pfd[1].events = POLLIN;
+
+ xsetfl(pipefds[0], O_NONBLOCK);
+ xsetfl(sock_fd, O_NONBLOCK);
+ my_fd_max = 128; // just keep srch_init happy
+
+ while (alive) {
+ int rc = poll(pfd, MY_ARRAY_SIZE(pfd), -1);
+
+ if (rc < 0) {
+ if (errno == EINTR) continue;
+ err(EXIT_FAILURE, "poll");
+ } else {
+ if (pfd[0].revents & POLLIN)
+ dynfork_dispatch();
+ if (pfd[1].revents & POLLIN)
+ dynfork_check_sigs();
+ }
+ }
+}
+