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.
This commit is contained in:
Eric Wong 2010-05-10 14:09:21 -07:00
parent 46021b9351
commit ec00873181
2 changed files with 19 additions and 5 deletions

View File

@ -187,10 +187,23 @@ static void rb_mysql_client_free(void * ptr) {
if (client->client) { if (client->client) {
/* /*
* this may send a "QUIT" message to the server and thus block * we'll send a QUIT message to the server, but that message is more of a
* on the socket write, users are encouraged to close this manually * formality than a hard requirement since the socket is getting shutdown
* to avoid this behavior * 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); mysql_close(client->client);
} }
xfree(ptr); xfree(ptr);
@ -204,8 +217,8 @@ static VALUE nogvl_close(void * ptr) {
/* /*
* Immediately disconnect from the server, normally the garbage collector * Immediately disconnect from the server, normally the garbage collector
* will disconnect automatically when a connection is no longer needed. * will disconnect automatically when a connection is no longer needed.
* Explicitly closing this can free up server resources sooner and is * Explicitly closing this will free up server resources sooner than waiting
* also 100% safe when faced with signals or running multithreaded * for the garbage collector.
*/ */
static VALUE rb_mysql_client_close(VALUE self) { static VALUE rb_mysql_client_close(VALUE self) {
mysql2_client_wrapper *client; mysql2_client_wrapper *client;

View File

@ -1,4 +1,5 @@
#include <ruby.h> #include <ruby.h>
#include <fcntl.h>
#ifdef HAVE_MYSQL_H #ifdef HAVE_MYSQL_H
#include <mysql.h> #include <mysql.h>