=================================================================== RCS file: /cvs/mandoc/catman.c,v retrieving revision 1.26 retrieving revision 1.29 diff -u -p -r1.26 -r1.29 --- mandoc/catman.c 2025/06/29 23:51:40 1.26 +++ mandoc/catman.c 2025/06/30 12:23:42 1.29 @@ -1,4 +1,4 @@ -/* $Id: catman.c,v 1.26 2025/06/29 23:51:40 schwarze Exp $ */ +/* $Id: catman.c,v 1.29 2025/06/30 12:23:42 schwarze Exp $ */ /* * Copyright (c) 2017, 2025 Ingo Schwarze * Copyright (c) 2017 Michael Stapelberg @@ -25,6 +25,7 @@ #include #include +#include #if HAVE_ERR #include #endif @@ -35,6 +36,8 @@ #else #include "compat_fts.h" #endif +#include +#include #include #include #include @@ -42,16 +45,24 @@ #include int verbose_flag = 0; +sig_atomic_t got_signal = 0; int process_manpage(int, int, const char *); int process_tree(int, int); void run_mandocd(int, const char *, const char *) __attribute__((__noreturn__)); +void signal_handler(int); ssize_t sock_fd_write(int, int, int, int); void usage(void) __attribute__((__noreturn__)); void +signal_handler(int signum) +{ + got_signal = signum; +} + +void run_mandocd(int sockfd, const char *outtype, const char* defos) { char sockfdstr[10]; @@ -159,12 +170,16 @@ process_manpage(int srv_fd, int dstdir_fd, const char int process_tree(int srv_fd, int dstdir_fd) { + const struct timespec timeout = { 0, 10000000 }; /* 0.01 s */ + const int max_inflight = 16; + FTS *ftsp; FTSENT *entry; const char *argv[2]; const char *path; - int fatal; + int inflight, irc, decr, fatal; int gooddirs, baddirs, goodfiles, badfiles; + char dummy[1]; argv[0] = "."; argv[1] = (char *)NULL; @@ -175,9 +190,45 @@ process_tree(int srv_fd, int dstdir_fd) return -1; } - fatal = 0; - gooddirs = baddirs = goodfiles = badfiles = 0; - while (fatal == 0 && (entry = fts_read(ftsp)) != NULL) { + if (verbose_flag >= 2) { + warnx("allowing up to %d files in flight", max_inflight); + fflush(stderr); + } + inflight = fatal = gooddirs = baddirs = goodfiles = badfiles = 0; + while (fatal == 0 && got_signal == 0 && + (entry = fts_read(ftsp)) != NULL) { + if (inflight >= max_inflight) { + while (recv(srv_fd, dummy, sizeof(dummy), 0) == -1) { + if (errno != EAGAIN) { + warn("FATAL: recv"); + fatal = errno; + break; + } + nanosleep(&timeout, NULL); + } + if (fatal != 0) + break; + decr = 1; + while ((irc = recv(srv_fd, dummy, sizeof(dummy), + MSG_DONTWAIT)) > 0) + decr++; + assert(inflight >= decr); + if (verbose_flag >= 2 && decr > 1) { + warnx("files in flight: %d - %d = %d", + inflight, decr, inflight - decr); + fflush(stderr); + } + inflight -= decr; + if (irc == 0) { + errno = ECONNRESET; + inflight = -1; + } + if (errno != EAGAIN) { + warn("FATAL: recv"); + fatal = errno; + break; + } + } path = entry->fts_path + 2; switch (entry->fts_info) { case FTS_F: @@ -190,6 +241,7 @@ process_tree(int srv_fd, int dstdir_fd) break; default: goodfiles++; + inflight++; break; } break; @@ -232,10 +284,41 @@ process_tree(int srv_fd, int dstdir_fd) break; } } - if (fatal == 0 && (fatal = errno) != 0) + if (got_signal != 0) { + switch (got_signal) { + case SIGCHLD: + warnx("FATAL: mandocd child died: got SIGCHLD"); + break; + case SIGPIPE: + warnx("FATAL: mandocd child died: got SIGPIPE"); + break; + default: + warnx("FATAL: signal SIG%s", sys_signame[got_signal]); + break; + } + inflight = -1; + fatal = 1; + } else if (fatal == 0 && (fatal = errno) != 0) warn("FATAL: fts_read"); fts_close(ftsp); + if (verbose_flag >= 2 && inflight > 0) { + warnx("waiting for %d files in flight", inflight); + fflush(stderr); + } + while (inflight > 0) { + irc = recv(srv_fd, dummy, sizeof(dummy), 0); + if (irc > 0) + inflight--; + else if (irc == -1 && errno == EAGAIN) + nanosleep(&timeout, NULL); + else { + if (irc == 0) + errno = ECONNRESET; + warn("recv"); + inflight = -1; + } + } if (verbose_flag) warnx("processed %d files in %d directories", goodfiles, gooddirs); @@ -248,13 +331,15 @@ process_tree(int srv_fd, int dstdir_fd) if (fatal != 0) { warnx("processing aborted due to fatal error, " "results are probably incomplete"); + inflight = -1; } - return 0; + return inflight; } int main(int argc, char **argv) { + struct sigaction sa; const char *defos, *outtype; int srv_fds[2]; int dstdir_fd; @@ -272,7 +357,7 @@ main(int argc, char **argv) outtype = optarg; break; case 'v': - verbose_flag = 1; + verbose_flag += 1; break; default: usage(); @@ -297,6 +382,22 @@ main(int argc, char **argv) } usage(); } + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = &signal_handler; + sa.sa_flags = SA_NOCLDWAIT; + if (sigfillset(&sa.sa_mask) == -1) + err(1, "sigfillset"); + if (sigaction(SIGHUP, &sa, NULL) == -1) + err(1, "sigaction(SIGHUP)"); + if (sigaction(SIGINT, &sa, NULL) == -1) + err(1, "sigaction(SIGINT)"); + if (sigaction(SIGPIPE, &sa, NULL) == -1) + err(1, "sigaction(SIGPIPE)"); + if (sigaction(SIGTERM, &sa, NULL) == -1) + err(1, "sigaction(SIGTERM)"); + if (sigaction(SIGCHLD, &sa, NULL) == -1) + err(1, "sigaction(SIGCHLD)"); if (socketpair(AF_LOCAL, SOCK_STREAM, AF_UNSPEC, srv_fds) == -1) err(1, "socketpair");