Skip to content

Commit 4244ae2

Browse files
Eric Wongbrianmario
authored andcommitted
reacquire GVL before retrying on EINTR on connect
If signals are received, we must reacquire the GVL to let (Ruby-level) signal handlers run. Otherwise, it may be impossible to effectively cancel/interrupt a slow connection negotiation. Fortunately, connecting to MySQL servers is rare and rarely interrupted (or even interruptible) by signal handlers, so maybe nobody noticed this bug.
1 parent 50174ff commit 4244ae2

File tree

1 file changed

+13
-9
lines changed

1 file changed

+13
-9
lines changed

ext/mysql2/client.c

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,10 @@ static VALUE nogvl_connect(void *ptr) {
114114
struct nogvl_connect_args *args = ptr;
115115
MYSQL *client;
116116

117-
do {
118-
client = mysql_real_connect(args->mysql, args->host,
119-
args->user, args->passwd,
120-
args->db, args->port, args->unix_socket,
121-
args->client_flag);
122-
} while (! client && errno == EINTR && (errno = 0) == 0);
117+
client = mysql_real_connect(args->mysql, args->host,
118+
args->user, args->passwd,
119+
args->db, args->port, args->unix_socket,
120+
args->client_flag);
123121

124122
return client ? Qtrue : Qfalse;
125123
}
@@ -202,6 +200,7 @@ static VALUE rb_mysql_client_escape(RB_MYSQL_UNUSED VALUE klass, VALUE str) {
202200

203201
static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE port, VALUE database, VALUE socket, VALUE flags) {
204202
struct nogvl_connect_args args;
203+
VALUE rv;
205204
GET_CLIENT(self);
206205

207206
args.host = NIL_P(host) ? "localhost" : StringValuePtr(host);
@@ -213,9 +212,14 @@ static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE po
213212
args.mysql = wrapper->client;
214213
args.client_flag = NUM2ULONG(flags);
215214

216-
if (rb_thread_blocking_region(nogvl_connect, &args, RUBY_UBF_IO, 0) == Qfalse) {
217-
// unable to connect
218-
return rb_raise_mysql2_error(wrapper);
215+
rv = rb_thread_blocking_region(nogvl_connect, &args, RUBY_UBF_IO, 0);
216+
if (rv == Qfalse) {
217+
while (rv == Qfalse && errno == EINTR) {
218+
errno = 0;
219+
rv = rb_thread_blocking_region(nogvl_connect, &args, RUBY_UBF_IO, 0);
220+
}
221+
if (rv == Qfalse)
222+
return rb_raise_mysql2_error(wrapper);
219223
}
220224

221225
return self;

0 commit comments

Comments
 (0)