about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2010-08-02 08:28:15 +0000
committerEric Wong <normalperson@yhbt.net>2010-08-02 08:31:37 +0000
commit3cf7ec34b6319693af14215ebb0da51c3e6a4603 (patch)
tree0a945e53ec5a4b7d566260363b0e7d1fd166e13b
parent3ca83d322486bb3da20d974af7faa74f9df891d8 (diff)
downloadruby_posix_mq-3cf7ec34b6319693af14215ebb0da51c3e6a4603.tar.gz
On ENOMEM, EMFILE, and ENFILE errors, it is customary to
invoke the Ruby GC and free up resources and retry the
system call.
-rw-r--r--ext/posix_mq/posix_mq.c30
-rw-r--r--test/test_posix_mq.rb6
2 files changed, 30 insertions, 6 deletions
diff --git a/ext/posix_mq/posix_mq.c b/ext/posix_mq/posix_mq.c
index db50534..04c1ea0 100644
--- a/ext/posix_mq/posix_mq.c
+++ b/ext/posix_mq/posix_mq.c
@@ -362,8 +362,14 @@ static VALUE init(int argc, VALUE *argv, VALUE self)
         }
 
         mq->des = (mqd_t)xopen(&x);
-        if (mq->des == MQD_INVALID)
-                rb_sys_fail("mq_open");
+        if (mq->des == MQD_INVALID) {
+                if (errno == ENOMEM || errno == EMFILE || errno == ENFILE) {
+                        rb_gc();
+                        mq->des = (mqd_t)xopen(&x);
+                }
+                if (mq->des == MQD_INVALID)
+                        rb_sys_fail("mq_open");
+        }
 
         mq->name = rb_str_dup(name);
         if (x.oflags & O_NONBLOCK)
@@ -736,6 +742,20 @@ static void thread_notify_fd(union sigval sv)
         while ((write(fd, "", 1) < 0) && (errno == EINTR || errno == EAGAIN));
 }
 
+static void my_mq_notify(mqd_t des, struct sigevent *not)
+{
+        mqd_t rv = mq_notify(des, not);
+
+        if (rv == MQD_INVALID) {
+                if (errno == ENOMEM) {
+                        rb_gc();
+                        rv = mq_notify(des, not);
+                }
+                if (rv == MQD_INVALID)
+                        rb_sys_fail("mq_notify");
+        }
+}
+
 /* :nodoc: */
 static VALUE setnotify_exec(VALUE self, VALUE io, VALUE thr)
 {
@@ -763,8 +783,7 @@ static VALUE setnotify_exec(VALUE self, VALUE io, VALUE thr)
                 rb_funcall(mq->thread, id_kill, 0, 0);
         mq->thread = thr;
 
-        if (mq_notify(mq->des, &not) < 0)
-                rb_sys_fail("mq_notify");
+        my_mq_notify(mq->des, &not);
 
         return thr;
 }
@@ -834,8 +853,7 @@ static VALUE setnotify(VALUE self, VALUE arg)
                 rb_raise(rb_eArgError, "must be a signal or nil");
         }
 
-        if (mq_notify(mq->des, notification) < 0)
-                rb_sys_fail("mq_notify");
+        my_mq_notify(mq->des, notification);
 
         return rv;
 }
diff --git a/test/test_posix_mq.rb b/test/test_posix_mq.rb
index 964fa94..37ca664 100644
--- a/test/test_posix_mq.rb
+++ b/test/test_posix_mq.rb
@@ -27,6 +27,12 @@ class Test_POSIX_MQ < Test::Unit::TestCase
     assert @mq.closed?
   end
 
+  def test_gc
+    assert_nothing_raised do
+      2025.times { POSIX_MQ.new(@path, :rw) }
+    end
+  end
+
   def test_name_clobber_proof
     @mq = POSIX_MQ.new(@path, :rw)
     tmp = @mq.name