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