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 31 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; }