From e9793b4bceac009e09598a7b98048b604c745daa Mon Sep 17 00:00:00 2001 From: Curtis McEnroe Date: Fri, 10 Aug 2018 13:36:00 -0400 Subject: Move process spawning onto the event loop Child processes weren't being reaped before, either. I wanted to have a function called readEmAndReap but the reaping should actually happen in a signal handler. --- chat.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----------- chat.h | 2 ++ url.c | 30 ++---------------- 3 files changed, 94 insertions(+), 46 deletions(-) diff --git a/chat.c b/chat.c index 41fc3cb..332cfd6 100644 --- a/chat.c +++ b/chat.c @@ -25,9 +25,95 @@ #include #include #include +#include #include "chat.h" +static union { + struct { + struct pollfd ui; + struct pollfd irc; + struct pollfd pipe; + }; + struct pollfd fds[3]; +} fds = { + .ui = { .events = POLLIN, .fd = STDIN_FILENO }, + .irc = { .events = POLLIN }, + .pipe = { .events = 0 }, +}; + +void spawn(char *const argv[]) { + if (fds.pipe.events) { + uiLog(L"spawn: existing pipe"); + return; + } + + int rw[2]; + int error = pipe(rw); + if (error) err(EX_OSERR, "pipe"); + + pid_t pid = fork(); + if (pid < 0) err(EX_OSERR, "fork"); + if (!pid) { + close(rw[0]); + close(STDIN_FILENO); + dup2(rw[1], STDOUT_FILENO); + dup2(rw[1], STDERR_FILENO); + close(rw[1]); + execvp(argv[0], argv); + perror(argv[0]); + exit(EX_CONFIG); + } + + close(rw[1]); + fds.pipe.fd = rw[0]; + fds.pipe.events = POLLIN; +} + +static void pipeRead(void) { + char buf[256]; + ssize_t len = read(fds.pipe.fd, buf, sizeof(buf) - 1); + if (len < 0) err(EX_IOERR, "read"); + if (len) { + buf[len] = '\0'; + len = strcspn(buf, "\n"); + uiFmt("%.*s", (int)len, buf); + } else { + close(fds.pipe.fd); + fds.pipe.events = 0; + fds.pipe.revents = 0; + } +} + +static void eventLoop(void) { + for (;;) { + uiDraw(); + + int n = poll(fds.fds, (fds.pipe.events ? 3 : 2), -1); + if (n < 0) { + if (errno != EINTR) err(EX_IOERR, "poll"); + uiRead(); + continue; + } + + if (fds.ui.revents) uiRead(); + if (fds.irc.revents) ircRead(); + if (fds.pipe.revents) pipeRead(); + } +} + +static void sigchld(int sig) { + (void)sig; + int status; + pid_t pid = wait(&status); + if (pid < 0) err(EX_OSERR, "wait"); + if (WIFEXITED(status) && WEXITSTATUS(status)) { + uiFmt("spawn: exit %d", WEXITSTATUS(status)); + } else if (WIFSIGNALED(status)) { + uiFmt("spawn: signal %d", WTERMSIG(status)); + } +} + static void sigint(int sig) { (void)sig; input("/quit"); @@ -80,28 +166,14 @@ int main(int argc, char *argv[]) { inputTab(); - signal(SIGINT, sigint); uiInit(); uiLog(L"Traveling..."); uiDraw(); - int sock = ircConnect(host, port, pass, webirc); + fds.irc.fd = ircConnect(host, port, pass, webirc); free(host); - struct pollfd fds[2] = { - { .fd = STDIN_FILENO, .events = POLLIN }, - { .fd = sock, .events = POLLIN }, - }; - for (;;) { - int nfds = poll(fds, 2, -1); - if (nfds < 0) { - if (errno != EINTR) err(EX_IOERR, "poll"); - fds[0].revents = POLLIN; - fds[1].revents = 0; - } - - if (fds[0].revents) uiRead(); - if (fds[1].revents) ircRead(); - uiDraw(); - } + signal(SIGINT, sigint); + signal(SIGCHLD, sigchld); + eventLoop(); } diff --git a/chat.h b/chat.h index fce1ba2..9a1b855 100644 --- a/chat.h +++ b/chat.h @@ -32,6 +32,8 @@ struct { char *join; } chat; +void spawn(char *const argv[]); + int ircConnect( const char *host, const char *port, const char *pass, const char *webPass ); diff --git a/url.c b/url.c index 33652ff..1c57126 100644 --- a/url.c +++ b/url.c @@ -64,32 +64,6 @@ void urlList(void) { void urlOpen(size_t i) { char *url = ring[(last - i) & (RING_LEN - 1)]; if (!url) return; - - int fd[2]; - int error = pipe(fd); - if (error) err(EX_OSERR, "pipe"); - - pid_t pid = fork(); - if (pid < 0) err(EX_OSERR, "fork"); - - if (!pid) { - close(STDIN_FILENO); - dup2(fd[1], STDOUT_FILENO); - dup2(fd[1], STDERR_FILENO); - execlp("open", "open", url, NULL); - perror("open"); - exit(EX_CONFIG); - } - close(fd[1]); - - // FIXME: This should technically go on the main event loop. - char buf[256]; - ssize_t len = read(fd[0], buf, sizeof(buf) - 1); - if (len < 0) err(EX_IOERR, "read"); - if (len) { - buf[len] = '\0'; - len = strcspn(buf, "\n"); - uiFmt("%.*s", (int)len, buf); - } - close(fd[0]); + char *argv[] = { "open", url, NULL }; + spawn(argv); } -- cgit 1.4.1