diff –git a/ext/libev/ev.c b/ext/libev/ev.c index e5bd5ab..10f6ff2 100644 — a/ext/libev/ev.c +++ b/ext/libev/ev.c @@ -37,6 +37,10 @@

either the BSD or the GPL.

+ ########## COOLIO PATCHERY HO! ##########

+#include “ruby.h” + ######################################## */ +

/* this big block deduces configuration from config.h */
#ifndef EV_STANDALONE
# ifdef EV_CONFIG_H

@@ -3237,9 +3241,27 @@ time_update (EV_P_ ev_tstamp max_block)

    }
}

+/* ########## COOLIO PATCHERY HO! ########## */ +#if defined(HAVE_RB_THREAD_BLOCKING_REGION) +static +VALUE ev_backend_poll(void **args) +{ + struct ev_loop *loop = (struct ev_loop *)args; + ev_tstamp waittime = *(ev_tstamp *)args; + backend_poll (EV_A_ waittime); +} +#endif +/* ######################################## */ +

int
ev_run (EV_P_ int flags)
{

+/* ########## COOLIO PATCHERY HO! ########## */ +#if defined(HAVE_RB_THREAD_BLOCKING_REGION) + void *poll_args; +#endif +/* ######################################## */ +

#if EV_FEATURE_API
  ++loop_depth;
#endif

@@ -3357,7 +3379,53 @@ ev_run (EV_P_ int flags)

        ++loop_count;
#endif
        assert ((loop_done = EVBREAK_RECURSE, 1)); /* assert for side effect */

+ +/* +########################## COOLIO PATCHERY HO! ########################## + +The original patch file is made by Tony Arcieri. +github.com/celluloid/nio4r/blob/680143345726c5a64bb22376ca8fc3c6857019ae/ext/libev/ruby_gil.patch. + +According to the grandwizards of Ruby, locking and unlocking of the global +interpreter lock are apparently too powerful a concept for a mere mortal to +wield (although redefining what + and - do to numbers is totally cool). +And so it came to pass that the only acceptable way to release the global +interpreter lock is through a convoluted callback system that thakes a +function pointer. While the grandwizard of libev foresaw this sort of scenario, +he too attempted to place an API with callbacks on it, one that runs before +the system call, and one that runs immediately after. + +And so it came to pass that trying to wrap everything up in callbacks created +two incompatible APIs, Ruby's which releases the global interpreter lock and +reacquires it when the callback returns, and libev's, which wants two +callbacks, one which runs before the polling operation starts, and one which +runs after it finishes. + +These two systems are incompatible as they both want to use callbacks to +solve the same problem, however libev wants to use before/after callbacks, +and Ruby wants to use an “around” callback. This presents a significant +problem as these two patterns of callbacks are diametrical opposites of each +other and thus cannot be composed. + +And thus we are left with no choice but to patch the internals of libev in +order to release a mutex at just the precise moment. + +Let this be a lesson to the all: CALLBACKS FUCKING BLOW + +####################################################################### +*/ + +#if defined(HAVE_RB_THREAD_BLOCKING_REGION) + poll_args = (void *)loop; + poll_args = (void *)&waittime; + rb_thread_blocking_region(ev_backend_poll, (void *)&poll_args, RUBY_UBF_IO, 0); +#else

backend_poll (EV_A_ waittime);

+#endif +/* +############################# END PATCHERY ############################ +*/ +

assert ((loop_done = EVBREAK_CANCEL, 1)); /* assert for side effect */

pipe_write_wanted = 0; /* just an optimisation, no fence needed */