Skip to content

Commit e60599b

Browse files
Eric Wongbrianmario
authored andcommitted
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.
1 parent 4ee579e commit e60599b

File tree

3 files changed

+39
-9
lines changed

3 files changed

+39
-9
lines changed

ext/mysql2/client.c

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#ifndef _WIN32
55
#include <sys/socket.h>
66
#endif
7+
#include "wait_for_single_fd.h"
78

89
VALUE cMysql2Client;
910
extern VALUE mMysql2, cMysql2Error;
@@ -341,9 +342,7 @@ static VALUE do_query(void *args) {
341342
struct timeval tv;
342343
struct timeval* tvp;
343344
long int sec;
344-
fd_set fdset;
345345
int retval;
346-
int fd_set_fd;
347346
VALUE read_timeout;
348347

349348
async_args = (struct async_query_args *)args;
@@ -364,14 +363,8 @@ static VALUE do_query(void *args) {
364363
tvp->tv_usec = 0;
365364
}
366365

367-
fd_set_fd = async_args->fd;
368366
for(;;) {
369-
// the below code is largely from do_mysql
370-
// http://github.com/datamapper/do
371-
FD_ZERO(&fdset);
372-
FD_SET(fd_set_fd, &fdset);
373-
374-
retval = rb_thread_select(fd_set_fd + 1, &fdset, NULL, NULL, tvp);
367+
retval = rb_wait_for_single_fd(async_args->fd, RB_WAITFD_IN, tvp);
375368

376369
if (retval == 0) {
377370
rb_raise(cMysql2Error, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout));

ext/mysql2/extconf.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ def asplode lib
77

88
# 1.9-only
99
have_func('rb_thread_blocking_region')
10+
have_func('rb_wait_for_single_fd')
1011

1112
# borrowed from mysqlplus
1213
# http://github.com/oldmoe/mysqlplus/blob/master/ext/extconf.rb

ext/mysql2/wait_for_single_fd.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* backwards compatibility for pre-1.9.3 C API
3+
*
4+
* Ruby 1.9.3 provides this API which allows the use of ppoll() on Linux
5+
* to minimize select() and malloc() overhead on high-numbered FDs.
6+
*/
7+
#ifdef HAVE_RB_WAIT_FOR_SINGLE_FD
8+
# include <ruby/io.h>
9+
#else
10+
# define RB_WAITFD_IN 0x001
11+
# define RB_WAITFD_PRI 0x002
12+
# define RB_WAITFD_OUT 0x004
13+
14+
static int my_wait_for_single_fd(int fd, int events, struct timeval *tvp)
15+
{
16+
fd_set fdset;
17+
fd_set *rfds = NULL;
18+
fd_set *wfds = NULL;
19+
fd_set *efds = NULL;
20+
21+
FD_ZERO(&fdset);
22+
FD_SET(fd, &fdset);
23+
24+
if (events & RB_WAITFD_IN)
25+
rfds = &fdset;
26+
if (events & RB_WAITFD_OUT)
27+
wfds = &fdset;
28+
if (events & RB_WAITFD_PRI)
29+
efds = &fdset;
30+
31+
return rb_thread_select(fd + 1, rfds, wfds, efds, tvp);
32+
}
33+
34+
#define rb_wait_for_single_fd(fd,events,tvp) \
35+
my_wait_for_single_fd((fd),(events),(tvp))
36+
#endif

0 commit comments

Comments
 (0)