Skip to content

Commit

Permalink
Use self-pipe instead of signal-blocking for SIGCHLD/SIGWINCH
Browse files Browse the repository at this point in the history
pselect() is broken on macOS. This isn't officially documented
anywhere but there are hints of it in this article:

https://daniel.haxx.se/blog/2016/10/11/poll-on-mac-10-12-is-broken/

To safely handle SIGCHLD/SIGWINCH without blocking them,
use the "self-pipe" trick, i.e. write to a pipe when those signals
occur and select() on the read-end of that pipe.

Fixes martanne#19
  • Loading branch information
rianhunter committed Sep 9, 2017
1 parent b45828d commit 1f1ed66
Showing 1 changed file with 60 additions and 10 deletions.
70 changes: 60 additions & 10 deletions dvtm.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ typedef struct {
int history;
int w;
int h;
volatile sig_atomic_t need_resize;
bool need_resize;
} Screen;

typedef struct {
Expand Down Expand Up @@ -248,6 +248,10 @@ static const char *shell;
static Register copyreg;
static volatile sig_atomic_t running = true;
static bool runinall = false;
static int sigwinch_pipe[] = {-1, -1};
static int sigchld_pipe[] = {-1, -1};

enum {PIPE_RD, PIPE_WR};

static void
eprint(const char *errstr, ...) {
Expand Down Expand Up @@ -698,6 +702,11 @@ get_client_by_coord(unsigned int x, unsigned int y) {

static void
sigchld_handler(int sig) {
write(sigchld_pipe[PIPE_WR], "\0", 1);
}

static void
handle_sigchld() {
int errsv = errno;
int status;
pid_t pid;
Expand Down Expand Up @@ -731,6 +740,11 @@ sigchld_handler(int sig) {

static void
sigwinch_handler(int sig) {
write(sigwinch_pipe[PIPE_WR], "\0", 1);
}

static void
handle_sigwinch() {
screen.need_resize = true;
}

Expand Down Expand Up @@ -939,6 +953,14 @@ getshell(void) {
return "/bin/sh";
}

static bool
set_blocking(int fd, bool blocking) {
int flags = fcntl(fd, F_GETFL, 0);
if (flags < 0) return false;
flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
return !fcntl(fd, F_SETFL, flags);
}

static void
setup(void) {
shell = getshell();
Expand All @@ -962,6 +984,23 @@ setup(void) {
colors[i].pair = vt_color_reserve(colors[i].fg, colors[i].bg);
}
resize_screen();

int *pipes[] = {&sigwinch_pipe[0], &sigchld_pipe[0]};
for (int i = 0; i < 2; ++i) {
int r = pipe(pipes[i]);
if (r < 0) {
perror("pipe()");
exit(EXIT_FAILURE);
}

for (int j = 0; j < 2; ++j) {
if (!set_blocking(pipes[i][j], false)) {
perror("fcntl()");
exit(EXIT_FAILURE);
}
}
}

struct sigaction sa;
memset(&sa, 0, sizeof sa);
sa.sa_flags = 0;
Expand Down Expand Up @@ -1815,20 +1854,13 @@ main(int argc, char *argv[]) {
KeyCombo keys;
unsigned int key_index = 0;
memset(keys, 0, sizeof(keys));
sigset_t emptyset, blockset;

setenv("DVTM", VERSION, 1);
if (!parse_args(argc, argv)) {
setup();
startup(NULL);
}

sigemptyset(&emptyset);
sigemptyset(&blockset);
sigaddset(&blockset, SIGWINCH);
sigaddset(&blockset, SIGCHLD);
sigprocmask(SIG_BLOCK, &blockset, NULL);

while (running) {
int r, nfds = 0;
fd_set rd;
Expand All @@ -1841,9 +1873,15 @@ main(int argc, char *argv[]) {
FD_ZERO(&rd);
FD_SET(STDIN_FILENO, &rd);

FD_SET(sigwinch_pipe[PIPE_RD], &rd);
nfds = MAX(nfds, sigwinch_pipe[PIPE_RD]);

FD_SET(sigchld_pipe[PIPE_RD], &rd);
nfds = MAX(nfds, sigchld_pipe[PIPE_RD]);

if (cmdfifo.fd != -1) {
FD_SET(cmdfifo.fd, &rd);
nfds = cmdfifo.fd;
nfds = MAX(nfds, cmdfifo.fd);
}

if (bar.fd != -1) {
Expand All @@ -1867,7 +1905,7 @@ main(int argc, char *argv[]) {
}

doupdate();
r = pselect(nfds + 1, &rd, NULL, NULL, NULL, &emptyset);
r = select(nfds + 1, &rd, NULL, NULL, NULL);

if (r < 0) {
if (errno == EINTR)
Expand Down Expand Up @@ -1903,6 +1941,18 @@ main(int argc, char *argv[]) {
continue;
}

if (FD_ISSET(sigwinch_pipe[PIPE_RD], &rd)) {
char buf[512];
while (read(sigwinch_pipe[PIPE_RD], &buf, sizeof(buf)) > 0);
handle_sigwinch();
}

if (FD_ISSET(sigchld_pipe[PIPE_RD], &rd)) {
char buf[512];
while (read(sigchld_pipe[PIPE_RD], &buf, sizeof(buf)) > 0);
handle_sigchld();
}

if (cmdfifo.fd != -1 && FD_ISSET(cmdfifo.fd, &rd))
handle_cmdfifo();

Expand Down

0 comments on commit 1f1ed66

Please sign in to comment.