about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2018-11-30 19:45:34 -0500
committerJune McEnroe <june@causal.agency>2018-11-30 19:45:34 -0500
commit414f928ac58278188638f8146a28a5747909de7b (patch)
tree8b5cf159990d66d7379f44a69e1f87526d1474bb
parentSeparate ircConnect and ircDisconnect (diff)
downloadcatgirl-414f928ac58278188638f8146a28a5747909de7b.tar.gz
catgirl-414f928ac58278188638f8146a28a5747909de7b.zip
Handle signals consistently in the event loop
-rw-r--r--chat.h3
-rw-r--r--event.c49
2 files changed, 39 insertions, 13 deletions
diff --git a/chat.h b/chat.h
index f0d396d..e8f9378 100644
--- a/chat.h
+++ b/chat.h
@@ -20,6 +20,7 @@
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdnoreturn.h>
 #include <time.h>
 #include <wchar.h>
 
@@ -43,7 +44,7 @@ void selfJoin(const char *join);
 
 void eventWait(const char *argv[static 2]);
 void eventPipe(const char *argv[static 2]);
-void eventLoop(void);
+noreturn void eventLoop(void);
 
 struct Tag {
 	size_t id;
diff --git a/event.c b/event.c
index 9f8c35e..f5d1f32 100644
--- a/event.c
+++ b/event.c
@@ -14,16 +14,18 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <assert.h>
 #include <err.h>
+#include <errno.h>
 #include <poll.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdnoreturn.h>
 #include <string.h>
 #include <sys/wait.h>
 #include <sysexits.h>
 #include <unistd.h>
-#include <errno.h>
 
 #include "chat.h"
 
@@ -86,8 +88,7 @@ static void pipeRead(void) {
 	}
 }
 
-static void sigchld(int sig) {
-	(void)sig;
+static void handleChild(void) {
 	int status;
 	pid_t pid = wait(&status);
 	if (pid < 0) err(EX_OSERR, "wait");
@@ -99,16 +100,31 @@ static void sigchld(int sig) {
 	spawn.wait = false;
 }
 
-static void sigint(int sig) {
-	(void)sig;
+static void handleInterrupt(void) {
 	input(TagStatus, "/quit");
 	uiExit();
 	exit(EX_OK);
 }
 
-void eventLoop(void) {
-	signal(SIGINT, sigint);
-	signal(SIGCHLD, sigchld);
+static sig_atomic_t sig[NSIG];
+static void handler(int n) {
+	sig[n] = 1;
+}
+
+noreturn void eventLoop(void) {
+	sigset_t mask;
+	sigemptyset(&mask);
+	struct sigaction sa = {
+		.sa_handler = handler,
+		.sa_mask = mask,
+		.sa_flags = SA_RESTART,
+	};
+	sigaction(SIGCHLD, &sa, NULL);
+	sigaction(SIGINT, &sa, NULL);
+
+	struct sigaction curses;
+	sigaction(SIGWINCH, &sa, &curses);
+	assert(!(curses.sa_flags & SA_SIGINFO));
 
 	int irc = ircConnect();
 
@@ -118,6 +134,17 @@ void eventLoop(void) {
 		{ -1, POLLIN, 0 },
 	};
 	for (;;) {
+		if (sig[SIGCHLD]) handleChild();
+		if (sig[SIGINT]) handleInterrupt();
+		if (sig[SIGWINCH]) {
+			curses.sa_handler(SIGWINCH);
+			uiRead();
+			uiDraw();
+		}
+		sig[SIGCHLD] = 0;
+		sig[SIGINT] = 0;
+		sig[SIGWINCH] = 0;
+
 		nfds_t nfds = 2;
 		if (spawn.wait) nfds = 1;
 		if (spawn.pipe) {
@@ -127,10 +154,8 @@ void eventLoop(void) {
 
 		int ready = poll(fds, nfds, -1);
 		if (ready < 0) {
-			if (errno != EINTR) err(EX_IOERR, "poll");
-			uiRead();
-			uiDraw();
-			continue;
+			if (errno == EINTR) continue;
+			err(EX_IOERR, "poll");
 		}
 
 		if (fds[0].revents) ircRead();