Why is a signal watcher active after default loop destruction and re-creation?
Jan-Philip Gehrcke
jgehrcke at googlemail.com
Fri Nov 22 17:24:24 CET 2013
Hello,
I am working on gevent/gipc and need to figure out why a libev signal
watcher is still 'active' after destroying its originally assigned event
loop. In the example code at the bottom of this mail, I
- create a signal watcher for SIGTERM
- assign it to the default event loop
- fork
- destroy the default event loop in the child
- create and run a new default event loop in the child
- send SIGTERM to the child
The output is:
> Msg from parent with PID 9934
> Msg from child with PID 9935
> Waiting for child.
> SIGTERM handler called in process 9935
> Child finished, exit parent.
I infer from this that
- the signal handler is still installed in the child (not surprising,
since it is inherited)
- in the child, the signal watcher object is magically connected to the
new loop
The latter surprises me. I went through the libev docs again and could
not really find an explanation. Especially, I found this part:
"Destroying the default loop will "orphan" (not stop) all registered
watchers, so you have to be careful not to execute code that modifies
those watchers. Note also that in that case, you have to re-register any
signal watchers."
What I indeed want is to "orphan" everything in the child related to the
default loop created in the parent. However, it looks like signal
watchers don't need to be re-registered, at least not for my test
system. For some this might be a feature, but in my application case,
this is a problem. I want to understand: why is that signal watcher
still active?
And yes, an obvious solution would be `signal(SIGTERM, SIG_DFL);` in the
child -- but what would the general approach be to make sure that
previously installed watchers are not active anymore when their
corresponding loop has been destroyed?
Thanks a lot for any insight,
Jan-Philip
The test program:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <signal.h>
#include <ev.h>
void sigtermhandler(struct ev_loop *l, ev_signal *w, int revents) {
printf("SIGTERM handler called in process %d\n", getpid());
ev_break(l, EVBREAK_ALL);
}
void child(struct ev_loop *loop) {
printf("Msg from child with PID %d\n", getpid());
ev_loop_destroy(loop);
// Reset signal handler:
//signal(SIGTERM, SIG_DFL);
struct ev_loop *newloop = ev_default_loop(0);
ev_run(newloop, 0);
}
int main (void) {
printf("Msg from parent with PID %d\n", getpid());
struct ev_loop *loop = EV_DEFAULT;
// Install signal watcher in parent, handling SIGTERM.
ev_signal signal_watcher;
ev_signal_init(&signal_watcher, sigtermhandler, SIGTERM);
ev_signal_start(loop, &signal_watcher);
pid_t pid;
pid = fork();
if (pid == -1) {
fprintf(stderr, "Can't fork, error %d\n", errno);
exit(1);
}
else if (pid == 0) {
child(loop);
exit(0);
}
// Dirtywait until child is upnrunning, then send SIGTER.
sleep(1);
kill(pid, SIGTERM);
//ev_run (loop, 0);
printf("Waiting for child.\n");
wait();
printf("Child finished, exit parent.\n");
}
More information about the libev
mailing list