Subject: | Loops should survive forks |
Sometimes we want to use the event loop after a fork.
The simplest case I've found is a pre-forking NaHTTP::Server, in which I create the listening socket in the parent, then fork, and have each child ->listen on it. To share memory, I create all the objects, including the loop, in the parent. If I'm using the Epoll loop, the whole thing breaks because all children are adding fds to the *same* epoll instance.
I have worked around the issue by calling this function:
sub _fix_the_loop {
my ($loop) = @_;
require Linux::Epoll;
# let's make sure that each child has a separate epoll instance
$loop->{epoll} = Linux::Epoll->new;
# then we want to re-add all the file descriptors that were
# registered in the parent's loop
my $watches = $loop->{iowatches};
return unless $watches && ref($watches);
# $watches is a hashref keyed on file descriptors: we don't
# actually care about the keys
for my $watch (values %$watches) {
my %args;
# this unpacks $watch the same way as
# IO::Async::Loop::__watch_io (yes, I'm depending on an
# implementation detail, so sue me)
@args{qw(handle on_read_ready on_write_ready on_hangup)}
= @$watch;
# finally we re-add the watch to the loop
$loop->watch_io(%args);
}
return;
}
IO::Async::Loop should have a 'post_fork' empty method, and IaL::Epoll should override it with something like my function.