Skip to content
Browse files

use rb_wait_for_single_fd() if available

rb_thread_select() is deprecated under Ruby 1.9.x (and currently
broken ([ruby-core:39095)] in trunk/1.9.3 as of 20110824) in
favor of rb_thread_fd_select().

Ruby 1.9.3+ also offers the rb_wait_for_single_fd() API which is
easier-to-use and (transparently) provides a minor performance
improvement under Linux where the ppoll() syscall is available.
Ruby 1.9.3 will fall back to the same logic used in
rb_thread_fd_select() on non-Linux platforms when using
rb_wait_for_single_fd().

Emulation using rb_thread_select() for older platforms is
provided.  This patch is tested on Ruby trunk r33022,
1.9.2-p290, and 1.8.7-p334.

Full disclosure: I co-implemented rb_wait_for_single_fd() for
Ruby 1.9.3 with Motohiro Kosaki.
  • Loading branch information...
1 parent 4ee579e commit e60599b912dfc6c0c0394656b103f537414d93f4 Eric Wong committed with
Showing with 39 additions and 9 deletions.
  1. +2 −9 ext/mysql2/client.c
  2. +1 −0 ext/mysql2/extconf.rb
  3. +36 −0 ext/mysql2/wait_for_single_fd.h
View
11 ext/mysql2/client.c
@@ -4,6 +4,7 @@
#ifndef _WIN32
#include <sys/socket.h>
#endif
+#include "wait_for_single_fd.h"
VALUE cMysql2Client;
extern VALUE mMysql2, cMysql2Error;
@@ -341,9 +342,7 @@ static VALUE do_query(void *args) {
struct timeval tv;
struct timeval* tvp;
long int sec;
- fd_set fdset;
int retval;
- int fd_set_fd;
VALUE read_timeout;
async_args = (struct async_query_args *)args;
@@ -364,14 +363,8 @@ static VALUE do_query(void *args) {
tvp->tv_usec = 0;
}
- fd_set_fd = async_args->fd;
for(;;) {
- // the below code is largely from do_mysql
- // http://github.com/datamapper/do
- FD_ZERO(&fdset);
- FD_SET(fd_set_fd, &fdset);
-
- retval = rb_thread_select(fd_set_fd + 1, &fdset, NULL, NULL, tvp);
+ retval = rb_wait_for_single_fd(async_args->fd, RB_WAITFD_IN, tvp);
if (retval == 0) {
rb_raise(cMysql2Error, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout));
View
1 ext/mysql2/extconf.rb
@@ -7,6 +7,7 @@ def asplode lib
# 1.9-only
have_func('rb_thread_blocking_region')
+have_func('rb_wait_for_single_fd')
# borrowed from mysqlplus
# http://github.com/oldmoe/mysqlplus/blob/master/ext/extconf.rb
View
36 ext/mysql2/wait_for_single_fd.h
@@ -0,0 +1,36 @@
+/*
+ * backwards compatibility for pre-1.9.3 C API
+ *
+ * Ruby 1.9.3 provides this API which allows the use of ppoll() on Linux
+ * to minimize select() and malloc() overhead on high-numbered FDs.
+ */
+#ifdef HAVE_RB_WAIT_FOR_SINGLE_FD
+# include <ruby/io.h>
+#else
+# define RB_WAITFD_IN 0x001
+# define RB_WAITFD_PRI 0x002
+# define RB_WAITFD_OUT 0x004
+
+static int my_wait_for_single_fd(int fd, int events, struct timeval *tvp)
+{
+ fd_set fdset;
+ fd_set *rfds = NULL;
+ fd_set *wfds = NULL;
+ fd_set *efds = NULL;
+
+ FD_ZERO(&fdset);
+ FD_SET(fd, &fdset);
+
+ if (events & RB_WAITFD_IN)
+ rfds = &fdset;
+ if (events & RB_WAITFD_OUT)
+ wfds = &fdset;
+ if (events & RB_WAITFD_PRI)
+ efds = &fdset;
+
+ return rb_thread_select(fd + 1, rfds, wfds, efds, tvp);
+}
+
+#define rb_wait_for_single_fd(fd,events,tvp) \
+ my_wait_for_single_fd((fd),(events),(tvp))
+#endif

0 comments on commit e60599b

Please sign in to comment.
Something went wrong with that request. Please try again.