@matheusbsbs / matheus-bagliano / commits / 4a16d07272
Fork 0

chain kill signals for cleanup functions

If a piece of code wanted to do some cleanup before exiting (e.g., cleaning up a lockfile or a tempfile), our usual strategy was to install a signal handler that did something like this: do_cleanup(); /* actual work */ signal(signo, SIG_DFL); /* restore previous behavior */ raise(signo); /* deliver signal, killing ourselves */ For a single handler, this works fine. However, if we want to clean up two _different_ things, we run into a problem. The most recently installed handler will run, but when it removes itself as a handler, it doesn't put back the first handler. This patch introduces sigchain, a tiny library for handling a stack of signal handlers. You sigchain_push each handler, and use sigchain_pop to restore whoever was before you in the stack. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Jan 22, 2009 at 01:02 UTC 4a16d072723b48699ea162da24eff05eba298834
12 files changed +125 -19
.gitignore
+1
@@ -152,6 +152,7 @@ test-match-trees
152 test-parse-options
153 test-path-utils
154 test-sha1
155 +test-sigchain
156 common-cmds.h
157 *.tar.gz
158 *.dsc
Makefile
+3
@@ -388,6 +388,7 @@ LIB_H += revision.h
388 LIB_H += run-command.h
389 LIB_H += sha1-lookup.h
390 LIB_H += sideband.h
391 +LIB_H += sigchain.h
392 LIB_H += strbuf.h
393 LIB_H += tag.h
394 LIB_H += transport.h
@@ -481,6 +482,7 @@ LIB_OBJS += sha1-lookup.o
482 LIB_OBJS += sha1_name.o
483 LIB_OBJS += shallow.o
484 LIB_OBJS += sideband.o
485 +LIB_OBJS += sigchain.o
486 LIB_OBJS += strbuf.o
487 LIB_OBJS += symlinks.o
488 LIB_OBJS += tag.o
@@ -1364,6 +1366,7 @@ TEST_PROGRAMS += test-match-trees$X
1366 TEST_PROGRAMS += test-parse-options$X
1367 TEST_PROGRAMS += test-path-utils$X
1368 TEST_PROGRAMS += test-sha1$X
1369 +TEST_PROGRAMS += test-sigchain$X
1370
1371 all:: $(TEST_PROGRAMS)
1372
builtin-clone.c
+3 -2
@@ -19,6 +19,7 @@
19 #include "strbuf.h"
20 #include "dir.h"
21 #include "pack-refs.h"
22 +#include "sigchain.h"
23
24 /*
25 * Overall FIXMEs:
@@ -288,7 +289,7 @@ static void remove_junk(void)
289 static void remove_junk_on_signal(int signo)
290 {
291 remove_junk();
291 - signal(SIGINT, SIG_DFL);
292 + sigchain_pop(signo);
293 raise(signo);
294 }
295
@@ -438,7 +439,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
439 }
440 junk_git_dir = git_dir;
441 atexit(remove_junk);
441 - signal(SIGINT, remove_junk_on_signal);
442 + sigchain_push(SIGINT, remove_junk_on_signal);
443
444 setenv(CONFIG_ENVIRONMENT, xstrdup(mkpath("%s/config", git_dir)), 1);
445
builtin-fetch--tool.c
+3 -2
@@ -2,6 +2,7 @@
2 #include "cache.h"
3 #include "refs.h"
4 #include "commit.h"
5 +#include "sigchain.h"
6
7 static char *get_stdin(void)
8 {
@@ -186,7 +187,7 @@ static void remove_keep(void)
187 static void remove_keep_on_signal(int signo)
188 {
189 remove_keep();
189 - signal(SIGINT, SIG_DFL);
190 + sigchain_pop(signo);
191 raise(signo);
192 }
193
@@ -245,7 +246,7 @@ static int fetch_native_store(FILE *fp,
246 char buffer[1024];
247 int err = 0;
248
248 - signal(SIGINT, remove_keep_on_signal);
249 + sigchain_push(SIGINT, remove_keep_on_signal);
250 atexit(remove_keep);
251
252 while (fgets(buffer, sizeof(buffer), stdin)) {
builtin-fetch.c
+3 -2
@@ -10,6 +10,7 @@
10 #include "transport.h"
11 #include "run-command.h"
12 #include "parse-options.h"
13 +#include "sigchain.h"
14
15 static const char * const builtin_fetch_usage[] = {
16 "git fetch [options] [<repository> <refspec>...]",
@@ -58,7 +59,7 @@ static void unlock_pack(void)
59 static void unlock_pack_on_signal(int signo)
60 {
61 unlock_pack();
61 - signal(SIGINT, SIG_DFL);
62 + sigchain_pop(signo);
63 raise(signo);
64 }
65
@@ -672,7 +673,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
673 ref_nr = j;
674 }
675
675 - signal(SIGINT, unlock_pack_on_signal);
676 + sigchain_push(SIGINT, unlock_pack_on_signal);
677 atexit(unlock_pack);
678 exit_code = do_fetch(transport,
679 parse_fetch_refspec(ref_nr, refs), ref_nr);
diff.c
+3 -2
@@ -12,6 +12,7 @@
12 #include "run-command.h"
13 #include "utf8.h"
14 #include "userdiff.h"
15 +#include "sigchain.h"
16
17 #ifdef NO_FAST_WORKING_DIRECTORY
18 #define FAST_WORKING_DIRECTORY 0
@@ -188,7 +189,7 @@ static void remove_tempfile(void)
189 static void remove_tempfile_on_signal(int signo)
190 {
191 remove_tempfile();
191 - signal(SIGINT, SIG_DFL);
192 + sigchain_pop(signo);
193 raise(signo);
194 }
195
@@ -1902,7 +1903,7 @@ static struct diff_tempfile *prepare_temp_file(const char *name,
1903
1904 if (!remove_tempfile_installed) {
1905 atexit(remove_tempfile);
1905 - signal(SIGINT, remove_tempfile_on_signal);
1906 + sigchain_push(SIGINT, remove_tempfile_on_signal);
1907 remove_tempfile_installed = 1;
1908 }
1909
http-push.c
+6 -5
@@ -10,6 +10,7 @@
10 #include "exec_cmd.h"
11 #include "remote.h"
12 #include "list-objects.h"
13 +#include "sigchain.h"
14
15 #include <expat.h>
16
@@ -1363,7 +1364,7 @@ static void remove_locks(void)
1364 static void remove_locks_on_signal(int signo)
1365 {
1366 remove_locks();
1366 - signal(signo, SIG_DFL);
1367 + sigchain_pop(signo);
1368 raise(signo);
1369 }
1370
@@ -2261,10 +2262,10 @@ int main(int argc, char **argv)
2262 goto cleanup;
2263 }
2264
2264 - signal(SIGINT, remove_locks_on_signal);
2265 - signal(SIGHUP, remove_locks_on_signal);
2266 - signal(SIGQUIT, remove_locks_on_signal);
2267 - signal(SIGTERM, remove_locks_on_signal);
2265 + sigchain_push(SIGINT, remove_locks_on_signal);
2266 + sigchain_push(SIGHUP, remove_locks_on_signal);
2267 + sigchain_push(SIGQUIT, remove_locks_on_signal);
2268 + sigchain_push(SIGTERM, remove_locks_on_signal);
2269
2270 /* Check whether the remote has server info files */
2271 remote->can_update_info_refs = 0;
lockfile.c
+7 -6
@@ -2,6 +2,7 @@
2 * Copyright (c) 2005, Junio C Hamano
3 */
4 #include "cache.h"
5 +#include "sigchain.h"
6
7 static struct lock_file *lock_file_list;
8 static const char *alternate_index_output;
@@ -24,7 +25,7 @@ static void remove_lock_file(void)
25 static void remove_lock_file_on_signal(int signo)
26 {
27 remove_lock_file();
27 - signal(signo, SIG_DFL);
28 + sigchain_pop(signo);
29 raise(signo);
30 }
31
@@ -136,11 +137,11 @@ static int lock_file(struct lock_file *lk, const char *path, int flags)
137 lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666);
138 if (0 <= lk->fd) {
139 if (!lock_file_list) {
139 - signal(SIGINT, remove_lock_file_on_signal);
140 - signal(SIGHUP, remove_lock_file_on_signal);
141 - signal(SIGTERM, remove_lock_file_on_signal);
142 - signal(SIGQUIT, remove_lock_file_on_signal);
143 - signal(SIGPIPE, remove_lock_file_on_signal);
140 + sigchain_push(SIGINT, remove_lock_file_on_signal);
141 + sigchain_push(SIGHUP, remove_lock_file_on_signal);
142 + sigchain_push(SIGTERM, remove_lock_file_on_signal);
143 + sigchain_push(SIGQUIT, remove_lock_file_on_signal);
144 + sigchain_push(SIGPIPE, remove_lock_file_on_signal);
145 atexit(remove_lock_file);
146 }
147 lk->owner = getpid();
sigchain.c new
+43
@@ -0,0 +1,43 @@
1 +#include "sigchain.h"
2 +#include "cache.h"
3 +
4 +#define SIGCHAIN_MAX_SIGNALS 32
5 +
6 +struct sigchain_signal {
7 + sigchain_fun *old;
8 + int n;
9 + int alloc;
10 +};
11 +static struct sigchain_signal signals[SIGCHAIN_MAX_SIGNALS];
12 +
13 +static void check_signum(int sig)
14 +{
15 + if (sig < 1 || sig >= SIGCHAIN_MAX_SIGNALS)
16 + die("BUG: signal out of range: %d", sig);
17 +}
18 +
19 +int sigchain_push(int sig, sigchain_fun f)
20 +{
21 + struct sigchain_signal *s = signals + sig;
22 + check_signum(sig);
23 +
24 + ALLOC_GROW(s->old, s->n + 1, s->alloc);
25 + s->old[s->n] = signal(sig, f);
26 + if (s->old[s->n] == SIG_ERR)
27 + return -1;
28 + s->n++;
29 + return 0;
30 +}
31 +
32 +int sigchain_pop(int sig)
33 +{
34 + struct sigchain_signal *s = signals + sig;
35 + check_signum(sig);
36 + if (s->n < 1)
37 + return 0;
38 +
39 + if (signal(sig, s->old[s->n - 1]) == SIG_ERR)
40 + return -1;
41 + s->n--;
42 + return 0;
43 +}
sigchain.h new
+9
@@ -0,0 +1,9 @@
1 +#ifndef SIGCHAIN_H
2 +#define SIGCHAIN_H
3 +
4 +typedef void (*sigchain_fun)(int);
5 +
6 +int sigchain_push(int sig, sigchain_fun f);
7 +int sigchain_pop(int sig);
8 +
9 +#endif /* SIGCHAIN_H */
t/t0005-signals.sh new
+22
@@ -0,0 +1,22 @@
1 +#!/bin/sh
2 +
3 +test_description='signals work as we expect'
4 +. ./test-lib.sh
5 +
6 +cat >expect <<EOF
7 +three
8 +two
9 +one
10 +EOF
11 +
12 +test_expect_success 'sigchain works' '
13 + test-sigchain >actual
14 + case "$?" in
15 + 130) true ;; # POSIX w/ SIGINT=2
16 + 3) true ;; # Windows
17 + *) false ;;
18 + esac &&
19 + test_cmp expect actual
20 +'
21 +
22 +test_done
test-sigchain.c new
+22
@@ -0,0 +1,22 @@
1 +#include "sigchain.h"
2 +#include "cache.h"
3 +
4 +#define X(f) \
5 +static void f(int sig) { \
6 + puts(#f); \
7 + fflush(stdout); \
8 + sigchain_pop(sig); \
9 + raise(sig); \
10 +}
11 +X(one)
12 +X(two)
13 +X(three)
14 +#undef X
15 +
16 +int main(int argc, char **argv) {
17 + sigchain_push(SIGINT, one);
18 + sigchain_push(SIGINT, two);
19 + sigchain_push(SIGINT, three);
20 + raise(SIGINT);
21 + return 0;
22 +}