Class: NIO::Selector
Relationships & Source Files | |
Inherits: | Object |
Defined in: | lib/nio/selector.rb, ext/nio4r/selector.c |
Overview
Selectors monitor IO objects for events of interest
Class Method Summary
-
.backends
Return supported backends as symbols.
-
.new(*args)
constructor
Create a new selector.
Instance Attribute Summary
-
#closed? ⇒ Boolean
readonly
Is this selector closed?
-
#empty? ⇒ Boolean
readonly
True if there are monitors on the loop.
Instance Method Summary
-
#backend
Return a symbol representing the backend I/O multiplexing mechanism used.
-
#close
Close the selector and free system resources.
-
#deregister(io)
Deregister the given IO object from the selector.
-
#initialize(backend = :ruby) ⇒ Selector
constructor
Create a new
Selector
-
#register(io, interest)
Register interest in an IO object with the selector for the given types of events.
-
#registered?(io) ⇒ Boolean
Is the given IO object registered with the selector?
-
#select(timeout = nil)
Select from all registered IO objects.
-
#wakeup
Wake up a thread that's in the middle of selecting on this selector, if any such thread exists.
Constructor Details
.new(*args)
Create a new selector. This is more or less the pure Ruby version translated into an MRI cext
# File 'ext/nio4r/selector.c', line 224
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; TypedData_Get_Struct(self, struct NIO_Selector, &NIO_Selector_type, 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; }
#initialize(backend = :ruby) ⇒ Selector
Create a new Selector
Class Method Details
.backends
Return supported backends as symbols
See #backend method definition for all possible backends
# File 'ext/nio4r/selector.c', line 186
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; }
Instance Attribute Details
#closed? ⇒ Boolean
(readonly)
Is this selector closed?
# File 'ext/nio4r/selector.c', line 548
static VALUE NIO_Selector_closed(VALUE self) { return NIO_Selector_synchronize(self, NIO_Selector_closed_synchronized, self); }
#empty? ⇒ Boolean
(readonly)
True if there are monitors on the loop
# File 'ext/nio4r/selector.c', line 563
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; }
Instance Method Details
#backend
Return a symbol representing the backend I/O multiplexing mechanism used. Supported backends are:
:ruby
- pure Ruby (i.eIO.select
):java
- Java NIO on JRuby:epoll
- libev w\ Linux epoll:poll
- libev w\ POSIX poll:kqueue
- libev w\ BSD kqueue:select
- libev w\ SysV select:port
- libev w\ I/O completion ports:linuxaio
- libev w\ Linux AIO io_submit (experimental):io_uring
- libev w\ Linux io_uring (experimental):unknown
- libev w\ unknown backend
# File 'ext/nio4r/selector.c', line 283
static VALUE NIO_Selector_backend(VALUE self) { struct NIO_Selector *selector; TypedData_Get_Struct(self, struct NIO_Selector, &NIO_Selector_type, 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
Close the selector and free system resources
# File 'ext/nio4r/selector.c', line 531
static VALUE NIO_Selector_close(VALUE self) { return NIO_Selector_synchronize(self, NIO_Selector_close_synchronized, self); }
#deregister(io)
Deregister the given IO object from the selector
# File 'ext/nio4r/selector.c', line 388
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); }
#register(io, interest)
Register interest in an IO object with the selector for the given types of events. Valid event types for interest are:
:r
- is the IO readable?:w
- is the IO writeable?:rw
- is the IO either readable or writeable?
# File 'ext/nio4r/selector.c', line 347
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?(io) ⇒ Boolean
Is the given IO object registered with the selector?
# File 'ext/nio4r/selector.c', line 414
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(timeout = nil)
Select from all registered IO objects
# File 'ext/nio4r/selector.c', line 423
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
Wake up a thread that's in the middle of selecting on this selector, if any such thread exists.
Invoking this method more than once between two successive select calls has the same effect as invoking it just once. In other words, it provides level-triggered behavior.
# File 'ext/nio4r/selector.c', line 515
static VALUE NIO_Selector_wakeup(VALUE self) { struct NIO_Selector *selector; TypedData_Get_Struct(self, struct NIO_Selector, &NIO_Selector_type, selector); if (selector->closed) { rb_raise(rb_eIOError, "selector is closed"); } selector->wakeup_fired = 1; write(selector->wakeup_writer, "\0", 1); return Qnil; }