From 3cf7ec34b6319693af14215ebb0da51c3e6a4603 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Mon, 2 Aug 2010 08:28:15 +0000 Subject: [PATCH] open/notify: invoke GC if needed On ENOMEM, EMFILE, and ENFILE errors, it is customary to invoke the Ruby GC and free up resources and retry the system call. --- ext/posix_mq/posix_mq.c | 30 ++++++++++++++++++++++++------ test/test_posix_mq.rb | 6 ++++++ 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, ¬) < 0) - rb_sys_fail("mq_notify"); + my_mq_notify(mq->des, ¬); 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 -- 2.11.4.GIT