summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorroot <root>2012-04-02 18:39:54 +0000
committerroot <root>2012-04-02 18:39:54 +0000
commit1a78f29c569e692a7e7fb56b47f0cc7f7398a9b6 (patch)
tree38887c5897dcb8096066b56adb3f37b33749ce1f
parent3ea499f2d3ae8aaa2389b2e7f47d1a9d20f78f89 (diff)
*** empty log message ***
-rw-r--r--Changes2
-rw-r--r--ev.pod6
-rw-r--r--ev_kqueue.c19
-rw-r--r--ev_vars.h3
-rw-r--r--ev_wrap.h2
5 files changed, 25 insertions, 7 deletions
diff --git a/Changes b/Changes
index ae491e1..b32b1b4 100644
--- a/Changes
+++ b/Changes
@@ -12,6 +12,8 @@ TODO: use __OPTIMIZE__ or __OPTIMIZE_SIZE__?
TODO: Jeff Davey libev patch
- (ecb) add memory fence support for xlC (Darin McBride).
- (ecb) add memory fence support for gcc-mips (Anton Kirilov).
+ - work around some kernels losing file descriptors by leaking
+ the kqueue descriptor in the child.
4.11 Sat Feb 4 19:52:39 CET 2012
- INCOMPATIBLE CHANGE: ev_timer_again now clears the pending status, as
diff --git a/ev.pod b/ev.pod
index bb1f95a..9ea2cd6 100644
--- a/ev.pod
+++ b/ev.pod
@@ -569,9 +569,9 @@ It scales in the same way as the epoll backend, but the interface to the
kernel is more efficient (which says nothing about its actual speed, of
course). While stopping, setting and starting an I/O watcher does never
cause an extra system call as with C<EVBACKEND_EPOLL>, it still adds up to
-two event changes per incident. Support for C<fork ()> is very bad (but
-sane, unlike epoll) and it drops fds silently in similarly hard-to-detect
-cases
+two event changes per incident. Support for C<fork ()> is very bad (you
+might have to leak fd's on fork, but it's more sane than epoll) and it
+drops fds silently in similarly hard-to-detect cases
This backend usually performs well under most conditions.
diff --git a/ev_kqueue.c b/ev_kqueue.c
index bc4ac48..9faf65a 100644
--- a/ev_kqueue.c
+++ b/ev_kqueue.c
@@ -155,7 +155,8 @@ kqueue_poll (EV_P_ ev_tstamp timeout)
int inline_size
kqueue_init (EV_P_ int flags)
{
- /* Initialize the kernel queue */
+ /* initialize the kernel queue */
+ kqueue_fd_pid = getpid ();
if ((backend_fd = kqueue ()) < 0)
return 0;
@@ -185,8 +186,20 @@ kqueue_destroy (EV_P)
void inline_size
kqueue_fork (EV_P)
{
- close (backend_fd);
-
+ /* some BSD kernels don't just destroy the kqueue itself,
+ * but also close the fd, which isn't documented, and
+ * impossible to support properly.
+ * we remember the pid of the kqueue call and only close
+ * the fd if the pid is still the same.
+ * this leaks fds on sane kernels, but BSD interfaces are
+ * notoriously buggy and rarely get fixed.
+ */
+ pid_t newpid = getpid ();
+
+ if (newpid == kqueue_fd_pid)
+ close (backend_fd);
+
+ kqueue_fd_pid = newpid;
while ((backend_fd = kqueue ()) < 0)
ev_syserr ("(libev) kqueue");
diff --git a/ev_vars.h b/ev_vars.h
index 9f7acb6..667a986 100644
--- a/ev_vars.h
+++ b/ev_vars.h
@@ -1,7 +1,7 @@
/*
* loop member variable declarations
*
- * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <libev@schmorp.de>
+ * Copyright (c) 2007,2008,2009,2010,2011,2012 Marc Alexander Lehmann <libev@schmorp.de>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modifica-
@@ -110,6 +110,7 @@ VARx(int, epoll_epermmax)
#endif
#if EV_USE_KQUEUE || EV_GENWRAP
+VARx(pid_t, kqueue_fd_pid)
VARx(struct kevent *, kqueue_changes)
VARx(int, kqueue_changemax)
VARx(int, kqueue_changecnt)
diff --git a/ev_wrap.h b/ev_wrap.h
index 36edbd2..3c47c6e 100644
--- a/ev_wrap.h
+++ b/ev_wrap.h
@@ -45,6 +45,7 @@
#define epoll_eperms ((loop)->epoll_eperms)
#define epoll_epermcnt ((loop)->epoll_epermcnt)
#define epoll_epermmax ((loop)->epoll_epermmax)
+#define kqueue_fd_pid ((loop)->kqueue_fd_pid)
#define kqueue_changes ((loop)->kqueue_changes)
#define kqueue_changemax ((loop)->kqueue_changemax)
#define kqueue_changecnt ((loop)->kqueue_changecnt)
@@ -143,6 +144,7 @@
#undef epoll_eperms
#undef epoll_epermcnt
#undef epoll_epermmax
+#undef kqueue_fd_pid
#undef kqueue_changes
#undef kqueue_changemax
#undef kqueue_changecnt