class Libev::Scheduler

Public Class Methods

new() click to toggle source
static VALUE Scheduler_initialize(VALUE self) {
  Scheduler_t *scheduler;
  VALUE thread = rb_thread_current();
  int is_main_thread = (thread == rb_thread_main());

  GetScheduler(self, scheduler);
  scheduler->ev_loop = is_main_thread ? EV_DEFAULT : ev_loop_new(EVFLAG_NOSIGMASK);

  ev_async_init(&scheduler->break_async, break_async_callback);
  ev_async_start(scheduler->ev_loop, &scheduler->break_async);
  ev_unref(scheduler->ev_loop); // don't count the break_async watcher

  scheduler->pending_count = 0;
  scheduler->currently_polling = 0;
  scheduler->ready = rb_ary_new();

  return Qnil;
}

Public Instance Methods

block(*args) click to toggle source
VALUE Scheduler_block(int argc, VALUE *argv, VALUE self) {
  VALUE timeout = (argc == 2) ? argv[1] : Qnil;

  if (timeout != Qnil)
    Scheduler_sleep(self, timeout);
  else
    Scheduler_pause(self);
  
  return Qtrue;
}
close() click to toggle source
VALUE Scheduler_close(VALUE self) {
  Scheduler_t *scheduler;
  GetScheduler(self, scheduler);

  Scheduler_run(self);

  ev_async_stop(scheduler->ev_loop, &scheduler->break_async);
  if (!ev_is_default_loop(scheduler->ev_loop)) ev_loop_destroy(scheduler->ev_loop);
  return self;
}
fiber(&block) click to toggle source
# File lib/libev_scheduler.rb, line 5
def fiber(&block)
  fiber = Fiber.new(blocking: false, &block)
  unblock(nil, fiber)
  # fiber.resume
  return fiber
end
io_wait(p1, p2, p3) click to toggle source
VALUE Scheduler_io_wait(VALUE self, VALUE io, VALUE events, VALUE timeout) {
  Scheduler_t *scheduler;
  struct libev_io io_watcher;
  struct libev_timer timeout_watcher;
  GetScheduler(self, scheduler);

  rb_io_t *fptr;
  VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
  if (underlying_io != Qnil) io = underlying_io;
  GetOpenFile(io, fptr);

  io_watcher.scheduler = scheduler;
  io_watcher.fiber = rb_fiber_current();
  ev_io_init(&io_watcher.io, Scheduler_io_callback, fptr->fd, io_event_mask(events));

  int use_timeout = timeout != Qnil;
  if (use_timeout) {
    timeout_watcher.scheduler = scheduler;
    timeout_watcher.fiber = rb_fiber_current();
    ev_timer_init(&timeout_watcher.timer, Scheduler_timer_callback, NUM2DBL(timeout), 0.);
    ev_timer_start(scheduler->ev_loop, &timeout_watcher.timer);
  }

  ev_io_start(scheduler->ev_loop, &io_watcher.io);
  VALUE nil = Qnil;
  scheduler->pending_count++;
  rb_fiber_yield(1, &nil);
  scheduler->pending_count--;
  ev_io_stop(scheduler->ev_loop, &io_watcher.io);
  if (use_timeout)
    ev_timer_stop(scheduler->ev_loop, &timeout_watcher.timer);
  
  return self;
}
kernel_sleep(duration = nil) click to toggle source
# File lib/libev_scheduler.rb, line 12
def kernel_sleep(duration = nil)
  block(:sleep, duration)
end
pending_count() click to toggle source
VALUE Scheduler_pending_count(VALUE self) {
  Scheduler_t *scheduler;
  GetScheduler(self, scheduler);

  return INT2NUM(scheduler->pending_count);
}
process_wait(p1, p2) click to toggle source
VALUE Scheduler_process_wait(VALUE self, VALUE pid, VALUE flags) {
  Scheduler_t *scheduler;
  struct libev_child watcher;
  VALUE result = Qnil;
  GetScheduler(self, scheduler);

  watcher.scheduler = scheduler;
  watcher.fiber = rb_fiber_current();
  watcher.status = Qnil;
  ev_child_init(&watcher.child, Scheduler_child_callback, NUM2INT(pid), 0);
  ev_child_start(scheduler->ev_loop, &watcher.child);
  VALUE nil = Qnil;
  scheduler->pending_count++;
  rb_fiber_yield(1, &nil);
  scheduler->pending_count--;
  ev_child_stop(scheduler->ev_loop, &watcher.child);
  RB_GC_GUARD(watcher.status);
  RB_GC_GUARD(result);
  return result;
}
run() click to toggle source
VALUE Scheduler_run(VALUE self) {
  Scheduler_t *scheduler;
  GetScheduler(self, scheduler);

  while (scheduler->pending_count > 0 || RARRAY_LEN(scheduler->ready) > 0) {
    Scheduler_poll(self);
  }

  return self;
}
unblock(p1, p2) click to toggle source
VALUE Scheduler_unblock(VALUE self, VALUE blocker, VALUE fiber) {
  Scheduler_t *scheduler;
  GetScheduler(self, scheduler);

  rb_ary_push(scheduler->ready, fiber);

  if (scheduler->currently_polling)
    ev_async_send(scheduler->ev_loop, &scheduler->break_async);

  return self;
}