run-command: add clean_on_exit_handler
Some processes might want to perform cleanup tasks before Git kills them due to the 'clean_on_exit' flag. Let's give them an interface for doing this. The feature is used in a subsequent patch. Please note, that the cleanup callback is not executed if Git dies of a signal. The reason is that only "async-signal-safe" functions would be allowed to be call in that case. Since we cannot control what functions the callback will use, we will not support the case. See 507d7804 for more details. Helped-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Lars Schneider <larsxschneider@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Lars Schneider committed
Oct 16, 2016 at 16:20 UTC
ac2fbaa674ce3d5b5faf6a83f88cc4af1654f9cd
2 files changed
+20
-4
run-command.c
+18
-4
@@ -21,6 +21,7 @@ void child_process_clear(struct child_process *child)
21
22
struct child_to_clean {
23
pid_t pid;
24
+ struct child_process *process;
25
struct child_to_clean *next;
26
};
27
static struct child_to_clean *children_to_clean;
@@ -31,6 +32,18 @@ static void cleanup_children(int sig, int in_signal)
32
while (children_to_clean) {
33
struct child_to_clean *p = children_to_clean;
34
children_to_clean = p->next;
35
+
36
+ if (p->process && !in_signal) {
37
+ struct child_process *process = p->process;
38
+ if (process->clean_on_exit_handler) {
39
+ trace_printf(
40
+ "trace: run_command: running exit handler for pid %"
41
+ PRIuMAX, (uintmax_t)p->pid
42
+ );
43
+ process->clean_on_exit_handler(process);
44
+ }
45
+ }
46
+
47
kill(p->pid, sig);
48
if (!in_signal)
49
free(p);
@@ -49,10 +62,11 @@ static void cleanup_children_on_exit(void)
62
cleanup_children(SIGTERM, 0);
63
}
64
52
-static void mark_child_for_cleanup(pid_t pid)
65
+static void mark_child_for_cleanup(pid_t pid, struct child_process *process)
66
{
67
struct child_to_clean *p = xmalloc(sizeof(*p));
68
p->pid = pid;
69
+ p->process = process;
70
p->next = children_to_clean;
71
children_to_clean = p;
72
@@ -422,7 +436,7 @@ fail_pipe:
436
if (cmd->pid < 0)
437
error_errno("cannot fork() for %s", cmd->argv[0]);
438
else if (cmd->clean_on_exit)
425
- mark_child_for_cleanup(cmd->pid);
439
+ mark_child_for_cleanup(cmd->pid, cmd);
440
441
/*
442
* Wait for child's execvp. If the execvp succeeds (or if fork()
@@ -483,7 +497,7 @@ fail_pipe:
497
if (cmd->pid < 0 && (!cmd->silent_exec_failure || errno != ENOENT))
498
error_errno("cannot spawn %s", cmd->argv[0]);
499
if (cmd->clean_on_exit && cmd->pid >= 0)
486
- mark_child_for_cleanup(cmd->pid);
500
+ mark_child_for_cleanup(cmd->pid, cmd);
501
502
argv_array_clear(&nargv);
503
cmd->argv = sargv;
@@ -765,7 +779,7 @@ int start_async(struct async *async)
779
exit(!!async->proc(proc_in, proc_out, async->data));
780
}
781
768
- mark_child_for_cleanup(async->pid);
782
+ mark_child_for_cleanup(async->pid, NULL);
783
784
if (need_in)
785
close(fdin[0]);
run-command.h
+2
@@ -43,6 +43,8 @@ struct child_process {
43
unsigned stdout_to_stderr:1;
44
unsigned use_shell:1;
45
unsigned clean_on_exit:1;
46
+ void (*clean_on_exit_handler)(struct child_process *process);
47
+ void *clean_on_exit_handler_cbdata;
48
};
49
50
#define CHILD_PROCESS_INIT { NULL, ARGV_ARRAY_INIT, ARGV_ARRAY_INIT }