From 73dfbeb1d59fbc1e22651cb4da8ee85f0a6fd9ce Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Tue, 3 Jul 2012 17:57:44 -0700 Subject: blocking functions do not raise Errno::EINTR Blocking functions should not raise Errno::EINTR to match existing semantics of Ruby IO methods (e.g. IO.select, IO#read, IO#write). This makes user code easier to read/write. Like th Ruby methods we emulate, we only reacquire the GVL on EINTR to fire signal handlers, but otherwise emulate SA_RESTART semantics. This is a backwards-incompatible API change (but unlikely to break existing code). --- ext/posix_mq/posix_mq.c | 12 +++++++++++- test/test_posix_mq.rb | 10 ++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/ext/posix_mq/posix_mq.c b/ext/posix_mq/posix_mq.c index 2958352..df667e3 100644 --- a/ext/posix_mq/posix_mq.c +++ b/ext/posix_mq/posix_mq.c @@ -542,8 +542,11 @@ static VALUE _send(int sflags, int argc, VALUE *argv, VALUE self) x.timeout = convert_timeout(&expire, timeout); x.msg_prio = NIL_P(prio) ? 0 : NUM2UINT(prio); +retry: rv = (mqd_t)rb_thread_blocking_region(xsend, &x, RUBY_UBF_IO, 0); if (rv == MQD_INVALID) { + if (errno == EINTR) + goto retry; if (errno == EAGAIN && (sflags & PMQ_TRY)) return Qfalse; rb_sys_fail("mq_send"); @@ -574,9 +577,13 @@ static VALUE send0(VALUE self, VALUE buffer) x.timeout = NULL; x.msg_prio = 0; +retry: rv = (mqd_t)rb_thread_blocking_region(xsend, &x, RUBY_UBF_IO, 0); - if (rv == MQD_INVALID) + if (rv == MQD_INVALID) { + if (errno == EINTR) + goto retry; rb_sys_fail("mq_send"); + } return self; } @@ -678,8 +685,11 @@ static VALUE _receive(int rflags, int argc, VALUE *argv, VALUE self) x.msg_len = (size_t)mq->attr.mq_msgsize; x.des = mq->des; +retry: r = (ssize_t)rb_thread_blocking_region(xrecv, &x, RUBY_UBF_IO, 0); if (r < 0) { + if (errno == EINTR) + goto retry; if (errno == EAGAIN && (rflags & PMQ_TRY)) return Qnil; rb_sys_fail("mq_receive"); diff --git a/test/test_posix_mq.rb b/test/test_posix_mq.rb index 5b78c22..8d6b014 100644 --- a/test/test_posix_mq.rb +++ b/test/test_posix_mq.rb @@ -118,16 +118,18 @@ class Test_POSIX_MQ < Test::Unit::TestCase end alarm or return warn "alarm() not found in #{libcs.inspect}" alarms = 0 - trap("ALRM") { alarms += 1 } + trap("ALRM") do + alarms += 1 + Thread.new { @mq.send("HI") } + end interval = 1 alarm.call interval @mq = POSIX_MQ.new(@path, :rw) assert ! @mq.nonblock? t0 = Time.now - a = nil - assert_raises(Errno::EINTR) { a = @mq.receive } + a = @mq.receive elapsed = Time.now - t0 - assert_nil a + assert_equal(["HI", 0], a) assert elapsed >= interval, elapsed.inspect assert elapsed < 1.10, elapsed.inspect assert_equal 1, alarms -- cgit v1.2.3-24-ge0c7