posix_mq RubyGem user+dev discussion/patches/pulls/bugs/help
 help / color / mirror / code / Atom feed
* [PATCH 1/2] prepare for rb_thread_blocking_region removal
@ 2014-02-15 13:33 Eric Wong
  2014-02-15 13:33 ` [PATCH 2/2] avoid deprecated rb_thread_blocking_region in Ruby 2.0/2.1 Eric Wong
  0 siblings, 1 reply; 2+ messages in thread
From: Eric Wong @ 2014-02-15 13:33 UTC (permalink / raw)
  To: ruby.posix.mq

It'll be OK to use rb_thread_call_without_gvl when
rb_thread_blocking_region is not detectable at all.
We still use rb_thread_blocking_region for Ruby 2.0-2.1 because
rb_thread_call_without_gvl was detectable in 1.9.3, but not
usable as an internal symbol.

ref: https://bugs.ruby-lang.org/issues/9502
---
 ext/posix_mq/extconf.rb |  1 +
 ext/posix_mq/posix_mq.c | 88 +++++++++++++++++++++++++++++--------------------
 2 files changed, 53 insertions(+), 36 deletions(-)

diff --git a/ext/posix_mq/extconf.rb b/ext/posix_mq/extconf.rb
index db50ee3..eb799b2 100644
--- a/ext/posix_mq/extconf.rb
+++ b/ext/posix_mq/extconf.rb
@@ -6,6 +6,7 @@ have_header("mqueue.h") or abort "mqueue.h header missing"
 have_header("pthread.h")
 have_func("rb_str_set_len")
 have_func('rb_thread_blocking_region')
+have_func('rb_thread_call_without_gvl')
 have_library("m")
 have_library("rt")
 have_library("pthread")
diff --git a/ext/posix_mq/posix_mq.c b/ext/posix_mq/posix_mq.c
index 7a3dc14..ad8bcff 100644
--- a/ext/posix_mq/posix_mq.c
+++ b/ext/posix_mq/posix_mq.c
@@ -96,17 +96,28 @@ static void rb_18_str_set_len(VALUE str, long len)
 #endif /* !defined(HAVE_RB_STR_SET_LEN) */
 
 /* partial emulation of the 1.9 rb_thread_blocking_region under 1.8 */
-#ifndef HAVE_RB_THREAD_BLOCKING_REGION
+#if defined(HAVE_RB_THREAD_BLOCKING_REGION) && \
+    defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
+/*
+ * Ruby 1.9 - 2.1 (we use deprecated rb_thread_blocking_region in 2.0+
+ * because we can detect (but not use) rb_thread_blocking_region in 1.9.3
+ */
+typedef VALUE(*my_blocking_fn_t)(void*);
+#  define WITHOUT_GVL(fn,a,ubf,b) \
+	rb_thread_blocking_region((my_blocking_fn_t)(fn),(a),(ubf),(b))
+#elif defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL) /* Ruby 2.2+ */
+#include <ruby/thread.h>
+#  define WITHOUT_GVL(fn,a,ubf,b) \
+	rb_thread_call_without_gvl((fn),(a),(ubf),(b))
+#else /* Ruby 1.8 */
 #  include <rubysig.h>
 #  define RUBY_UBF_IO ((rb_unblock_function_t *)-1)
 typedef void rb_unblock_function_t(void *);
-typedef VALUE rb_blocking_function_t(void *);
-static VALUE
-rb_thread_blocking_region(
-	rb_blocking_function_t *func, void *data1,
-	rb_unblock_function_t *ubf, void *data2)
+typedef void * rb_blocking_function_t(void *);
+static void * WITHOUT_GVL(rb_blocking_function_t *func, void *data1,
+			rb_unblock_function_t *ubf, void *data2)
 {
-	VALUE rv;
+	void *rv;
 
 	assert(RUBY_UBF_IO == ubf && "RUBY_UBF_IO required for emulation");
 
@@ -120,6 +131,7 @@ rb_thread_blocking_region(
 
 /* used to pass arguments to mq_open inside blocking region */
 struct open_args {
+	mqd_t des;
 	int argc;
 	const char *name;
 	int oflags;
@@ -130,6 +142,10 @@ struct open_args {
 /* used to pass arguments to mq_send/mq_receive inside blocking region */
 struct rw_args {
 	mqd_t des;
+	union {
+		ssize_t received;
+		int retval;
+	};
 	char *msg_ptr;
 	size_t msg_len;
 	unsigned msg_prio;
@@ -229,43 +245,44 @@ static struct timespec *convert_timeout(struct timespec *dest, VALUE t)
 }
 
 /* (may) run without GVL */
-static VALUE xopen(void *ptr)
+static void * xopen(void *ptr)
 {
 	struct open_args *x = ptr;
-	mqd_t rv;
 
 	switch (x->argc) {
-	case 2: rv = mq_open(x->name, x->oflags); break;
-	case 3: rv = mq_open(x->name, x->oflags, x->mode, NULL); break;
-	case 4: rv = mq_open(x->name, x->oflags, x->mode, &x->attr); break;
-	default: rv = MQD_INVALID;
+	case 2: x->des = mq_open(x->name, x->oflags); break;
+	case 3: x->des = mq_open(x->name, x->oflags, x->mode, NULL); break;
+	case 4: x->des = mq_open(x->name, x->oflags, x->mode, &x->attr); break;
+	default: x->des = MQD_INVALID;
 	}
 
-	return (VALUE)rv;
+	return NULL;
 }
 
 /* runs without GVL */
-static VALUE xsend(void *ptr)
+static void *xsend(void *ptr)
 {
 	struct rw_args *x = ptr;
 
-	if (x->timeout)
-		return (VALUE)mq_timedsend(x->des, x->msg_ptr, x->msg_len,
-		                           x->msg_prio, x->timeout);
+	x->retval = x->timeout ?
+		mq_timedsend(x->des, x->msg_ptr, x->msg_len,
+		             x->msg_prio, x->timeout) :
+		mq_send(x->des, x->msg_ptr, x->msg_len, x->msg_prio);
 
-	return (VALUE)mq_send(x->des, x->msg_ptr, x->msg_len, x->msg_prio);
+	return NULL;
 }
 
 /* runs without GVL */
-static VALUE xrecv(void *ptr)
+static void * xrecv(void *ptr)
 {
 	struct rw_args *x = ptr;
 
-	if (x->timeout)
-		return (VALUE)mq_timedreceive(x->des, x->msg_ptr, x->msg_len,
-		                              &x->msg_prio, x->timeout);
+	x->received = x->timeout ?
+		mq_timedreceive(x->des, x->msg_ptr, x->msg_len,
+		                &x->msg_prio, x->timeout) :
+		mq_receive(x->des, x->msg_ptr, x->msg_len, &x->msg_prio);
 
-	return (VALUE)mq_receive(x->des, x->msg_ptr, x->msg_len, &x->msg_prio);
+	return NULL;
 }
 
 /* called by GC */
@@ -438,7 +455,8 @@ static VALUE init(int argc, VALUE *argv, VALUE self)
 		check_struct_type(attr);
 	}
 
-	mq->des = (mqd_t)xopen(&x);
+	(void)xopen(&x);
+	mq->des = x.des;
 	if (mq->des == MQD_INVALID) {
 		switch (errno) {
 		case ENOMEM:
@@ -446,7 +464,8 @@ static VALUE init(int argc, VALUE *argv, VALUE self)
 		case ENFILE:
 		case ENOSPC:
 			rb_gc();
-			mq->des = (mqd_t)xopen(&x);
+			(void)xopen(&x);
+			mq->des = x.des;
 		}
 		if (mq->des == MQD_INVALID)
 			rb_sys_fail("mq_open");
@@ -532,7 +551,6 @@ static VALUE _send(int sflags, int argc, VALUE *argv, VALUE self)
 	struct posix_mq *mq = get(self, 1);
 	struct rw_args x;
 	VALUE buffer, prio, timeout;
-	int rv;
 	struct timespec expire;
 
 	rb_scan_args(argc, argv, "12", &buffer, &prio, &timeout);
@@ -543,8 +561,8 @@ static VALUE _send(int sflags, int argc, VALUE *argv, VALUE self)
 	x.msg_prio = NIL_P(prio) ? 0 : NUM2UINT(prio);
 
 retry:
-	rv = (int)rb_thread_blocking_region(xsend, &x, RUBY_UBF_IO, 0);
-	if (rv == -1) {
+	WITHOUT_GVL(xsend, &x, RUBY_UBF_IO, 0);
+	if (x.retval == -1) {
 		if (errno == EINTR)
 			goto retry;
 		if (errno == EAGAIN && (sflags & PMQ_TRY))
@@ -570,7 +588,6 @@ static VALUE send0(VALUE self, VALUE buffer)
 {
 	struct posix_mq *mq = get(self, 1);
 	struct rw_args x;
-	int rv;
 
 	setup_send_buffer(&x, buffer);
 	x.des = mq->des;
@@ -578,8 +595,8 @@ static VALUE send0(VALUE self, VALUE buffer)
 	x.msg_prio = 0;
 
 retry:
-	rv = (int)rb_thread_blocking_region(xsend, &x, RUBY_UBF_IO, 0);
-	if (rv == -1) {
+	WITHOUT_GVL(xsend, &x, RUBY_UBF_IO, 0);
+	if (x.retval == -1) {
 		if (errno == EINTR)
 			goto retry;
 		rb_sys_fail("mq_send");
@@ -662,7 +679,6 @@ static VALUE _receive(int rflags, int argc, VALUE *argv, VALUE self)
 	struct posix_mq *mq = get(self, 1);
 	struct rw_args x;
 	VALUE buffer, timeout;
-	ssize_t r;
 	struct timespec expire;
 
 	if (mq->attr.mq_msgsize < 0) {
@@ -686,8 +702,8 @@ static VALUE _receive(int rflags, int argc, VALUE *argv, VALUE self)
 	x.des = mq->des;
 
 retry:
-	r = (ssize_t)rb_thread_blocking_region(xrecv, &x, RUBY_UBF_IO, 0);
-	if (r < 0) {
+	WITHOUT_GVL(xrecv, &x, RUBY_UBF_IO, 0);
+	if (x.received < 0) {
 		if (errno == EINTR)
 			goto retry;
 		if (errno == EAGAIN && (rflags & PMQ_TRY))
@@ -695,7 +711,7 @@ retry:
 		rb_sys_fail("mq_receive");
 	}
 
-	rb_str_set_len(buffer, r);
+	rb_str_set_len(buffer, x.received);
 
 	if (rflags & PMQ_WANTARRAY)
 		return rb_ary_new3(2, buffer, UINT2NUM(x.msg_prio));
-- 
1.9.0.rc3.13.gda73b5f



^ permalink raw reply related	[flat|nested] 2+ messages in thread

* [PATCH 2/2] avoid deprecated rb_thread_blocking_region in Ruby 2.0/2.1
  2014-02-15 13:33 [PATCH 1/2] prepare for rb_thread_blocking_region removal Eric Wong
@ 2014-02-15 13:33 ` Eric Wong
  0 siblings, 0 replies; 2+ messages in thread
