]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
2489. [port] solaris: Workaround Solaris's kernel bug about
authorTatuya JINMEI 神明達哉 <jinmei@isc.org>
Sat, 8 Nov 2008 22:42:56 +0000 (22:42 +0000)
committerTatuya JINMEI 神明達哉 <jinmei@isc.org>
Sat, 8 Nov 2008 22:42:56 +0000 (22:42 +0000)
/dev/poll:
http://bugs.opensolaris.org/view_bug.do?bug_id=6724237
Define ISC_SOCKET_USE_POLLWATCH at build time to enable
this workaround. [RT #18870]

CHANGES
README
lib/isc/unix/socket.c

diff --git a/CHANGES b/CHANGES
index be3dd67ac6f34e52d499ea019c1da6c1c3295800..d2f212b156b061664b9526f6a20c0f6054c03635 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,8 @@
+2489.  [port]          solaris: Workaround Solaris's kernel bug about
+                       /dev/poll:
+                       http://bugs.opensolaris.org/view_bug.do?bug_id=6724237
+                       Define ISC_SOCKET_USE_POLLWATCH at build time to enable
+                       this workaround. [RT #18870]
 
        --- 9.3.6rc1 released ---
 
diff --git a/README b/README
index ba269fd57607c68e610f7a38b6623bbb46d05c36..c30934f8f8cd7d8dfaa589d7f76d64f638ff920b 100644 (file)
--- a/README
+++ b/README
@@ -279,6 +279,10 @@ Building
                                    -DDIG_SIGCHASE_BU=1)
                Disable dropping queries from particular well known ports.
                  -DNS_CLIENT_DROPPORT=0
+               Enable workaround for Solaris kernel bug about /dev/poll
+                 -DISC_SOCKET_USE_POLLWATCH=1
+                 The watch timeout is also configurable, e.g.,
+                 -DISC_SOCKET_POLLWATCH_TIMEOUT=20
 
            LDFLAGS
                Linker flags. Defaults to empty string.
index 9a642461a58a4e7bbae750f62827e0c0bb53e205..e886cbb8eedda4613f27351c0c266976f7f040d5 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: socket.c,v 1.207.2.19.2.58 2008/10/17 21:53:54 jinmei Exp $ */
+/* $Id: socket.c,v 1.207.2.19.2.59 2008/11/08 22:42:56 jinmei Exp $ */
 
 #include <config.h>
 
@@ -140,6 +140,35 @@ struct isc_socketwait {
 #endif /* __APPLE__ */
 #endif /* USE_SELECT */
 
+#ifdef ISC_SOCKET_USE_POLLWATCH
+/*
+ * If this macro is defined, enable workaround for a Solaris /dev/poll kernel
+ * bug: DP_POLL ioctl could keep sleeping even if socket I/O is possible for
+ * some of the specified FD.  The idea is based on the observation that it's
+ * likely for a busy server to keep receiving packets.  It specifically works
+ * as follows: the socket watcher is first initialized with the state of
+ * "poll_idle".  While it's in the idle state it keeps sleeping until a socket
+ * event occurs.  When it wakes up for a socket I/O event, it moves to the
+ * poll_active state, and sets the poll timeout to a short period
+ * (ISC_SOCKET_POLLWATCH_TIMEOUT msec).  If timeout occurs in this state, the
+ * watcher goes to the poll_checking state with the same timeout period.
+ * In this state, the watcher tries to detect whether this is a break
+ * during intermittent events or the kernel bug is triggered.  If the next
+ * polling reports an event within the short period, the previous timeout is
+ * likely to be a kernel bug, and so the watcher goes back to the active state.
+ * Otherwise, it moves to the idle state again.
+ *
+ * It's not clear whether this is a thread-related bug, but since we've only
+ * seen this with threads, this workaround is used only when enabling threads.
+ */
+
+typedef enum { poll_idle, poll_active, poll_checking } pollstate_t;
+
+#ifndef ISC_SOCKET_POLLWATCH_TIMEOUT
+#define ISC_SOCKET_POLLWATCH_TIMEOUT 10
+#endif /* ISC_SOCKET_POLLWATCH_TIMEOUT */
+#endif /* ISC_SOCKET_USE_POLLWATCH */
+
 /*
  * Size of per-FD lock buckets.
  */
@@ -2990,6 +3019,9 @@ watcher(void *uap) {
        int maxfd;
 #endif
        char strbuf[ISC_STRERRORSIZE];
+#ifdef ISC_SOCKET_USE_POLLWATCH
+       pollstate_t pollstate = poll_idle;
+#endif
 
        /*
         * Get the control fd here.  This will never change.
@@ -3007,7 +3039,14 @@ watcher(void *uap) {
 #elif defined(USE_DEVPOLL)
                        dvp.dp_fds = manager->events;
                        dvp.dp_nfds = manager->nevents;
+#ifndef ISC_SOCKET_USE_POLLWATCH
                        dvp.dp_timeout = -1;
+#else
+                       if (pollstate == poll_idle)
+                               dvp.dp_timeout = -1;
+                       else
+                               dvp.dp_timeout = ISC_SOCKET_POLLWATCH_TIMEOUT;
+#endif /* ISC_SOCKET_USE_POLLWATCH */
                        cc = ioctl(manager->devpoll_fd, DP_POLL, &dvp);
 #elif defined(USE_SELECT)
                        LOCK(&manager->lock);
@@ -3031,6 +3070,33 @@ watcher(void *uap) {
                                                           ISC_MSG_FAILED,
                                                           "failed"), strbuf);
                        }
+
+#if defined(USE_DEVPOLL) && defined(ISC_SOCKET_USE_POLLWATCH)
+                       if (cc == 0) {
+                               if (pollstate == poll_active)
+                                       pollstate = poll_checking;
+                               else if (pollstate == poll_checking)
+                                       pollstate = poll_idle;
+                       } else if (cc > 0) {
+                               if (pollstate == poll_checking) {
+                                       /*
+                                        * XXX: We'd like to use a more
+                                        * verbose log level as it's actually an
+                                        * unexpected event, but the kernel bug
+                                        * reportedly happens pretty frequently
+                                        * (and it can also be a false positive)
+                                        * so it would be just too noisy.
+                                        */
+                                       manager_log(manager,
+                                                   ISC_LOGCATEGORY_GENERAL,
+                                                   ISC_LOGMODULE_SOCKET,
+                                                   ISC_LOG_DEBUG(1),
+                                                   ISC_LOG_INFO,
+                                                   "unexpected POLL timeout");
+                               }
+                               pollstate = poll_active;
+                       }
+#endif
                } while (cc < 0);
 
 #if defined(USE_KQUEUE) || defined (USE_EPOLL) || defined (USE_DEVPOLL)