about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <e@yhbt.net>2011-03-06 02:17:57 +0000
committerEric Wong <normalperson@yhbt.net>2011-03-06 02:30:06 +0000
commite29be690d10747c09aaf4839a4a5a4a0ed11729a (patch)
tree95cd44291ab1ea4c008932e5f48e2afb7c9939f4
parentf14855b5b746c6bb6c6edb0dada2803ab60c5b94 (diff)
downloadsleepy_penguin-e29be690d10747c09aaf4839a4a5a4a0ed11729a.tar.gz
This modifies an existing SignalFD.
-rw-r--r--ext/sleepy_penguin/signalfd.c69
-rw-r--r--test/test_signalfd.rb10
2 files changed, 71 insertions, 8 deletions
diff --git a/ext/sleepy_penguin/signalfd.c b/ext/sleepy_penguin/signalfd.c
index 91b734c..17cd41e 100644
--- a/ext/sleepy_penguin/signalfd.c
+++ b/ext/sleepy_penguin/signalfd.c
@@ -57,23 +57,48 @@ static void value2sigset(sigset_t *mask, VALUE set)
         }
 }
 
-static void sfd_args(int *flags, sigset_t *mask, int argc, VALUE *argv)
+static int cur_flags(int fd)
 {
-        VALUE vmask, vflags;
-
-        rb_scan_args(argc, argv, "02", &vmask, &vflags);
-        *flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
-        value2sigset(mask, vmask);
+        int rv = 0;
+#ifdef SFD_CLOEXEC
+        {
+                int flags = fcntl(fd, F_GETFD);
+                if (flags == -1) rb_sys_fail("fcntl(F_GETFD)");
+                if (flags & FD_CLOEXEC) rv |= SFD_CLOEXEC;
+        }
+#endif
+#ifdef SFD_NONBLOCK
+        {
+                int flags = fcntl(fd, F_GETFL);
+                if (flags == -1) rb_sys_fail("fcntl(F_GETFL)");
+                if (flags & O_NONBLOCK) rv |= SFD_NONBLOCK;
+        }
+#endif
+        return rv;
 }
 
+/*
+ * call-seq:
+ *        include SleepyPenguin
+ *        sfd = SignalFD.new
+ *        ...
+ *        sfd.update! signals
+ *        sfd.update! signals, flags
+ *
+ * Updates the signal mask watched for by the given +sigfd+.
+ * Takes the same arguments as SignalFD.new.
+ */
 static VALUE update_bang(int argc, VALUE *argv, VALUE self)
 {
+        VALUE vmask, vflags;
         sigset_t mask;
         int flags;
         int fd = my_fileno(self);
         int rc;
 
-        sfd_args(&flags, &mask, argc, argv);
+        rb_scan_args(argc, argv, "02", &vmask, &vflags);
+        flags = NIL_P(vflags) ? cur_flags(fd) : NUM2INT(vflags);
+        value2sigset(&mask, vmask);
 
         rc = signalfd(fd, &mask, flags);
         if (rc == -1)
@@ -81,13 +106,34 @@ static VALUE update_bang(int argc, VALUE *argv, VALUE self)
         return self;
 }
 
+/*
+ * call-seq:
+ *        include SleepyPenguin
+ *        SignalFD.new -> SignalFD IO object
+ *        SignalFD.new(signals) -> SignalFD IO object
+ *        SignalFD.new(signals, flags) -> SignalFD IO object
+ *
+ * Creates a new SignalFD object to watch given +signals+ with +flags+.
+ *
+ * +signals+ is an Array of signal names or a single signal name that
+ * Signal.trap understands:
+ *
+ *        signals = [ :USR1, "USR2" ]
+ *        signals = :USR1
+ *        signals = 15
+ *
+ * +flags+ is a mask of SignalFD::CLOEXEC and SignalFD::NONBLOCK
+ */
 static VALUE s_new(int argc, VALUE *argv, VALUE klass)
 {
+        VALUE vmask, vflags;
         sigset_t mask;
         int flags;
         int fd;
 
-        sfd_args(&flags, &mask, argc, argv);
+        rb_scan_args(argc, argv, "02", &vmask, &vflags);
+        flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
+        value2sigset(&mask, vmask);
 
         fd = signalfd(-1, &mask, flags);
         if (fd == -1) {
@@ -147,6 +193,12 @@ static ssize_t do_sfd_read(struct signalfd_siginfo *ssi)
 }
 #endif /* ! HAVE_RB_THREAD_BLOCKING_REGION */
 
+/*
+ * call-seq:
+ *        sfd.take -> SignalFD::SigInfo object
+ *
+ * Returns the next SigInfo object representing a received signal.
+ */
 static VALUE sfd_take(VALUE self)
 {
         VALUE rv = ssi_alloc(cSigInfo);
@@ -205,6 +257,7 @@ void sleepy_penguin_init_signalfd(void)
 #endif
 
         rb_define_method(cSignalFD, "take", sfd_take, 0);
+        rb_define_method(cSignalFD, "update!", update_bang, -1);
         id_for_fd = rb_intern("for_fd");
         ssi_members = rb_ary_new();
         rb_define_const(cSigInfo, "MEMBERS", ssi_members);
diff --git a/test/test_signalfd.rb b/test/test_signalfd.rb
index 00fe18f..36486dc 100644
--- a/test/test_signalfd.rb
+++ b/test/test_signalfd.rb
@@ -21,4 +21,14 @@ class TestSignalFD < Test::Unit::TestCase
     assert_equal pid, siginfo.pid
     assert Process.waitpid2(pid)[1].success?
   end
+
+  def test_update
+    assert_nothing_raised do
+      @sfd = SignalFD.new
+      @sfd.update! Signal.list["USR1"]
+      @sfd.update! [ "USR1", Signal.list["USR2"] ]
+      @sfd.update! [ "USR1", :USR2 ]
+      @sfd.update! [ Signal.list["USR1"], Signal.list["USR2"] ]
+    end
+  end
 end if RUBY_VERSION =~ %r{\A1\.9} && defined?(SleepyPenguin::SignalFD)