From: Eric Wong @ 2014-02-15 13:33 UTC (permalink / raw)
  To: ruby.posix.mq

This will be removed in Ruby 2.2, so avoid the deprecation warning.
---
 ext/posix_mq/posix_mq.c | 21 +++++++++------------
 1 file changed, 9 insertions(+), 12 deletions(-)

diff --git a/ext/posix_mq/posix_mq.c b/ext/posix_mq/posix_mq.c
index ad8bcff..cbc32b9 100644
--- a/ext/posix_mq/posix_mq.c
+++ b/ext/posix_mq/posix_mq.c
@@ -95,21 +95,18 @@ static void rb_18_str_set_len(VALUE str, long len)
 #define rb_str_set_len rb_18_str_set_len
 #endif /* !defined(HAVE_RB_STR_SET_LEN) */
 
-/* partial emulation of the 1.9 rb_thread_blocking_region under 1.8 */
-#if defined(HAVE_RB_THREAD_BLOCKING_REGION) && \
-    defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
-/*
- * Ruby 1.9 - 2.1 (we use deprecated rb_thread_blocking_region in 2.0+
- * because we can detect (but not use) rb_thread_blocking_region in 1.9.3
- */
-typedef VALUE(*my_blocking_fn_t)(void*);
+#if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL) && defined(HAVE_RUBY_THREAD_H)
+/* Ruby 2.0+ */
+#  include <ruby/thread.h>
 #  define WITHOUT_GVL(fn,a,ubf,b) \
