dovecot-2.0: lib-signals: Redesigned how delayed signals are han...

dovecot at dovecot.org dovecot at dovecot.org
Wed Jul 22 00:15:00 EEST 2009


details:   http://hg.dovecot.org/dovecot-2.0/rev/028878f7063a
changeset: 9648:028878f7063a
user:      Timo Sirainen <tss at iki.fi>
date:      Tue Jul 21 17:14:41 2009 -0400
description:
lib-signals: Redesigned how delayed signals are handled.
Fixes signal handler hanging infinitely in write() when many signals were
sent rapidly.

diffstat:

1 file changed, 45 insertions(+), 42 deletions(-)
src/lib/lib-signals.c |   87 +++++++++++++++++++++++++------------------------

diffs (126 lines):

diff -r 22ede7ce7be4 -r 028878f7063a src/lib/lib-signals.c
--- a/src/lib/lib-signals.c	Tue Jul 21 15:18:49 2009 -0400
+++ b/src/lib/lib-signals.c	Tue Jul 21 17:14:41 2009 -0400
@@ -26,6 +26,9 @@ static int sig_pipe_fd[2] = { -1, -1 };
 
 static bool signals_initialized = FALSE;
 static struct io *io_sig = NULL;
+
+static siginfo_t pending_signals[MAX_SIGNAL_VALUE+1];
+static bool have_pending_signals = FALSE;
 
 const char *lib_signal_code_to_str(int signo, int sicode)
 {
@@ -70,7 +73,7 @@ static void sig_handler(int signo, sigin
 static void sig_handler(int signo, siginfo_t *si, void *context ATTR_UNUSED)
 {
 	struct signal_handler *h;
-	bool delayed_sent = FALSE;
+	char c = 0;
 
 	if (signo < 0 || signo > MAX_SIGNAL_VALUE)
 		return;
@@ -80,14 +83,16 @@ static void sig_handler(int signo, sigin
 	for (h = signal_handlers[signo]; h != NULL; h = h->next) {
 		if (!h->delayed)
 			h->handler(si, h->context);
-		else if (!delayed_sent) {
-			int saved_errno = errno;
-
-			if (write(sig_pipe_fd[1], si,
-				  sizeof(*si)) != sizeof(*si))
-				i_error("write(sigpipe) failed: %m");
-			delayed_sent = TRUE;
-			errno = saved_errno;
+		else if (pending_signals[signo].si_signo == 0) {
+			pending_signals[signo] = *si;
+			if (!have_pending_signals) {
+				int saved_errno = errno;
+
+				if (write(sig_pipe_fd[1], &c, 1) != 1)
+					i_error("write(sigpipe) failed: %m");
+				have_pending_signals = TRUE;
+				errno = saved_errno;
+			}
 		}
 	}
 }
@@ -101,47 +106,45 @@ static void sig_ignore(int signo ATTR_UN
 
 static void signal_read(void *context ATTR_UNUSED)
 {
-	siginfo_t signal_buf[10];
 	siginfo_t signals[MAX_SIGNAL_VALUE+1];
-	ssize_t i, ret;
+	sigset_t fullset, oldset;
+	struct signal_handler *h;
+	char buf[2];
 	int signo;
-
-	ret = read(sig_pipe_fd[0], signal_buf, sizeof(signal_buf));
+	ssize_t ret;
+
+	if (sigfillset(&fullset) < 0)
+		i_fatal("sigfillset() failed: %m");
+	if (sigprocmask(SIG_BLOCK, &fullset, &oldset) < 0)
+		i_fatal("sigprocmask() failed: %m");
+
+	ret = read(sig_pipe_fd[0], buf, sizeof(buf));
+	i_assert(ret <= 1);
 	if (ret > 0) {
-		if (ret % sizeof(siginfo_t) != 0)
-			i_fatal("read(sigpipe) returned partial data");
-		ret /= sizeof(siginfo_t);
-
-		/* get rid of duplicate signals */
-		memset(signals, 0, sizeof(signals));
-		for (i = 0; i < ret; i++) {
-			signo = signal_buf[i].si_signo;
-			if (signo > MAX_SIGNAL_VALUE) {
-				i_panic("sigpipe contains signal %d > %d",
-					signo, MAX_SIGNAL_VALUE);
-			}
-			signals[signo] = signal_buf[i];
-		}
-
-		/* call the delayed handlers */
-		for (signo = 0; signo < MAX_SIGNAL_VALUE; signo++) {
-			if (signals[signo].si_signo > 0) {
-				struct signal_handler *h =
-					signal_handlers[signo];
-
-				for (; h != NULL; h = h->next) {
-					if (h->delayed) {
-						h->handler(&signals[signo],
-							   h->context);
-					}
-				}
-			}
-		}
+		memcpy(signals, pending_signals, sizeof(signals));
+		memset(pending_signals, 0, sizeof(pending_signals));
+		have_pending_signals = FALSE;
 	} else if (ret < 0) {
 		if (errno != EAGAIN)
 			i_fatal("read(sigpipe) failed: %m");
 	} else {
 		i_fatal("read(sigpipe) failed: EOF");
+	}
+	if (sigprocmask(SIG_SETMASK, &oldset, NULL) < 0)
+		i_fatal("sigprocmask() failed: %m");
+
+	if (ret < 0)
+		return;
+
+	/* call the delayed handlers after signals are copied and unblocked */
+	for (signo = 0; signo < MAX_SIGNAL_VALUE; signo++) {
+		if (signals[signo].si_signo == 0)
+			continue;
+
+		for (h = signal_handlers[signo]; h != NULL; h = h->next) {
+			if (h->delayed)
+				h->handler(&signals[signo], h->context);
+		}
 	}
 }
 


More information about the dovecot-cvs mailing list