mirror of
https://github.com/git/git
synced 2024-08-27 11:39:22 +00:00
Merge branch 'jk/signal-cleanup'
* jk/signal-cleanup: t0005: use SIGTERM for sigchain test pager: do wait_for_pager on signal death refactor signal handling for cleanup functions chain kill signals for cleanup functions diff: refactor tempfile cleanup handling Windows: Fix signal numbers
This commit is contained in:
commit
fa5bc8abb3
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -153,6 +153,7 @@ test-match-trees
|
|||
test-parse-options
|
||||
test-path-utils
|
||||
test-sha1
|
||||
test-sigchain
|
||||
common-cmds.h
|
||||
*.tar.gz
|
||||
*.dsc
|
||||
|
|
3
Makefile
3
Makefile
|
@ -391,6 +391,7 @@ LIB_H += revision.h
|
|||
LIB_H += run-command.h
|
||||
LIB_H += sha1-lookup.h
|
||||
LIB_H += sideband.h
|
||||
LIB_H += sigchain.h
|
||||
LIB_H += strbuf.h
|
||||
LIB_H += tag.h
|
||||
LIB_H += transport.h
|
||||
|
@ -484,6 +485,7 @@ LIB_OBJS += sha1-lookup.o
|
|||
LIB_OBJS += sha1_name.o
|
||||
LIB_OBJS += shallow.o
|
||||
LIB_OBJS += sideband.o
|
||||
LIB_OBJS += sigchain.o
|
||||
LIB_OBJS += strbuf.o
|
||||
LIB_OBJS += symlinks.o
|
||||
LIB_OBJS += tag.o
|
||||
|
@ -1374,6 +1376,7 @@ TEST_PROGRAMS += test-match-trees$X
|
|||
TEST_PROGRAMS += test-parse-options$X
|
||||
TEST_PROGRAMS += test-path-utils$X
|
||||
TEST_PROGRAMS += test-sha1$X
|
||||
TEST_PROGRAMS += test-sigchain$X
|
||||
|
||||
all:: $(TEST_PROGRAMS)
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "strbuf.h"
|
||||
#include "dir.h"
|
||||
#include "pack-refs.h"
|
||||
#include "sigchain.h"
|
||||
|
||||
/*
|
||||
* Overall FIXMEs:
|
||||
|
@ -288,7 +289,7 @@ static void remove_junk(void)
|
|||
static void remove_junk_on_signal(int signo)
|
||||
{
|
||||
remove_junk();
|
||||
signal(SIGINT, SIG_DFL);
|
||||
sigchain_pop(signo);
|
||||
raise(signo);
|
||||
}
|
||||
|
||||
|
@ -441,7 +442,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
|||
}
|
||||
junk_git_dir = git_dir;
|
||||
atexit(remove_junk);
|
||||
signal(SIGINT, remove_junk_on_signal);
|
||||
sigchain_push_common(remove_junk_on_signal);
|
||||
|
||||
setenv(CONFIG_ENVIRONMENT, xstrdup(mkpath("%s/config", git_dir)), 1);
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "cache.h"
|
||||
#include "refs.h"
|
||||
#include "commit.h"
|
||||
#include "sigchain.h"
|
||||
|
||||
static char *get_stdin(void)
|
||||
{
|
||||
|
@ -186,7 +187,7 @@ static void remove_keep(void)
|
|||
static void remove_keep_on_signal(int signo)
|
||||
{
|
||||
remove_keep();
|
||||
signal(SIGINT, SIG_DFL);
|
||||
sigchain_pop(signo);
|
||||
raise(signo);
|
||||
}
|
||||
|
||||
|
@ -245,7 +246,7 @@ static int fetch_native_store(FILE *fp,
|
|||
char buffer[1024];
|
||||
int err = 0;
|
||||
|
||||
signal(SIGINT, remove_keep_on_signal);
|
||||
sigchain_push_common(remove_keep_on_signal);
|
||||
atexit(remove_keep);
|
||||
|
||||
while (fgets(buffer, sizeof(buffer), stdin)) {
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "transport.h"
|
||||
#include "run-command.h"
|
||||
#include "parse-options.h"
|
||||
#include "sigchain.h"
|
||||
|
||||
static const char * const builtin_fetch_usage[] = {
|
||||
"git fetch [options] [<repository> <refspec>...]",
|
||||
|
@ -58,7 +59,7 @@ static void unlock_pack(void)
|
|||
static void unlock_pack_on_signal(int signo)
|
||||
{
|
||||
unlock_pack();
|
||||
signal(SIGINT, SIG_DFL);
|
||||
sigchain_pop(signo);
|
||||
raise(signo);
|
||||
}
|
||||
|
||||
|
@ -672,7 +673,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
|
|||
ref_nr = j;
|
||||
}
|
||||
|
||||
signal(SIGINT, unlock_pack_on_signal);
|
||||
sigchain_push_common(unlock_pack_on_signal);
|
||||
atexit(unlock_pack);
|
||||
exit_code = do_fetch(transport,
|
||||
parse_fetch_refspec(ref_nr, refs), ref_nr);
|
||||
|
|
|
@ -21,12 +21,12 @@ typedef int pid_t;
|
|||
#define WEXITSTATUS(x) ((x) & 0xff)
|
||||
#define WIFSIGNALED(x) ((unsigned)(x) > 259)
|
||||
|
||||
#define SIGKILL 0
|
||||
#define SIGCHLD 0
|
||||
#define SIGPIPE 0
|
||||
#define SIGHUP 0
|
||||
#define SIGQUIT 0
|
||||
#define SIGALRM 100
|
||||
#define SIGHUP 1
|
||||
#define SIGQUIT 3
|
||||
#define SIGKILL 9
|
||||
#define SIGPIPE 13
|
||||
#define SIGALRM 14
|
||||
#define SIGCHLD 17
|
||||
|
||||
#define F_GETFD 1
|
||||
#define F_SETFD 2
|
||||
|
|
106
diff.c
106
diff.c
|
@ -12,6 +12,7 @@
|
|||
#include "run-command.h"
|
||||
#include "utf8.h"
|
||||
#include "userdiff.h"
|
||||
#include "sigchain.h"
|
||||
|
||||
#ifdef NO_FAST_WORKING_DIRECTORY
|
||||
#define FAST_WORKING_DIRECTORY 0
|
||||
|
@ -170,6 +171,33 @@ static struct diff_tempfile {
|
|||
char tmp_path[PATH_MAX];
|
||||
} diff_temp[2];
|
||||
|
||||
static struct diff_tempfile *claim_diff_tempfile(void) {
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(diff_temp); i++)
|
||||
if (!diff_temp[i].name)
|
||||
return diff_temp + i;
|
||||
die("BUG: diff is failing to clean up its tempfiles");
|
||||
}
|
||||
|
||||
static int remove_tempfile_installed;
|
||||
|
||||
static void remove_tempfile(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(diff_temp); i++)
|
||||
if (diff_temp[i].name == diff_temp[i].tmp_path) {
|
||||
unlink(diff_temp[i].name);
|
||||
diff_temp[i].name = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void remove_tempfile_on_signal(int signo)
|
||||
{
|
||||
remove_tempfile();
|
||||
sigchain_pop(signo);
|
||||
raise(signo);
|
||||
}
|
||||
|
||||
static int count_lines(const char *data, int size)
|
||||
{
|
||||
int count, ch, completely_empty = 1, nl_just_seen = 0;
|
||||
|
@ -1940,10 +1968,11 @@ static void prep_temp_blob(struct diff_tempfile *temp,
|
|||
sprintf(temp->mode, "%06o", mode);
|
||||
}
|
||||
|
||||
static void prepare_temp_file(const char *name,
|
||||
struct diff_tempfile *temp,
|
||||
static struct diff_tempfile *prepare_temp_file(const char *name,
|
||||
struct diff_filespec *one)
|
||||
{
|
||||
struct diff_tempfile *temp = claim_diff_tempfile();
|
||||
|
||||
if (!DIFF_FILE_VALID(one)) {
|
||||
not_a_valid_file:
|
||||
/* A '-' entry produces this for file-2, and
|
||||
|
@ -1952,7 +1981,13 @@ static void prepare_temp_file(const char *name,
|
|||
temp->name = "/dev/null";
|
||||
strcpy(temp->hex, ".");
|
||||
strcpy(temp->mode, ".");
|
||||
return;
|
||||
return temp;
|
||||
}
|
||||
|
||||
if (!remove_tempfile_installed) {
|
||||
atexit(remove_tempfile);
|
||||
sigchain_push_common(remove_tempfile_on_signal);
|
||||
remove_tempfile_installed = 1;
|
||||
}
|
||||
|
||||
if (!one->sha1_valid ||
|
||||
|
@ -1992,7 +2027,7 @@ static void prepare_temp_file(const char *name,
|
|||
*/
|
||||
sprintf(temp->mode, "%06o", one->mode);
|
||||
}
|
||||
return;
|
||||
return temp;
|
||||
}
|
||||
else {
|
||||
if (diff_populate_filespec(one, 0))
|
||||
|
@ -2000,24 +2035,7 @@ static void prepare_temp_file(const char *name,
|
|||
prep_temp_blob(temp, one->data, one->size,
|
||||
one->sha1, one->mode);
|
||||
}
|
||||
}
|
||||
|
||||
static void remove_tempfile(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
if (diff_temp[i].name == diff_temp[i].tmp_path) {
|
||||
unlink(diff_temp[i].name);
|
||||
diff_temp[i].name = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void remove_tempfile_on_signal(int signo)
|
||||
{
|
||||
remove_tempfile();
|
||||
signal(SIGINT, SIG_DFL);
|
||||
raise(signo);
|
||||
return temp;
|
||||
}
|
||||
|
||||
/* An external diff command takes:
|
||||
|
@ -2035,34 +2053,22 @@ static void run_external_diff(const char *pgm,
|
|||
int complete_rewrite)
|
||||
{
|
||||
const char *spawn_arg[10];
|
||||
struct diff_tempfile *temp = diff_temp;
|
||||
int retval;
|
||||
static int atexit_asked = 0;
|
||||
const char *othername;
|
||||
const char **arg = &spawn_arg[0];
|
||||
|
||||
othername = (other? other : name);
|
||||
if (one && two) {
|
||||
prepare_temp_file(name, &temp[0], one);
|
||||
prepare_temp_file(othername, &temp[1], two);
|
||||
if (! atexit_asked &&
|
||||
(temp[0].name == temp[0].tmp_path ||
|
||||
temp[1].name == temp[1].tmp_path)) {
|
||||
atexit_asked = 1;
|
||||
atexit(remove_tempfile);
|
||||
}
|
||||
signal(SIGINT, remove_tempfile_on_signal);
|
||||
}
|
||||
|
||||
if (one && two) {
|
||||
struct diff_tempfile *temp_one, *temp_two;
|
||||
const char *othername = (other ? other : name);
|
||||
temp_one = prepare_temp_file(name, one);
|
||||
temp_two = prepare_temp_file(othername, two);
|
||||
*arg++ = pgm;
|
||||
*arg++ = name;
|
||||
*arg++ = temp[0].name;
|
||||
*arg++ = temp[0].hex;
|
||||
*arg++ = temp[0].mode;
|
||||
*arg++ = temp[1].name;
|
||||
*arg++ = temp[1].hex;
|
||||
*arg++ = temp[1].mode;
|
||||
*arg++ = temp_one->name;
|
||||
*arg++ = temp_one->hex;
|
||||
*arg++ = temp_one->mode;
|
||||
*arg++ = temp_two->name;
|
||||
*arg++ = temp_two->hex;
|
||||
*arg++ = temp_two->mode;
|
||||
if (other) {
|
||||
*arg++ = other;
|
||||
*arg++ = xfrm_msg;
|
||||
|
@ -3537,15 +3543,15 @@ void diff_unmerge(struct diff_options *options,
|
|||
static char *run_textconv(const char *pgm, struct diff_filespec *spec,
|
||||
size_t *outsize)
|
||||
{
|
||||
struct diff_tempfile temp;
|
||||
struct diff_tempfile *temp;
|
||||
const char *argv[3];
|
||||
const char **arg = argv;
|
||||
struct child_process child;
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
|
||||
prepare_temp_file(spec->path, &temp, spec);
|
||||
temp = prepare_temp_file(spec->path, spec);
|
||||
*arg++ = pgm;
|
||||
*arg++ = temp.name;
|
||||
*arg++ = temp->name;
|
||||
*arg = NULL;
|
||||
|
||||
memset(&child, 0, sizeof(child));
|
||||
|
@ -3554,13 +3560,11 @@ static char *run_textconv(const char *pgm, struct diff_filespec *spec,
|
|||
if (start_command(&child) != 0 ||
|
||||
strbuf_read(&buf, child.out, 0) < 0 ||
|
||||
finish_command(&child) != 0) {
|
||||
if (temp.name == temp.tmp_path)
|
||||
unlink(temp.name);
|
||||
remove_tempfile();
|
||||
error("error running textconv command '%s'", pgm);
|
||||
return NULL;
|
||||
}
|
||||
if (temp.name == temp.tmp_path)
|
||||
unlink(temp.name);
|
||||
remove_tempfile();
|
||||
|
||||
return strbuf_detach(&buf, outsize);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "exec_cmd.h"
|
||||
#include "remote.h"
|
||||
#include "list-objects.h"
|
||||
#include "sigchain.h"
|
||||
|
||||
#include <expat.h>
|
||||
|
||||
|
@ -1384,7 +1385,7 @@ static void remove_locks(void)
|
|||
static void remove_locks_on_signal(int signo)
|
||||
{
|
||||
remove_locks();
|
||||
signal(signo, SIG_DFL);
|
||||
sigchain_pop(signo);
|
||||
raise(signo);
|
||||
}
|
||||
|
||||
|
@ -2277,10 +2278,7 @@ int main(int argc, char **argv)
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
signal(SIGINT, remove_locks_on_signal);
|
||||
signal(SIGHUP, remove_locks_on_signal);
|
||||
signal(SIGQUIT, remove_locks_on_signal);
|
||||
signal(SIGTERM, remove_locks_on_signal);
|
||||
sigchain_push_common(remove_locks_on_signal);
|
||||
|
||||
/* Check whether the remote has server info files */
|
||||
remote->can_update_info_refs = 0;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* Copyright (c) 2005, Junio C Hamano
|
||||
*/
|
||||
#include "cache.h"
|
||||
#include "sigchain.h"
|
||||
|
||||
static struct lock_file *lock_file_list;
|
||||
static const char *alternate_index_output;
|
||||
|
@ -24,7 +25,7 @@ static void remove_lock_file(void)
|
|||
static void remove_lock_file_on_signal(int signo)
|
||||
{
|
||||
remove_lock_file();
|
||||
signal(signo, SIG_DFL);
|
||||
sigchain_pop(signo);
|
||||
raise(signo);
|
||||
}
|
||||
|
||||
|
@ -136,11 +137,7 @@ static int lock_file(struct lock_file *lk, const char *path, int flags)
|
|||
lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666);
|
||||
if (0 <= lk->fd) {
|
||||
if (!lock_file_list) {
|
||||
signal(SIGINT, remove_lock_file_on_signal);
|
||||
signal(SIGHUP, remove_lock_file_on_signal);
|
||||
signal(SIGTERM, remove_lock_file_on_signal);
|
||||
signal(SIGQUIT, remove_lock_file_on_signal);
|
||||
signal(SIGPIPE, remove_lock_file_on_signal);
|
||||
sigchain_push_common(remove_lock_file_on_signal);
|
||||
atexit(remove_lock_file);
|
||||
}
|
||||
lk->owner = getpid();
|
||||
|
|
9
pager.c
9
pager.c
|
@ -1,5 +1,6 @@
|
|||
#include "cache.h"
|
||||
#include "run-command.h"
|
||||
#include "sigchain.h"
|
||||
|
||||
/*
|
||||
* This is split up from the rest of git so that we can do
|
||||
|
@ -38,6 +39,13 @@ static void wait_for_pager(void)
|
|||
finish_command(&pager_process);
|
||||
}
|
||||
|
||||
static void wait_for_pager_signal(int signo)
|
||||
{
|
||||
wait_for_pager();
|
||||
sigchain_pop(signo);
|
||||
raise(signo);
|
||||
}
|
||||
|
||||
void setup_pager(void)
|
||||
{
|
||||
const char *pager = getenv("GIT_PAGER");
|
||||
|
@ -75,6 +83,7 @@ void setup_pager(void)
|
|||
close(pager_process.in);
|
||||
|
||||
/* this makes sure that the parent terminates after the pager */
|
||||
sigchain_push_common(wait_for_pager_signal);
|
||||
atexit(wait_for_pager);
|
||||
}
|
||||
|
||||
|
|
52
sigchain.c
Normal file
52
sigchain.c
Normal file
|
@ -0,0 +1,52 @@
|
|||
#include "sigchain.h"
|
||||
#include "cache.h"
|
||||
|
||||
#define SIGCHAIN_MAX_SIGNALS 32
|
||||
|
||||
struct sigchain_signal {
|
||||
sigchain_fun *old;
|
||||
int n;
|
||||
int alloc;
|
||||
};
|
||||
static struct sigchain_signal signals[SIGCHAIN_MAX_SIGNALS];
|
||||
|
||||
static void check_signum(int sig)
|
||||
{
|
||||
if (sig < 1 || sig >= SIGCHAIN_MAX_SIGNALS)
|
||||
die("BUG: signal out of range: %d", sig);
|
||||
}
|
||||
|
||||
int sigchain_push(int sig, sigchain_fun f)
|
||||
{
|
||||
struct sigchain_signal *s = signals + sig;
|
||||
check_signum(sig);
|
||||
|
||||
ALLOC_GROW(s->old, s->n + 1, s->alloc);
|
||||
s->old[s->n] = signal(sig, f);
|
||||
if (s->old[s->n] == SIG_ERR)
|
||||
return -1;
|
||||
s->n++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sigchain_pop(int sig)
|
||||
{
|
||||
struct sigchain_signal *s = signals + sig;
|
||||
check_signum(sig);
|
||||
if (s->n < 1)
|
||||
return 0;
|
||||
|
||||
if (signal(sig, s->old[s->n - 1]) == SIG_ERR)
|
||||
return -1;
|
||||
s->n--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sigchain_push_common(sigchain_fun f)
|
||||
{
|
||||
sigchain_push(SIGINT, f);
|
||||
sigchain_push(SIGHUP, f);
|
||||
sigchain_push(SIGTERM, f);
|
||||
sigchain_push(SIGQUIT, f);
|
||||
sigchain_push(SIGPIPE, f);
|
||||
}
|
11
sigchain.h
Normal file
11
sigchain.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifndef SIGCHAIN_H
|
||||
#define SIGCHAIN_H
|
||||
|
||||
typedef void (*sigchain_fun)(int);
|
||||
|
||||
int sigchain_push(int sig, sigchain_fun f);
|
||||
int sigchain_pop(int sig);
|
||||
|
||||
void sigchain_push_common(sigchain_fun f);
|
||||
|
||||
#endif /* SIGCHAIN_H */
|
22
t/t0005-signals.sh
Executable file
22
t/t0005-signals.sh
Executable file
|
@ -0,0 +1,22 @@
|
|||
#!/bin/sh
|
||||
|
||||
test_description='signals work as we expect'
|
||||
. ./test-lib.sh
|
||||
|
||||
cat >expect <<EOF
|
||||
three
|
||||
two
|
||||
one
|
||||
EOF
|
||||
|
||||
test_expect_success 'sigchain works' '
|
||||
test-sigchain >actual
|
||||
case "$?" in
|
||||
143) true ;; # POSIX w/ SIGTERM=15
|
||||
3) true ;; # Windows
|
||||
*) false ;;
|
||||
esac &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_done
|
22
test-sigchain.c
Normal file
22
test-sigchain.c
Normal file
|
@ -0,0 +1,22 @@
|
|||
#include "sigchain.h"
|
||||
#include "cache.h"
|
||||
|
||||
#define X(f) \
|
||||
static void f(int sig) { \
|
||||
puts(#f); \
|
||||
fflush(stdout); \
|
||||
sigchain_pop(sig); \
|
||||
raise(sig); \
|
||||
}
|
||||
X(one)
|
||||
X(two)
|
||||
X(three)
|
||||
#undef X
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
sigchain_push(SIGTERM, one);
|
||||
sigchain_push(SIGTERM, two);
|
||||
sigchain_push(SIGTERM, three);
|
||||
raise(SIGTERM);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue