use bytes;
use POSIX ();
use Time::HiRes ();
+use IO::Handle qw();
+use Fcntl qw(FD_CLOEXEC F_SETFD F_GETFD);
use warnings;
$HaveKQueue,
%DescriptorMap, # fd (num) -> PublicInbox::DS object
$Epoll, # Global epoll fd (for epoll mode only)
- $KQueue, # Global kqueue fd (for kqueue mode only)
+ $KQueue, # Global kqueue fd ref (for kqueue mode only)
+ $_io, # IO::Handle for Epoll
@ToClose, # sockets to close when event loop is done
$PostLoopCallback, # subref to call at the end of each loop, if defined (global)
%PLCMap = ();
$DoneInit = 0;
- POSIX::close($Epoll) if defined $Epoll && $Epoll >= 0;
- POSIX::close($KQueue) if defined $KQueue && $KQueue >= 0;
+ # NOTE kqueue is close-on-fork, and we don't account for it, yet
+ # OTOH, we (public-inbox) don't need this sub outside of tests...
+ POSIX::close($$KQueue) if !$_io && $KQueue && $$KQueue >= 0;
+ $KQueue = undef;
+
+ $_io = undef; # close $Epoll
+ $Epoll = undef;
*EventLoop = *FirstTimeEventLoop;
}
die "Shouldn't get here.";
}
+# keeping this around in case we support other FD types for now,
+# epoll_create1(EPOLL_CLOEXEC) requires Linux 2.6.27+...
+sub set_cloexec ($) {
+ my ($fd) = @_;
+
+ $_io = IO::Handle->new_from_fd($fd, 'r+') or return;
+ defined(my $fl = fcntl($_io, F_GETFD, 0)) or return;
+ fcntl($_io, F_SETFD, $fl | FD_CLOEXEC);
+}
+
sub _InitPoller
{
return if $DoneInit;
if ($HAVE_KQUEUE) {
$KQueue = IO::KQueue->new();
- $HaveKQueue = $KQueue >= 0;
+ $HaveKQueue = defined $KQueue;
if ($HaveKQueue) {
*EventLoop = *KQueueEventLoop;
}
$Epoll = eval { epoll_create(1024); };
$HaveEpoll = defined $Epoll && $Epoll >= 0;
if ($HaveEpoll) {
+ set_cloexec($Epoll);
*EventLoop = *EpollEventLoop;
}
}