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 */