cURL / Mailing Lists / curl-library / Single Mail

curl-library

Re: Mac OS X and poll()

From: Daniel Johnson <daniel_at_daniel-johnson.org>
Date: Mon, 12 Feb 2007 20:29:56 -0500

I sent this message on Friday, but I'm not sure if it got through
since the server seemed to be down over the weekend. If it did get
through, sorry!

On Feb 9, 2007, at 4:53 PM, Daniel Stenberg wrote:

> On Fri, 9 Feb 2007, Daniel Johnson wrote:
>
>
>>> http://www.greenend.org.uk/rjk/2001/06/poll.html
>>>
>>
>> That's an interesting page. I ran his test program and got this:
>>
>> Darwin mentalis.local 8.9.1 Darwin Kernel Version 8.9.1: Tue Jan
>> 23 23:00:25 PST 2007; root:xnu-792.18.12~1/RELEASE_I386 i386 i386
>>
>
>
>> pipe: POLLIN|POLLHUP
>> socketpair: POLLIN|POLLHUP
>> SHUT_WR socketpair: POLLIN|POLLHUP
>> SHUT_RD socketpair: POLLIN|POLLHUP
>> regular: POLLIN
>>
>
> As a comparsion, my Linux 2.6.18 with glibc 2.3.6 says:
>
> pipe: POLLHUP
> socketpair: POLLIN|POLLHUP
> SHUT_WR socketpair: POLLIN
> SHUT_RD socketpair: POLLIN
> regular: POLLIN
>
> Hm, ok so I guess we then really should make configure do the check
> for poll/select on darwin like on other systems, and thus use poll
> () in the code.
>
> Do you happen to have a patch for this?
>

Well, I found a problem. Turns out that lib/telnet.c calls Curl_poll
on stdin, which is a device and therefore doesn't work with darwin's
poll. In this case poll just spews POLLNVAL and curl goes into an
infinite loop. :( Things are fine when select is used. So unless you
want to special-case the code in telnet.c, Mac OS X will have to
stick with select.

I do have a patch to configure.ac that makes the check for a broken
poll more generic (shamelessly borrowed from glib2) rather than just
checking for OS X. It specifically checks that poll works for
devices. I've also included a patch to telnet.c that checks for
POLLIN|POLLHUP rather than just POLLIN to be consistent with select.c.

Daniel

Index: configure.ac
===================================================================
RCS file: /cvsroot/curl/curl/configure.ac,v
retrieving revision 1.215
diff -u -r1.215 configure.ac
--- configure.ac 7 Feb 2007 17:34:30 -0000 1.215
+++ configure.ac 10 Feb 2007 23:11:17 -0000
@@ -1783,16 +1783,33 @@
    CURL_CHECK_NI_WITHSCOPEID
fi
-AC_MSG_CHECKING([if we are Mac OS X (to disable poll)])
-disable_poll=no
-case $host in
- *-*-darwin*)
- disable_poll="yes";
- ;;
- *)
- ;;
-esac
-AC_MSG_RESULT($disable_poll)
+# Check for Mac OS X's broken poll
+if test "$ac_cv_func_poll" = "yes"; then
+ AC_MSG_CHECKING([if poll works on devices])
+ AC_RUN_IFELSE([[
+#include <stdlib.h>
+#include <fcntl.h>
+#include <poll.h>
+ 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);
+ }]],
+ disable_poll="no"
+ AC_MSG_RESULT(yes),
+ disable_poll="yes"
+ AC_MSG_RESULT(no),
+ disable_poll="no"
+ AC_MSG_RESULT(cross-compiling assumes yes)
+ ) dnl end of AC_RUN_IFELSE
+fi dnl poll() was found
if test "$disable_poll" = "no"; then
Index: lib/telnet.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/telnet.c,v
retrieving revision 1.86
diff -u -r1.86 telnet.c
--- lib/telnet.c 5 Feb 2007 22:51:33 -0000 1.86
+++ lib/telnet.c 10 Feb 2007 23:11:48 -0000
@@ -1343,7 +1343,7 @@
      case 0: /* timeout */
        break;
      default: /* read! */
- if(pfd[1].revents & POLLIN) { /* read from stdin */
+ if(pfd[1].revents & (POLLIN|POLLHUP)) { /* read from stdin */
          unsigned char outbuf[2];
          int out_count = 0;
          ssize_t bytes_written;
@@ -1362,7 +1362,7 @@
          }
        }
- if(pfd[0].revents & POLLIN) {
+ if(pfd[0].revents & (POLLIN|POLLHUP)) {
          /* This OUGHT to check the return code... */
          (void)Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
Received on 2007-02-13