ext/asyncengine/ae_next_tick.c in asyncengine-0.0.1.testing1 vs ext/asyncengine/ae_next_tick.c in asyncengine-0.0.2.alpha1

- old
+ new

@@ -1,51 +1,111 @@ #include "asyncengine_ruby.h" #include "ae_handle_common.h" #include "ae_next_tick.h" -// C variable indicating whether there are pending next_ticks. -static int pending_next_ticks; +static ID att_next_tick_procs; -static ID id_method_execute_next_ticks; +static uv_idle_t* ae_next_tick_uv_idle; -void init_ae_next_tick() +/** Pre-declaration of static functions. */ + +static void _uv_idle_callback(uv_idle_t* handle, int status); +static VALUE _ae_idle_callback(void); + + +void init_ae_next_tick(void) { - pending_next_ticks = 0; + AE_TRACE(); - rb_define_module_function(mAsyncEngine, "_c_next_tick", AsyncEngine_c_next_tick, 0); + rb_define_module_function(mAsyncEngine, "next_tick", AsyncEngine_next_tick, -1); - id_method_execute_next_ticks = rb_intern("execute_next_ticks"); + att_next_tick_procs = rb_intern("@_next_tick_procs"); + + ae_next_tick_uv_idle = NULL; } +void load_ae_next_tick_uv_idle(void) +{ + AE_TRACE(); + int r; + + AE_ASSERT(ae_next_tick_uv_idle == NULL); + + ae_next_tick_uv_idle = ALLOC(uv_idle_t); + r = uv_idle_init(AE_uv_loop, ae_next_tick_uv_idle); + AE_ASSERT(r == 0); +} + + +void unload_ae_next_tick_uv_idle(void) +{ + AE_TRACE(); + + AE_ASSERT(ae_next_tick_uv_idle != NULL); + + AE_CLOSE_UV_HANDLE(ae_next_tick_uv_idle); + ae_next_tick_uv_idle = NULL; +} + + static -void execute_next_tick_with_gvl() +VALUE AsyncEngine_next_tick(int argc, VALUE *argv, VALUE self) { AE_TRACE(); - rb_funcall(mAsyncEngine, id_method_execute_next_ticks, 0, 0); + VALUE proc; + int r; + + AE_ASSERT(ae_next_tick_uv_idle != NULL); + + AE_CHECK_STATUS(); + AE_RB_CHECK_NUM_ARGS(0,1); + AE_RB_ENSURE_BLOCK_OR_PROC(1, proc); + + rb_ary_push(rb_ivar_get(mAsyncEngine, att_next_tick_procs), proc); + if (! uv_is_active((uv_handle_t *)ae_next_tick_uv_idle)) { + r = uv_idle_start(ae_next_tick_uv_idle, _uv_idle_callback); + AE_ASSERT(r == 0); + } + + return Qtrue; } static -void next_tick_callback(uv_idle_t* handle, int status) +void _uv_idle_callback(uv_idle_t* handle, int status) { AE_TRACE(); + uv_idle_stop(handle); - uv_close((uv_handle_t *)handle, ae_handle_close_callback_0); - pending_next_ticks = 0; - rb_thread_call_with_gvl(execute_next_tick_with_gvl, NULL); + ae_take_gvl_and_run_with_error_handler(_ae_idle_callback); } -VALUE AsyncEngine_c_next_tick(VALUE self) +static +VALUE _ae_idle_callback(void) { AE_TRACE(); - if (pending_next_ticks == 0) { - uv_idle_t* _uv_handle = ALLOC(uv_idle_t); - uv_idle_init(uv_default_loop(), _uv_handle); - pending_next_ticks = 1; - uv_idle_start(_uv_handle, next_tick_callback); + VALUE procs; + long i; + + AE_ASSERT(AE_status == AE_RUNNING); + + // procs = @_next_tick_procs + procs = rb_ivar_get(mAsyncEngine, att_next_tick_procs); + // @_next_tick_procs = [] + rb_ivar_set(mAsyncEngine, att_next_tick_procs, rb_ary_new()); + + // Iterate procs Array and call each proc. + for(i=0 ; i<RARRAY_LEN(procs) ; i++) { + // It could occur that one of these procs is a release_loop() method, so + // stop iterating. + if (AE_status != AE_RUNNING) + break; + ae_run_with_error_handler(ae_proc_call_0, rb_ary_entry(procs, i)); } - return Qtrue; -} \ No newline at end of file + procs = Qnil; + + return Qnil; +}