Skip to content

Commit 91137e5

Browse files
committed
Use self-pipe instead of signal-blocking for SIGCHLD/SIGWINCH
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 #19
1 parent b45828d commit 91137e5

File tree

1 file changed

+60
-10
lines changed

1 file changed

+60
-10
lines changed

dvtm.c

+60-10
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ typedef struct {
5252
int history;
5353
int w;
5454
int h;
55-
volatile sig_atomic_t need_resize;
55+
bool need_resize;
5656
} Screen;
5757

5858
typedef struct {
@@ -248,6 +248,10 @@ static const char *shell;
248248
static Register copyreg;
249249
static volatile sig_atomic_t running = true;
250250
static bool runinall = false;
251+
static int sigwinch_pipe[] = {-1, -1};
252+
static int sigchld_pipe[] = {-1, -1};
253+
254+
enum {PIPE_RD, PIPE_WR};
251255

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

699703
static void
700704
sigchld_handler(int sig) {
705+
write(sigchld_pipe[PIPE_WR], "\0", 1);
706+
}
707+
708+
static void
709+
handle_sigchld() {
701710
int errsv = errno;
702711
int status;
703712
pid_t pid;
@@ -731,6 +740,11 @@ sigchld_handler(int sig) {
731740

732741
static void
733742
sigwinch_handler(int sig) {
743+
write(sigwinch_pipe[PIPE_WR], "\0", 1);
744+
}
745+
746+
static void
747+
handle_sigwinch() {
734748
screen.need_resize = true;
735749
}
736750

@@ -939,6 +953,14 @@ getshell(void) {
939953
return "/bin/sh";
940954
}
941955

956+
static bool
957+
set_blocking(int fd, bool blocking) {
958+
int flags = fcntl(fd, F_GETFL, 0);
959+
if (flags < 0) return false;
960+
flags = blocking ? (flags&~O_NONBLOCK) : (flags|O_NONBLOCK);
961+
return (fcntl(fd, F_SETFL, flags) == 0) ? true : false;
962+
}
963+
942964
static void
943965
setup(void) {
944966
shell = getshell();
@@ -962,6 +984,23 @@ setup(void) {
962984
colors[i].pair = vt_color_reserve(colors[i].fg, colors[i].bg);
963985
}
964986
resize_screen();
987+
988+
int *pipes[] = {&sigwinch_pipe[0], &sigchld_pipe[0]};
989+
for (int i = 0; i < 2; ++i) {
990+
int r = pipe(pipes[i]);
991+
if (r < 0) {
992+
perror("pipe()");
993+
exit(EXIT_FAILURE);
994+
}
995+
996+
for (int j = 0; j < 2; ++j) {
997+
if (!set_blocking(pipes[i][j], false)) {
998+
perror("fcntl()");
999+
exit(EXIT_FAILURE);
1000+
}
1001+
}
1002+
}
1003+
9651004
struct sigaction sa;
9661005
memset(&sa, 0, sizeof sa);
9671006
sa.sa_flags = 0;
@@ -1815,20 +1854,13 @@ main(int argc, char *argv[]) {
18151854
KeyCombo keys;
18161855
unsigned int key_index = 0;
18171856
memset(keys, 0, sizeof(keys));
1818-
sigset_t emptyset, blockset;
18191857

18201858
setenv("DVTM", VERSION, 1);
18211859
if (!parse_args(argc, argv)) {
18221860
setup();
18231861
startup(NULL);
18241862
}
18251863

1826-
sigemptyset(&emptyset);
1827-
sigemptyset(&blockset);
1828-
sigaddset(&blockset, SIGWINCH);
1829-
sigaddset(&blockset, SIGCHLD);
1830-
sigprocmask(SIG_BLOCK, &blockset, NULL);
1831-
18321864
while (running) {
18331865
int r, nfds = 0;
18341866
fd_set rd;
@@ -1841,9 +1873,15 @@ main(int argc, char *argv[]) {
18411873
FD_ZERO(&rd);
18421874
FD_SET(STDIN_FILENO, &rd);
18431875

1876+
FD_SET(sigwinch_pipe[PIPE_RD], &rd);
1877+
nfds = MAX(nfds, sigwinch_pipe[PIPE_RD]);
1878+
1879+
FD_SET(sigchld_pipe[PIPE_RD], &rd);
1880+
nfds = MAX(nfds, sigchld_pipe[PIPE_RD]);
1881+
18441882
if (cmdfifo.fd != -1) {
18451883
FD_SET(cmdfifo.fd, &rd);
1846-
nfds = cmdfifo.fd;
1884+
nfds = MAX(nfds, cmdfifo.fd);
18471885
}
18481886

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

18691907
doupdate();
1870-
r = pselect(nfds + 1, &rd, NULL, NULL, NULL, &emptyset);
1908+
r = select(nfds + 1, &rd, NULL, NULL, NULL);
18711909

18721910
if (r < 0) {
18731911
if (errno == EINTR)
@@ -1903,6 +1941,18 @@ main(int argc, char *argv[]) {
19031941
continue;
19041942
}
19051943

1944+
if (FD_ISSET(sigwinch_pipe[PIPE_RD], &rd)) {
1945+
char buf[512];
1946+
while (read(sigwinch_pipe[PIPE_RD], &buf, sizeof(buf)) > 0);
1947+
handle_sigwinch();
1948+
}
1949+
1950+
if (FD_ISSET(sigchld_pipe[PIPE_RD], &rd)) {
1951+
char buf[512];
1952+
while (read(sigchld_pipe[PIPE_RD], &buf, sizeof(buf)) > 0);
1953+
handle_sigchld();
1954+
}
1955+
19061956
if (cmdfifo.fd != -1 && FD_ISSET(cmdfifo.fd, &rd))
19071957
handle_cmdfifo();
19081958

0 commit comments

Comments
 (0)