changeset 22996:fd4e4582ff6c

lib-master: ipc-client: Support aborting commands
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Thu, 05 Jul 2018 14:42:30 +0300
parents 80ba6e7551ee
children 0a2614a38fc6
files src/lib-master/ipc-client.c src/lib-master/ipc-client.h
diffstat 2 files changed, 44 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-master/ipc-client.c	Thu Jul 05 14:41:38 2018 +0300
+++ b/src/lib-master/ipc-client.c	Thu Jul 05 14:42:30 2018 +0300
@@ -29,6 +29,7 @@
 	struct istream *input;
 	struct ostream *output;
 	struct ipc_client_cmd *cmds_head, *cmds_tail;
+	unsigned int aborted_cmds_count;
 };
 
 static void ipc_client_disconnect(struct ipc_client *client);
@@ -39,7 +40,10 @@
 	enum ipc_client_cmd_state state;
 	bool disconnect = FALSE;
 
-	if (cmd == NULL) {
+	if (client->aborted_cmds_count > 0) {
+		/* the command was already aborted */
+		cmd = NULL;
+	} else if (cmd == NULL) {
 		i_error("IPC proxy sent unexpected input: %s", line);
 		return;
 	}
@@ -62,10 +66,17 @@
 		break;
 	}
 
-	if (state != IPC_CLIENT_CMD_STATE_REPLY)
-		DLLIST2_REMOVE(&client->cmds_head, &client->cmds_tail, cmd);
-	cmd->callback(state, line, cmd->context);
-	i_free(cmd);
+	if (state != IPC_CLIENT_CMD_STATE_REPLY) {
+		if (cmd != NULL)
+			DLLIST2_REMOVE(&client->cmds_head,
+				       &client->cmds_tail, cmd);
+		else
+			client->aborted_cmds_count--;
+	}
+	if (cmd != NULL) {
+		cmd->callback(state, line, cmd->context);
+		i_free(cmd);
+	}
 	if (disconnect)
 		ipc_client_disconnect(client);
 }
@@ -159,8 +170,9 @@
 	timeout_remove(&client->to_failed);
 }
 
-void ipc_client_cmd(struct ipc_client *client, const char *cmd,
-		    ipc_client_callback_t *callback, void *context)
+struct ipc_client_cmd *
+ipc_client_cmd(struct ipc_client *client, const char *cmd,
+	       ipc_client_callback_t *callback, void *context)
 {
 	struct ipc_client_cmd *ipc_cmd;
 	struct const_iovec iov[2];
@@ -185,4 +197,24 @@
 		iov[1].iov_len = 1;
 		o_stream_nsendv(client->output, iov, N_ELEMENTS(iov));
 	}
+	return ipc_cmd;
 }
+
+void ipc_client_cmd_abort(struct ipc_client *client,
+			  struct ipc_client_cmd **_cmd)
+{
+	struct ipc_client_cmd *cmd = *_cmd;
+
+	*_cmd = NULL;
+	cmd->callback = NULL;
+	/* Free the command only if it's the oldest. Free also other such
+	   commands in case they were aborted earlier. */
+	while (client->cmds_head != NULL &&
+	       client->cmds_head->callback == NULL) {
+		struct ipc_client_cmd *head = client->cmds_head;
+
+		client->aborted_cmds_count++;
+		DLLIST2_REMOVE(&client->cmds_head, &client->cmds_tail, head);
+		i_free(head);
+	}
+}
--- a/src/lib-master/ipc-client.h	Thu Jul 05 14:41:38 2018 +0300
+++ b/src/lib-master/ipc-client.h	Thu Jul 05 14:42:30 2018 +0300
@@ -14,8 +14,11 @@
 ipc_client_init(const char *ipc_socket_path);
 void ipc_client_deinit(struct ipc_client **client);
 
-void ipc_client_cmd(struct ipc_client *client, const char *cmd,
-		    ipc_client_callback_t *callback, void *context)
+struct ipc_client_cmd *
+ipc_client_cmd(struct ipc_client *client, const char *cmd,
+	       ipc_client_callback_t *callback, void *context)
 	ATTR_NULL(4);
+void ipc_client_cmd_abort(struct ipc_client *client,
+			  struct ipc_client_cmd **cmd);
 
 #endif