class NIO::Selector
Selectors monitor IO objects for events of interest
Public Class Methods
backends()
click to toggle source
Return an array of symbols for supported backends
static VALUE NIO_Selector_supported_backends(VALUE klass)
{
unsigned int backends = ev_supported_backends();
VALUE result = rb_ary_new();
if (backends & EVBACKEND_EPOLL) {
rb_ary_push(result, ID2SYM(rb_intern("epoll")));
}
if (backends & EVBACKEND_POLL) {
rb_ary_push(result, ID2SYM(rb_intern("poll")));
}
if (backends & EVBACKEND_KQUEUE) {
rb_ary_push(result, ID2SYM(rb_intern("kqueue")));
}
if (backends & EVBACKEND_SELECT) {
rb_ary_push(result, ID2SYM(rb_intern("select")));
}
if (backends & EVBACKEND_PORT) {
rb_ary_push(result, ID2SYM(rb_intern("port")));
}
if (backends & EVBACKEND_LINUXAIO) {
rb_ary_push(result, ID2SYM(rb_intern("linuxaio")));
}
if (backends & EVBACKEND_IOURING) {
rb_ary_push(result, ID2SYM(rb_intern("io_uring")));
}
return result;
}
new(p1 = v1)
click to toggle source
Create a new selector. This is more or less the pure Ruby version translated into an MRI cext
static VALUE NIO_Selector_initialize(int argc, VALUE *argv, VALUE self)
{
ID backend_id;
VALUE backend;
VALUE lock;
struct NIO_Selector *selector;
unsigned int flags = 0;
Data_Get_Struct(self, struct NIO_Selector, selector);
rb_scan_args(argc, argv, "01", &backend);
if (backend != Qnil) {
if (!rb_ary_includes(NIO_Selector_supported_backends(CLASS_OF(self)), backend)) {
rb_raise(rb_eArgError, "unsupported backend: %s", RSTRING_PTR(rb_funcall(backend, rb_intern("inspect"), 0)));
}
backend_id = SYM2ID(backend);
if (backend_id == rb_intern("epoll")) {
flags = EVBACKEND_EPOLL;
} else if (backend_id == rb_intern("poll")) {
flags = EVBACKEND_POLL;
} else if (backend_id == rb_intern("kqueue")) {
flags = EVBACKEND_KQUEUE;
} else if (backend_id == rb_intern("select")) {
flags = EVBACKEND_SELECT;
} else if (backend_id == rb_intern("port")) {
flags = EVBACKEND_PORT;
} else if (backend_id == rb_intern("linuxaio")) {
flags = EVBACKEND_LINUXAIO;
} else if (backend_id == rb_intern("io_uring")) {
flags = EVBACKEND_IOURING;
} else {
rb_raise(rb_eArgError, "unsupported backend: %s", RSTRING_PTR(rb_funcall(backend, rb_intern("inspect"), 0)));
}
}
/* Ensure the selector loop has not yet been initialized */
assert(!selector->ev_loop);
selector->ev_loop = ev_loop_new(flags);
if (!selector->ev_loop) {
rb_raise(rb_eIOError, "error initializing event loop");
}
ev_io_start(selector->ev_loop, &selector->wakeup);
rb_ivar_set(self, rb_intern("selectables"), rb_hash_new());
rb_ivar_set(self, rb_intern("lock_holder"), Qnil);
lock = rb_class_new_instance(0, 0, rb_const_get(rb_cObject, rb_intern("Mutex")));
rb_ivar_set(self, rb_intern("lock"), lock);
rb_ivar_set(self, rb_intern("lock_holder"), Qnil);
return Qnil;
}
new(backend = :ruby)
click to toggle source
Create a new NIO::Selector
# File lib/nio/selector.rb, line 16 def initialize(backend = :ruby) raise ArgumentError, "unsupported backend: #{backend}" unless [:ruby, nil].include?(backend) @selectables = {} @lock = Mutex.new # Other threads can wake up a selector @wakeup, @waker = IO.pipe @closed = false end
Public Instance Methods
backend()
click to toggle source
static VALUE NIO_Selector_backend(VALUE self)
{
struct NIO_Selector *selector;
Data_Get_Struct(self, struct NIO_Selector, selector);
if (selector->closed) {
rb_raise(rb_eIOError, "selector is closed");
}
switch (ev_backend(selector->ev_loop)) {
case EVBACKEND_EPOLL:
return ID2SYM(rb_intern("epoll"));
case EVBACKEND_POLL:
return ID2SYM(rb_intern("poll"));
case EVBACKEND_KQUEUE:
return ID2SYM(rb_intern("kqueue"));
case EVBACKEND_SELECT:
return ID2SYM(rb_intern("select"));
case EVBACKEND_PORT:
return ID2SYM(rb_intern("port"));
case EVBACKEND_LINUXAIO:
return ID2SYM(rb_intern("linuxaio"));
case EVBACKEND_IOURING:
return ID2SYM(rb_intern("io_uring"));
}
return ID2SYM(rb_intern("unknown"));
}
close()
click to toggle source
Close the selector and free system resources
static VALUE NIO_Selector_close(VALUE self)
{
return NIO_Selector_synchronize(self, NIO_Selector_close_synchronized, self);
}
closed?()
click to toggle source
Is the selector closed?
static VALUE NIO_Selector_closed(VALUE self)
{
return NIO_Selector_synchronize(self, NIO_Selector_closed_synchronized, self);
}
deregister(p1)
click to toggle source
Deregister an IO object from the selector
static VALUE NIO_Selector_deregister(VALUE self, VALUE io)
{
VALUE args[2] = {self, io};
return NIO_Selector_synchronize(self, NIO_Selector_deregister_synchronized, (VALUE)args);
}
empty?()
click to toggle source
True if there are monitors on the loop
static VALUE NIO_Selector_is_empty(VALUE self)
{
VALUE selectables = rb_ivar_get(self, rb_intern("selectables"));
return rb_funcall(selectables, rb_intern("empty?"), 0) == Qtrue ? Qtrue : Qfalse;
}
register(p1, p2)
click to toggle source
Register an IO object with the selector for the given interests
static VALUE NIO_Selector_register(VALUE self, VALUE io, VALUE interests)
{
VALUE args[3] = {self, io, interests};
return NIO_Selector_synchronize(self, NIO_Selector_register_synchronized, (VALUE)args);
}
registered?(p1)
click to toggle source
Is the given IO object registered with the selector
static VALUE NIO_Selector_is_registered(VALUE self, VALUE io)
{
VALUE selectables = rb_ivar_get(self, rb_intern("selectables"));
/* Perhaps this should be holding the mutex? */
return rb_funcall(selectables, rb_intern("has_key?"), 1, io);
}
select(p1 = v1)
click to toggle source
Select from all registered IO objects
static VALUE NIO_Selector_select(int argc, VALUE *argv, VALUE self)
{
VALUE timeout;
rb_scan_args(argc, argv, "01", &timeout);
if (timeout != Qnil && NUM2DBL(timeout) < 0) {
rb_raise(rb_eArgError, "time interval must be positive");
}
VALUE args[2] = {self, timeout};
return NIO_Selector_synchronize(self, NIO_Selector_select_synchronized, (VALUE)args);
}
wakeup()
click to toggle source
Wake the selector up from another thread
static VALUE NIO_Selector_wakeup(VALUE self)
{
struct NIO_Selector *selector;
Data_Get_Struct(self, struct NIO_Selector, selector);
if (selector->closed) {
rb_raise(rb_eIOError, "selector is closed");
}
selector->wakeup_fired = 1;
write(selector->wakeup_writer, "\0", 1);
return Qnil;
}