about summary refs log tree commit homepage
path: root/ext/sleepy_penguin/epoll.c
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2011-05-15 00:33:04 +0000
committerEric Wong <normalperson@yhbt.net>2011-05-19 20:39:33 +0000
commitc41c94fd1a7d3c4c92ffc81c8816e629bfa3d8a6 (patch)
treeb03ec8a36816f0c3a334e63cc02ebef581c02aec /ext/sleepy_penguin/epoll.c
parent6df27bca6c4aba321ee24e4dacfa507e1deaac73 (diff)
downloadsleepy_penguin-c41c94fd1a7d3c4c92ffc81c8816e629bfa3d8a6.tar.gz
Diffstat (limited to 'ext/sleepy_penguin/epoll.c')
-rw-r--r--ext/sleepy_penguin/epoll.c51
1 files changed, 47 insertions, 4 deletions
diff --git a/ext/sleepy_penguin/epoll.c b/ext/sleepy_penguin/epoll.c
index 81e7623..66bfc8c 100644
--- a/ext/sleepy_penguin/epoll.c
+++ b/ext/sleepy_penguin/epoll.c
@@ -1,6 +1,7 @@
 #include "sleepy_penguin.h"
 #include <sys/epoll.h>
 #include <pthread.h>
+#include <time.h>
 #include "missing_epoll.h"
 #ifdef HAVE_RUBY_ST_H
 #  include <ruby/st.h>
@@ -303,6 +304,36 @@ static VALUE epwait_result(struct rb_epoll *ep, int n)
         return INT2NUM(n);
 }
 
+static int epoll_expired_p(struct timespec *expire, struct rb_epoll *ep)
+{
+        struct timespec now;
+
+        fprintf(stderr, "old_timeout: %d\n", ep->timeout);
+        if (ep->timeout < 0)
+                return 0;
+        if (ep->timeout == 0)
+                return 1;
+
+        clock_gettime(CLOCK_MONOTONIC, &now);
+        if ((expire->tv_sec > now.tv_sec) ||
+            (expire->tv_sec == now.tv_sec) &&
+             (expire->tv_nsec < now.tv_nsec)) {
+                now.tv_sec = expire->tv_sec - now.tv_sec;
+                now.tv_nsec = expire->tv_nsec - now.tv_nsec;
+                if (now.tv_nsec < 0) {
+                        now.tv_nsec += 1000000000;
+                        now.tv_sec--;
+                }
+                ep->timeout = (now.tv_sec * 1000);
+                ep->timeout += (now.tv_nsec + 500000) / 1000000;
+                if (ep->timeout < 0)
+                        ep->timeout = 0;
+                fprintf(stderr, "new_timeout: %d\n", ep->timeout);
+                return 0;
+        }
+        return 1;
+}
+
 #if defined(HAVE_RB_THREAD_BLOCKING_REGION)
 static VALUE nogvl_wait(void *args)
 {
@@ -314,7 +345,17 @@ static VALUE nogvl_wait(void *args)
 
 static VALUE real_epwait(struct rb_epoll *ep)
 {
-        int n = (int)rb_sp_io_region(nogvl_wait, ep);
+        int n;
+        struct timespec expire;
+
+        if (ep->timeout > 0) {
+                clock_gettime(CLOCK_MONOTONIC, &expire);
+                expire.tv_sec += ep->timeout / 1000;
+                expire.tv_nsec += (ep->timeout % 1000) * 1000000;
+        }
+        do {
+                n = (int)rb_sp_io_region(nogvl_wait, ep);
+        } while (n == -1 && errno == EINTR && ! epoll_expired_p(&expire, ep));
 
         return epwait_result(ep, n);
 }
@@ -343,9 +384,11 @@ static int safe_epoll_wait(struct rb_epoll *ep)
 {
         int n;
 
-        TRAP_BEG;
-        n = epoll_wait(ep->fd, ep->events, ep->maxevents, 0);
-        TRAP_END;
+        do {
+                TRAP_BEG;
+                n = epoll_wait(ep->fd, ep->events, ep->maxevents, 0);
+                TRAP_END;
+        } while (n == -1 && errno == EINTR);
 
         return n;
 }