[2/2] process: Cancel all asynchronous jobs on reinit
diff mbox

Message ID 20170124045248.23804-2-sam@mendozajonas.com
State Accepted
Headers show

Commit Message

Samuel Mendoza-Jonas Jan. 24, 2017, 4:52 a.m. UTC
If an asynchronous job is running over a reinit, the process can return
and run its callback function after the reinit. This becomes a problem
if the callback function accesses pointers that were only valid before
the reinit (eg. device structs).
If a reinit is requested explicitly stop all active asynchronous jobs
and clear their callback functions before the reinit.

Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
---
 discover/device-handler.c |  3 +++
 lib/process/process.c     | 21 +++++++++++++++++++++
 lib/process/process.h     |  2 ++
 3 files changed, 26 insertions(+)

Patch
diff mbox

diff --git a/discover/device-handler.c b/discover/device-handler.c
index a3e5bdb..dd8249f 100644
--- a/discover/device-handler.c
+++ b/discover/device-handler.c
@@ -358,6 +358,9 @@  void device_handler_reinit(struct device_handler *handler)
 		handler->pending_boot_is_default = false;
 	}
 
+	/* Cancel any remaining async jobs */
+	process_stop_async_all();
+
 	/* free unresolved boot options */
 	list_for_each_entry_safe(&handler->unresolved_boot_options,
 			opt, tmp, list)
diff --git a/lib/process/process.c b/lib/process/process.c
index 93fd9c9..f7e5b8f 100644
--- a/lib/process/process.c
+++ b/lib/process/process.c
@@ -440,8 +440,29 @@  int process_run_async(struct process *process)
 
 void process_stop_async(struct process *process)
 {
+	/* Avoid signalling an old pid */
+	if (process->cancelled)
+		return;
+
 	pb_debug("process: sending SIGTERM to pid %d\n", process->pid);
 	kill(process->pid, SIGTERM);
+	process->cancelled = true;
+}
+
+void process_stop_async_all(void)
+{
+	struct process_info *procinfo;
+	struct process *process = NULL;
+
+	pb_debug("process: cancelling all async jobs\n");
+
+	list_for_each_entry(&procset->async_list, procinfo, async_list) {
+		process = &procinfo->process;
+		/* Ignore the process completion - callbacks may use stale data */
+		process->exit_cb = NULL;
+		process->stdout_cb = NULL;
+		process_stop_async(process);
+	}
 }
 
 int process_run_simple_argv(void *ctx, const char *argv[])
diff --git a/lib/process/process.h b/lib/process/process.h
index 65fdba8..f858b0e 100644
--- a/lib/process/process.h
+++ b/lib/process/process.h
@@ -45,6 +45,7 @@  struct process {
 
 	/* post-execution information */
 	int			exit_status;
+	bool			cancelled;
 };
 
 /* Process management system init. process_init must be called before
@@ -77,6 +78,7 @@  int process_run_simple(void *ctx, const char *name, ...)
 int process_run_async(struct process *process);
 
 void process_stop_async(struct process *process);
+void process_stop_async_all(void);
 
 /* helper function to determine if a process exited cleanly, with a non-zero
  * exit status */