Mercurial > dovecot > core-2.2
changeset 19415:ecfd706b0e21
imap: Added extra assert checks to make sure command states are consistent.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Tue, 24 Nov 2015 13:41:58 +0200 |
parents | 20e51832875e |
children | d204b943dd21 |
files | src/imap/imap-client.c src/imap/imap-client.h |
diffstat | 2 files changed, 61 insertions(+), 13 deletions(-) [+] |
line wrap: on
line diff
--- 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; }
--- 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);