unix: reset signal counters after fork (#3485)
If a signal was received but was not dispatched before fork then caught_signals counter should be reset. Closing of signal pipe makes impossible to receive the signal that was counted. There is no need in this signal because it was sent to parent process Fixes: https://github.com/libuv/libuv/issues/3483
This commit is contained in:
parent
d83fadaf09
commit
2a4cab70ef
@ -279,6 +279,8 @@ static int uv__signal_loop_once_init(uv_loop_t* loop) {
|
||||
|
||||
|
||||
int uv__signal_loop_fork(uv_loop_t* loop) {
|
||||
struct uv__queue* q;
|
||||
|
||||
if (loop->signal_pipefd[0] == -1)
|
||||
return 0;
|
||||
uv__io_stop(loop, &loop->signal_io_watcher, POLLIN);
|
||||
@ -286,6 +288,19 @@ int uv__signal_loop_fork(uv_loop_t* loop) {
|
||||
uv__close(loop->signal_pipefd[1]);
|
||||
loop->signal_pipefd[0] = -1;
|
||||
loop->signal_pipefd[1] = -1;
|
||||
|
||||
uv__queue_foreach(q, &loop->handle_queue) {
|
||||
uv_handle_t* handle = uv__queue_data(q, uv_handle_t, handle_queue);
|
||||
uv_signal_t* sh;
|
||||
|
||||
if (handle->type != UV_SIGNAL)
|
||||
continue;
|
||||
|
||||
sh = (uv_signal_t*) handle;
|
||||
sh->caught_signals = 0;
|
||||
sh->dispatched_signals = 0;
|
||||
}
|
||||
|
||||
return uv__signal_loop_once_init(loop);
|
||||
}
|
||||
|
||||
|
||||
@ -371,6 +371,47 @@ TEST_IMPL(fork_signal_to_child_closed) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fork_signal_cb(uv_signal_t* h, int s) {
|
||||
fork_signal_cb_called = s;
|
||||
}
|
||||
static void empty_close_cb(uv_handle_t* h){}
|
||||
|
||||
TEST_IMPL(fork_close_signal_in_child) {
|
||||
uv_loop_t loop;
|
||||
uv_signal_t signal_handle;
|
||||
pid_t child_pid;
|
||||
|
||||
ASSERT_EQ(0, uv_loop_init(&loop));
|
||||
ASSERT_EQ(0, uv_signal_init(&loop, &signal_handle));
|
||||
ASSERT_EQ(0, uv_signal_start(&signal_handle, &fork_signal_cb, SIGHUP));
|
||||
|
||||
ASSERT_EQ(0, kill(getpid(), SIGHUP));
|
||||
child_pid = fork();
|
||||
ASSERT_NE(child_pid, -1);
|
||||
ASSERT_EQ(0, fork_signal_cb_called);
|
||||
|
||||
if (!child_pid) {
|
||||
uv_loop_fork(&loop);
|
||||
uv_close((uv_handle_t*)&signal_handle, &empty_close_cb);
|
||||
uv_run(&loop, UV_RUN_DEFAULT);
|
||||
/* Child doesn't receive the signal */
|
||||
ASSERT_EQ(0, fork_signal_cb_called);
|
||||
} else {
|
||||
/* Parent. Runing once to receive the signal */
|
||||
uv_run(&loop, UV_RUN_ONCE);
|
||||
ASSERT_EQ(SIGHUP, fork_signal_cb_called);
|
||||
|
||||
/* loop should stop after closing the only handle */
|
||||
uv_close((uv_handle_t*)&signal_handle, &empty_close_cb);
|
||||
ASSERT_EQ(0, uv_run(&loop, UV_RUN_DEFAULT));
|
||||
|
||||
assert_wait_child(child_pid);
|
||||
}
|
||||
|
||||
MAKE_VALGRIND_HAPPY(&loop);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void create_file(const char* name) {
|
||||
int r;
|
||||
|
||||
@ -546,6 +546,7 @@ TEST_DECLARE (fork_socketpair)
|
||||
TEST_DECLARE (fork_socketpair_started)
|
||||
TEST_DECLARE (fork_signal_to_child)
|
||||
TEST_DECLARE (fork_signal_to_child_closed)
|
||||
TEST_DECLARE (fork_close_signal_in_child)
|
||||
#ifndef __APPLE__ /* This is forbidden in a fork child: The process has forked
|
||||
and you cannot use this CoreFoundation functionality
|
||||
safely. You MUST exec(). */
|
||||
@ -1184,6 +1185,7 @@ TASK_LIST_START
|
||||
TEST_ENTRY (fork_socketpair_started)
|
||||
TEST_ENTRY (fork_signal_to_child)
|
||||
TEST_ENTRY (fork_signal_to_child_closed)
|
||||
TEST_ENTRY (fork_close_signal_in_child)
|
||||
#ifndef __APPLE__
|
||||
TEST_ENTRY (fork_fs_events_child)
|
||||
TEST_ENTRY (fork_fs_events_child_dir)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user