-	rb_thread_blocking_region((my_blocking_fn_t)(fn),(a),(ubf),(b))
-#elif defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL) /* Ruby 2.2+ */
-#include <ruby/thread.h>
+        rb_thread_call_without_gvl((fn),(a),(ubf),(b))
+#elif defined(HAVE_RB_THREAD_BLOCKING_REGION)
+typedef VALUE (*my_blocking_fn_t)(void*);
 #  define WITHOUT_GVL(fn,a,ubf,b) \
-	rb_thread_call_without_gvl((fn),(a),(ubf),(b))
+	rb_thread_blocking_region((my_blocking_fn_t)(fn),(a),(ubf),(b))
+
 #else /* Ruby 1.8 */
+/* partial emulation of the 1.9 rb_thread_blocking_region under 1.8 */
 #  include <rubysig.h>
 #  define RUBY_UBF_IO ((rb_unblock_function_t *)-1)
 typedef void rb_unblock_function_t(void *);
-- 
1.9.0.rc3.13.gda73b5f



^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2014-02-15 13:33 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-15 13:33 [PATCH 1/2] prepare for rb_thread_blocking_region removal Eric Wong
2014-02-15 13:33 ` [PATCH 2/2] avoid deprecated rb_thread_blocking_region in Ruby 2.0/2.1 Eric Wong

Code repositories for project(s) associated with this public inbox

	https://yhbt.net/ruby_posix_mq.git/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).