about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2010-09-26 02:46:51 +0000
committerEric Wong <normalperson@yhbt.net>2010-09-26 02:53:04 +0000
commita226d237666728ea9242f6079b2c76528d53cdb2 (patch)
tree44a04f643cecf78dc6ffaae2979732569f63143a
parent3ca3a23d3e68f62af6d57cf22825b2751c226fff (diff)
downloadsleepy_penguin-a226d237666728ea9242f6079b2c76528d53cdb2.tar.gz
There can be ways (in the future) where supporting
Epoll#dup/Epoll#clone can proveuseful, so continue to
support them until proven otherwise.
-rw-r--r--ext/sleepy_penguin/epoll.c19
-rw-r--r--test/test_epoll.rb4
2 files changed, 20 insertions, 3 deletions
diff --git a/ext/sleepy_penguin/epoll.c b/ext/sleepy_penguin/epoll.c
index 83f1568..3540c51 100644
--- a/ext/sleepy_penguin/epoll.c
+++ b/ext/sleepy_penguin/epoll.c
@@ -112,6 +112,7 @@ static VALUE alloc(VALUE klass)
         ep->fd = -1;
         ep->io = Qnil;
         ep->capa = step;
+        ep->flags = EPOLL_CLOEXEC;
         ep->events = xmalloc(sizeof(struct epoll_event) * ep->capa);
 
         return self;
@@ -448,6 +449,19 @@ static VALUE epclosed(VALUE self)
         return ep->fd == -1 ? Qtrue : Qfalse;
 }
 
+static int cloexec_dup(struct rb_epoll *ep)
+{
+#ifdef F_DUPFD_CLOEXEC
+        int flags = ep->flags & EPOLL_CLOEXEC ? F_DUPFD_CLOEXEC : F_DUPFD;
+        int fd = fcntl(ep->fd, flags, 0);
+#else
+        int fd = dup(ep->fd);
+        if (fd >= 0)
+                (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
+#endif
+        return fd;
+}
+
 static VALUE init_copy(VALUE copy, VALUE orig)
 {
         struct rb_epoll *a = ep_get(orig);
@@ -457,11 +471,12 @@ static VALUE init_copy(VALUE copy, VALUE orig)
                NIL_P(b->io) && "Ruby broken?");
 
         ep_check(a);
-        b->fd = dup(a->fd);
+        b->flags = a->flags;
+        b->fd = cloexec_dup(a);
         if (b->fd == -1) {
                 if (errno == ENFILE || errno == EMFILE) {
                         rb_gc();
-                        b->fd = dup(a->fd);
+                        b->fd = cloexec_dup(a);
                 }
                 if (b->fd == -1)
                         rb_sys_fail("dup");
diff --git a/test/test_epoll.rb b/test/test_epoll.rb
index 0acf08d..50daf3e 100644
--- a/test/test_epoll.rb
+++ b/test/test_epoll.rb
@@ -31,6 +31,8 @@ class TestEpoll < Test::Unit::TestCase
     fork { @ep.add(@rd, Epoll::IN); exit!(0) }
     fork { @ep.set(@rd, Epoll::IN); exit!(0) }
     fork { @ep.to_io; exit!(0) }
+    fork { @ep.dup; exit!(0) }
+    fork { @ep.clone; exit!(0) }
     fork { @ep.close; exit!(0) }
     fork { @ep.closed?; exit!(0) }
     fork {
@@ -202,7 +204,7 @@ class TestEpoll < Test::Unit::TestCase
 
   def test_dup
     tmp = []
-    clone = @ep.clone
+    clone = @ep.dup
     assert @ep.to_io.fileno != clone.to_io.fileno
     clone.add @wr, Epoll::OUT
     @ep.wait(nil, 0) { |flags, obj| tmp << [ flags, obj ] }