build: Never use poll() on Darwin family (macOS, etc.) or Interix
authorSimon McVittie <smcv@collabora.com>
Mon, 22 Oct 2018 10:45:45 +0000 (11:45 +0100)
committerSimon McVittie <smcv@collabora.com>
Fri, 16 Nov 2018 15:07:39 +0000 (15:07 +0000)
Doing a runtime check in configure.ac (AC_RUN_IFELSE) has several
disadvantages:

* It doesn't work when cross-compiling. For example, if we build macOS
  binaries on a Linux system, we'd assume that poll() works, but in
  fact it won't.

* It checks the build system capabilities, but that is not necessarily
  appropriate if (for example) a macOS 10.10 user builds binaries that
  could be used by macOS 10.12 or macOS 10.9 users.

* It checks for one specific failure mode, but macOS seems to have a
  history of various implementation issues in poll().

* If we want it to work in CMake, we have to duplicate it in the CMake
  build system.

None of these is a showstopper on its own, but the combination of all
of them makes the current approach to avoiding the broken poll() on
macOS look unreliable. libcurl, a widely-portable library making
extensive use of sockets, specifically doesn't use poll() on Darwin
(macOS, iOS, etc.) or on Interix; let's follow their example here.

See also https://bugzilla.gnome.org/show_bug.cgi?id=302672 and
https://daniel.haxx.se/blog/2016/10/11/poll-on-mac-10-12-is-broken/
for some relevant history.

Signed-off-by: Simon McVittie <smcv@collabora.com>
Resolves: https://gitlab.freedesktop.org/dbus/dbus/issues/232
(cherry picked from commit 0414ea65ca8196e328da09c3a2324d7765fba8c4)

configure.ac
dbus/dbus-sysdeps.h

index 09a12ab..0a18ab6 100644 (file)
@@ -630,34 +630,6 @@ fi
 AC_CHECK_HEADERS_ONCE([sys/prctl.h])
 AC_CHECK_FUNCS_ONCE([prctl raise])
 
-#### Check for broken poll; taken from Glib's configure
-
-AC_MSG_CHECKING([for broken poll])
-AC_RUN_IFELSE([AC_LANG_SOURCE([[
-    #include <stdlib.h>
-    #include <fcntl.h>
-    #include <poll.h>
-    #ifdef HAVE_SYS_POLL_H
-    #include <sys/poll.h>
-    #endif
-    int main(void) {
-      struct pollfd fds[1];
-      int fd;
-      fd = open("/dev/null", 1);
-      fds[0].fd = fd;
-      fds[0].events = POLLIN;
-      fds[0].revents = 0;
-      if (poll(fds, 1, 0) < 0 || (fds[0].revents & POLLNVAL) != 0) {
-            exit(1);  /* Does not work for devices -- fail */
-      }
-      exit(0);
-    }]])],
-  [broken_poll=no],
-  [broken_poll=yes
-   AC_DEFINE(BROKEN_POLL,1,[poll doesn't work on devices])],
-  [broken_poll="no (cross compiling)"])
-AC_MSG_RESULT($broken_poll)
-
 AC_MSG_CHECKING(for dirfd)
 AC_LINK_IFELSE([AC_LANG_PROGRAM([[
 #include <sys/types.h>
index 6892247..ef786ec 100644 (file)
 #include <string.h>
 #include <stdarg.h>
 
+#if !defined(BROKEN_POLL) && (defined(__APPLE__) || defined(__INTERIX))
+  /* Following libcurl's example, we blacklist poll() on Darwin
+   * (macOS, iOS, etc.) and Interix due to a history of implementation
+   * issues.
+   * https://github.com/curl/curl/blob/master/m4/curl-functions.m4
+   *
+   * On unspecified older macOS versions, poll() failed if given a
+   * device node to poll.
+   *
+   * On macOS < 10.9, poll() with nfds=0 failed instead of waiting for
+   * the timeout and then succeeding.
+   *
+   * On macOS >= 10.12, poll() with nfds=0 succeeded immediately
+   * instead of waiting for the timeout, resulting in busy-looping.
+   *
+   * On Interix, poll() apparently only works for files in /proc.
+   *
+   * The "legacy" build flavour in our CI machinery defines BROKEN_POLL
+   * on whatever platform is in use (normally Linux) to force use of the
+   * same select()-based poll() emulation that we use for macOS, Interix,
+   * and any platform that lacks a real poll(), so that we can test it
+   * more regularly.
+   */
+# define BROKEN_POLL
+#endif
+
 /* AIX sys/poll.h does #define events reqevents, and other
  * wonderousness, so must include sys/poll before declaring
  * DBusPollFD