dovecot-2.0: When writing to logs, ignore write()=EINTR failures...

dovecot at dovecot.org dovecot at dovecot.org
Tue Sep 14 19:39:50 EEST 2010


details:   http://hg.dovecot.org/dovecot-2.0/rev/5626fee3b7b9
changeset: 12118:5626fee3b7b9
user:      Timo Sirainen <tss at iki.fi>
date:      Tue Sep 14 17:39:40 2010 +0100
description:
When writing to logs, ignore write()=EINTR failures from non-terminal signals.
The previous code failed after 3 successive EINTRs, which was possible if
the process got a lot of signals (e.g. master process getting lots of SIGCHLD
signals).

diffstat:

 src/lib/failures.c |  44 +++++++++++++++++++++++++++++---------------
 1 files changed, 29 insertions(+), 15 deletions(-)

diffs (69 lines):

diff -r 7f364dafc675 -r 5626fee3b7b9 src/lib/failures.c
--- a/src/lib/failures.c	Tue Sep 14 17:38:08 2010 +0100
+++ b/src/lib/failures.c	Tue Sep 14 17:39:40 2010 +0100
@@ -5,6 +5,7 @@
 #include "str.h"
 #include "hostpid.h"
 #include "network.h"
+#include "lib-signals.h"
 #include "backtrace-string.h"
 #include "printf-format-fix.h"
 #include "write-full.h"
@@ -85,7 +86,8 @@
 	struct ioloop *ioloop;
 	struct io *io;
 	ssize_t ret;
-	unsigned int eintr_count = 0;
+	unsigned int prev_signal_term_counter = signal_term_counter;
+	unsigned int terminal_eintr_count = 0;
 
 	while ((ret = write(fd, data, len)) != (ssize_t)len) {
 		if (ret > 0) {
@@ -99,21 +101,33 @@
 			errno = ENOSPC;
 			return -1;
 		}
-		if (errno == EINTR && ++eintr_count < 3) {
-			/* we don't want to die because of this.
-			   try again a couple of times. */
-			continue;
+		switch (errno) {
+		case EAGAIN:
+			/* wait until we can write more. this can happen at
+			   least when writing to terminal, even if fd is
+			   blocking. */
+			ioloop = io_loop_create();
+			io = io_add(fd, IO_WRITE, log_fd_flush_stop, ioloop);
+			io_loop_run(ioloop);
+			io_remove(&io);
+			io_loop_destroy(&ioloop);
+			break;
+		case EINTR:
+			if (prev_signal_term_counter == signal_term_counter) {
+				/* non-terminal signal. ignore. */
+			} else if (terminal_eintr_count++ == 0) {
+				/* we'd rather not die in the middle of
+				   writing to log. try again once more */
+			} else {
+				/* received two terminal signals.
+				   someone wants us dead. */
+				return -1;
+			}
+			break;
+		default:
+			return -1;
 		}
-		if (errno != EAGAIN)
-			return -1;
-
-		/* wait until we can write more. this can happen at least
-		   when writing to terminal, even if fd is blocking. */
-		ioloop = io_loop_create();
-		io = io_add(fd, IO_WRITE, log_fd_flush_stop, ioloop);
-		io_loop_run(ioloop);
-		io_remove(&io);
-		io_loop_destroy(&ioloop);
+		prev_signal_term_counter = signal_term_counter;
 	}
 	return 0;
 }


More information about the dovecot-cvs mailing list