dovecot-2.2: imap: Added extra assert checks to make sure comman...

dovecot at dovecot.org dovecot at dovecot.org
Tue Nov 24 12:47:54 UTC 2015


details:   http://hg.dovecot.org/dovecot-2.2/rev/ecfd706b0e21
changeset: 19415:ecfd706b0e21
user:      Timo Sirainen <tss at iki.fi>
date:      Tue Nov 24 13:41:58 2015 +0200
description:
imap: Added extra assert checks to make sure command states are consistent.

diffstat:

 src/imap/imap-client.c |  72 ++++++++++++++++++++++++++++++++++++++++---------
 src/imap/imap-client.h |   2 +
 2 files changed, 61 insertions(+), 13 deletions(-)

diffs (121 lines):

diff -r 20e51832875e -r ecfd706b0e21 src/imap/imap-client.c
--- a/src/imap/imap-client.c	Tue Nov 24 13:40:12 2015 +0200
+++ b/src/imap/imap-client.c	Tue Nov 24 13:41:58 2015 +0200
@@ -799,37 +799,84 @@
 	}
 }
 
-void client_continue_pending_input(struct client *client)
+static void client_check_command_hangs(struct client *client)
 {
-	i_assert(!client->handling_input);
+	struct client_command_context *cmd;
+	unsigned int unfinished_count = 0;
+	bool have_wait_unfinished = FALSE;
 
+	for (cmd = client->command_queue; cmd != NULL; cmd = cmd->next) {
+		switch (cmd->state) {
+		case CLIENT_COMMAND_STATE_WAIT_INPUT:
+			i_assert(client->io != NULL);
+			unfinished_count++;
+			break;
+		case CLIENT_COMMAND_STATE_WAIT_OUTPUT:
+			i_assert((io_loop_find_fd_conditions(current_ioloop, client->fd_out) & IO_WRITE) != 0);
+			unfinished_count++;
+			break;
+		case CLIENT_COMMAND_STATE_WAIT_EXTERNAL:
+			unfinished_count++;
+			break;
+		case CLIENT_COMMAND_STATE_WAIT_UNAMBIGUITY:
+			have_wait_unfinished = TRUE;
+			break;
+		case CLIENT_COMMAND_STATE_WAIT_SYNC:
+			if ((io_loop_find_fd_conditions(current_ioloop, client->fd_out) & IO_WRITE) == 0)
+				have_wait_unfinished = TRUE;
+			else {
+				/* we have an output callback, which will be
+				   called soon and it'll run cmd_sync_delayed().
+				   FIXME: is this actually wanted? */
+			}
+			break;
+		case CLIENT_COMMAND_STATE_DONE:
+			i_unreached();
+		}
+	}
+	i_assert(!have_wait_unfinished || unfinished_count > 0);
+}
+
+static bool client_remove_pending_unambiguity(struct client *client)
+{
 	if (client->input_lock != NULL) {
 		/* there's a command that has locked the input */
 		struct client_command_context *cmd = client->input_lock;
 
 		if (cmd->state != CLIENT_COMMAND_STATE_WAIT_UNAMBIGUITY)
-			return;
+			return FALSE;
 
 		/* the command is waiting for existing ambiguity causing
 		   commands to finish. */
 		if (client_command_is_ambiguous(cmd)) {
 			/* we could be waiting for existing sync to finish */
 			if (!cmd_sync_delayed(client))
-				return;
+				return FALSE;
 			if (client_command_is_ambiguous(cmd))
-				return;
+				return FALSE;
 		}
 		cmd->state = CLIENT_COMMAND_STATE_WAIT_INPUT;
 	}
+	return TRUE;
+}
 
-	client_add_missing_io(client);
+void client_continue_pending_input(struct client *client)
+{
+	i_assert(!client->handling_input);
 
-	/* if there's unread data in buffer, handle it. */
-	if (i_stream_get_data_size(client->input) > 0 &&
-	    !client->disconnected) {
-		if (client_handle_input(client))
-			client_continue_pending_input(client);
+	/* this function is called at the end of I/O callbacks (and only there).
+	   fix up the command states and verify that they're correct. */
+	while (client_remove_pending_unambiguity(client)) {
+		client_add_missing_io(client);
+
+		/* if there's unread data in buffer, handle it. */
+		if (i_stream_get_data_size(client->input) == 0 ||
+		    client->disconnected)
+			break;
+		if (!client_handle_input(client))
+			break;
 	}
+	client_check_command_hangs(client);
 }
 
 /* Skip incoming data until newline is found,
@@ -1021,8 +1068,7 @@
 		cmd_sync_delayed(client);
 	} else if (client->input_lock->state == CLIENT_COMMAND_STATE_WAIT_UNAMBIGUITY) {
 		/* the command may be waiting for previous command to sync. */
-		if (cmd_sync_delayed(client))
-			client_continue_pending_input(client);
+		cmd_sync_delayed(client);
 	}
 	return TRUE;
 }
diff -r 20e51832875e -r ecfd706b0e21 src/imap/imap-client.h
--- a/src/imap/imap-client.h	Tue Nov 24 13:40:12 2015 +0200
+++ b/src/imap/imap-client.h	Tue Nov 24 13:41:58 2015 +0200
@@ -270,6 +270,8 @@
 void client_command_free(struct client_command_context **cmd);
 
 bool client_handle_unfinished_cmd(struct client_command_context *cmd);
+/* Handle any pending command input. This must be run at the end of all
+   I/O callbacks after they've (potentially) finished some commands. */
 void client_continue_pending_input(struct client *client);
 void client_add_missing_io(struct client *client);
 const char *client_stats(struct client *client);


More information about the dovecot-cvs mailing list