summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--configure.in2
-rw-r--r--include/ruby/io.h14
-rw-r--r--thread.c58
4 files changed, 77 insertions, 4 deletions
diff --git a/ChangeLog b/ChangeLog
index a470c2b4c3..b2db0e44af 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Wed May 4 10:01:27 2011 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * thread.c (rb_wait_for_single_fd): new. poll(2) based backend for rb_wait_for_single_fd().
+ Now only Linux uses it.
+
+ The patch was written by Eric Wong. [Ruby 1.9 - Feature #4531]
+
Wed May 4 09:56:57 2011 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
* thread.c (rb_wait_for_single_fd): new.
diff --git a/configure.in b/configure.in
index 5692eb150e..512f8b859a 100644
--- a/configure.in
+++ b/configure.in
@@ -1310,7 +1310,7 @@ AC_CHECK_FUNCS(fmod killpg wait4 waitpid fork spawnv syscall __syscall chroot ge
dlopen sigprocmask sigaction sigsetjmp _setjmp _longjmp\
setsid telldir seekdir fchmod cosh sinh tanh log2 round\
setuid setgid daemon select_large_fdset setenv unsetenv\
- mktime timegm gmtime_r clock_gettime gettimeofday\
+ mktime timegm gmtime_r clock_gettime gettimeofday poll\
pread sendfile shutdown sigaltstack dl_iterate_phdr)
AC_CACHE_CHECK(for unsetenv returns a value, rb_cv_unsetenv_return_value,
diff --git a/include/ruby/io.h b/include/ruby/io.h
index bf1b9f8b37..cfdfaf1fb7 100644
--- a/include/ruby/io.h
+++ b/include/ruby/io.h
@@ -27,9 +27,17 @@ extern "C" {
#include <stdio_ext.h>
#endif
-#define RB_WAITFD_IN 0x001
-#define RB_WAITFD_PRI 0x002
-#define RB_WAITFD_OUT 0x004
+#include "ruby/config.h"
+#if defined(HAVE_POLL)
+# include <poll.h>
+# define RB_WAITFD_IN POLLIN
+# define RB_WAITFD_PRI POLLPRI
+# define RB_WAITFD_OUT POLLOUT
+#else
+# define RB_WAITFD_IN 0x001
+# define RB_WAITFD_PRI 0x002
+# define RB_WAITFD_OUT 0x004
+#endif
#if defined __GNUC__ && __GNUC__ >= 4
#pragma GCC visibility push(default)
diff --git a/thread.c b/thread.c
index 8d681f7f41..6246243706 100644
--- a/thread.c
+++ b/thread.c
@@ -2704,6 +2704,63 @@ rb_thread_fd_select(int max, rb_fdset_t * read, rb_fdset_t * write, rb_fdset_t *
return do_select(max, read, write, except, timeout);
}
+/*
+ * poll() is supported by many OSes, but so far Linux is the only
+ * one we know of that supports using poll() in all places select()
+ * would work.
+ */
+#if defined(HAVE_POLL) && defined(linux)
+# define USE_POLL
+#endif
+
+#ifdef USE_POLL
+/*
+ * returns a mask of events
+ */
+int
+rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
+{
+ struct pollfd fds;
+ int result, lerrno;
+ double start;
+ int timeout = tv ? tv->tv_sec * 1000 + (tv->tv_usec + 500) / 1000 : -1;
+
+ fds.fd = fd;
+ fds.events = (short)events;
+
+retry:
+ lerrno = 0;
+ start = timeofday();
+ BLOCKING_REGION({
+ result = poll(&fds, 1, timeout);
+ if (result < 0) lerrno = errno;
+ }, ubf_select, GET_THREAD());
+
+ if (result > 0) {
+ /* remain compatible with select(2)-based implementation */
+ result = (int)(fds.revents & fds.events);
+ return result == 0 ? events : result;
+ }
+
+ if (result < 0) {
+ errno = lerrno;
+ switch (errno) {
+ case EINTR:
+#ifdef ERESTART
+ case ERESTART:
+#endif
+ if (timeout > 0) {
+ timeout -= (timeofday() - start) * 1000;
+ if (timeout < 0)
+ timeout = 0;
+ }
+ goto retry;
+ }
+ }
+
+ return result;
+}
+#else /* ! USE_POLL - implement rb_io_poll_fd() using select() */
static rb_fdset_t *init_set_fd(int fd, rb_fdset_t *fds)
{
rb_fd_init(fds);
@@ -2777,6 +2834,7 @@ rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
return r;
}
+#endif /* ! USE_POLL */
/*
* for GC