From ec008731813c94a77adb5a33455a4595a682c3e2 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Mon, 10 May 2010 14:09:21 -0700 Subject: [PATCH] make Mysql2::Client destructor safely non-blocking Since sending a QUIT message to the MySQL server is more of a formality than a hard requirement in a TCP-based protocol, we'll just fire-and-forget the message to avoid any chance of blocking the interpreter during the GC finalizer phase. Since the socket will be closed immediately afterwards, there's no long-term side-effects from making the socket non-blocking. We do this instead of using rb_thread_blocking_region because the GVL is already destroyed by the time the ObjectSpace finalizers are called under 1.9. --- ext/mysql2_ext.c | 23 ++++++++++++++++++----- ext/mysql2_ext.h | 1 + 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/ext/mysql2_ext.c b/ext/mysql2_ext.c index 1df155e..254eebc 100644 --- a/ext/mysql2_ext.c +++ b/ext/mysql2_ext.c @@ -187,10 +187,23 @@ static void rb_mysql_client_free(void * ptr) { if (client->client) { /* - * this may send a "QUIT" message to the server and thus block - * on the socket write, users are encouraged to close this manually - * to avoid this behavior + * we'll send a QUIT message to the server, but that message is more of a + * formality than a hard requirement since the socket is getting shutdown + * anyways, so ensure the socket write does not block our interpreter */ + int fd = client->client->net.fd; + int flags; + + if (fd >= 0) { + /* + * if the socket is dead we have no chance of blocking, + * so ignore any potential fcntl errors since they don't matter + */ + flags = fcntl(fd, F_GETFL); + if (flags > 0 && !(flags & O_NONBLOCK)) + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + } + mysql_close(client->client); } xfree(ptr); @@ -204,8 +217,8 @@ static VALUE nogvl_close(void * ptr) { /* * Immediately disconnect from the server, normally the garbage collector * will disconnect automatically when a connection is no longer needed. - * Explicitly closing this can free up server resources sooner and is - * also 100% safe when faced with signals or running multithreaded + * Explicitly closing this will free up server resources sooner than waiting + * for the garbage collector. */ static VALUE rb_mysql_client_close(VALUE self) { mysql2_client_wrapper *client; diff --git a/ext/mysql2_ext.h b/ext/mysql2_ext.h index b02f0dd..668f2b6 100644 --- a/ext/mysql2_ext.h +++ b/ext/mysql2_ext.h @@ -1,4 +1,5 @@ #include +#include #ifdef HAVE_MYSQL_H #include