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.master
parent
b740e937df
commit
e9793b4bce
108
chat.c
108
chat.c
|
@ -25,9 +25,95 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sysexits.h>
|
#include <sysexits.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
#include "chat.h"
|
#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) {
|
static void sigint(int sig) {
|
||||||
(void)sig;
|
(void)sig;
|
||||||
input("/quit");
|
input("/quit");
|
||||||
|
@ -80,28 +166,14 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
inputTab();
|
inputTab();
|
||||||
|
|
||||||
signal(SIGINT, sigint);
|
|
||||||
uiInit();
|
uiInit();
|
||||||
uiLog(L"Traveling...");
|
uiLog(L"Traveling...");
|
||||||
uiDraw();
|
uiDraw();
|
||||||
|
|
||||||
int sock = ircConnect(host, port, pass, webirc);
|
fds.irc.fd = ircConnect(host, port, pass, webirc);
|
||||||
free(host);
|
free(host);
|
||||||
|
|
||||||
struct pollfd fds[2] = {
|
signal(SIGINT, sigint);
|
||||||
{ .fd = STDIN_FILENO, .events = POLLIN },
|
signal(SIGCHLD, sigchld);
|
||||||
{ .fd = sock, .events = POLLIN },
|
eventLoop();
|
||||||
};
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
2
chat.h
2
chat.h
|
@ -32,6 +32,8 @@ struct {
|
||||||
char *join;
|
char *join;
|
||||||
} chat;
|
} chat;
|
||||||
|
|
||||||
|
void spawn(char *const argv[]);
|
||||||
|
|
||||||
int ircConnect(
|
int ircConnect(
|
||||||
const char *host, const char *port, const char *pass, const char *webPass
|
const char *host, const char *port, const char *pass, const char *webPass
|
||||||
);
|
);
|
||||||
|
|
30
url.c
30
url.c
|
@ -64,32 +64,6 @@ void urlList(void) {
|
||||||
void urlOpen(size_t i) {
|
void urlOpen(size_t i) {
|
||||||
char *url = ring[(last - i) & (RING_LEN - 1)];
|
char *url = ring[(last - i) & (RING_LEN - 1)];
|
||||||
if (!url) return;
|
if (!url) return;
|
||||||
|
char *argv[] = { "open", url, NULL };
|
||||||
int fd[2];
|
spawn(argv);
|
||||||
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]);
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue