Class: SleepyPenguin::Kqueue::IO
- Inherits:
-
IO
- Object
- IO
- SleepyPenguin::Kqueue::IO
- Defined in:
- ext/sleepy_penguin/kqueue.c,
ext/sleepy_penguin/kqueue.c
Overview
Kqueue::IO is a low-level class. It does not provide fork nor GC-safety, so Ruby IO objects added via kevent must be retained by the application until IO#close is called.
Warning: this class is easy to misuse, be careful as failure to preserve references objects passed as Kevent#udata may lead to crashes in Ruby. The high-level Kqueue class prevents these crashes (but may still return invalid objects).
Class Method Summary collapse
-
.new ⇒ Object
SleepyPenguin::Kqueue::IO.new -> Kqueue::IO object.
Instance Method Summary collapse
-
#kevent(*args) ⇒ Object
kq_io.kevent([changelist[, nevents[, timeout]]]) { |ident,filter,flags,fflags,data,udata| … }.
Class Method Details
.new ⇒ Object
SleepyPenguin::Kqueue::IO.new -> Kqueue::IO object
Creates a new Kqueue::IO object. This is a wrapper around the kqueue(2) system call which creates a Ruby IO object around the kqueue descriptor.
kqueue descriptors are automatically invalidated by the OS across fork, so care must be taken when forking. Setting IO#autoclose=false is recommended for applications which fork after kqueue creation.
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'ext/sleepy_penguin/kqueue.c', line 112 static VALUE s_new(VALUE klass) { VALUE rv; int fd = kqueue(); int flags; if (fd < 0) { /* * ENOMEM/EMFILE/ENFILE are the only documented errors * for kqueue(), hope GC can give us some space to retry: */ rb_gc(); fd = kqueue(); if (fd < 0) rb_sys_fail("kqueue"); } flags = fcntl(fd, F_GETFD); if (flags != -1) fcntl(fd, F_SETFD, flags | FD_CLOEXEC); rv = INT2FIX(fd); return rb_call_super(1, &rv); } |
Instance Method Details
#kevent(*args) ⇒ Object
kq_io.kevent([changelist[, nevents[, timeout]]]) { |ident,filter,flags,fflags,data,udata| … }
This is a wrapper around the kevent(2) system call to change and/or retrieve events from the underlying kqueue descriptor.
changelist may be nil, a single Kevent struct or an array of Kevent structs. If changelist is nil, no changes will be made to the underlying kqueue object.
nevents may be non-negative integer or nil. If nevents is zero or nil, no events are retrieved. If nevents is positive, a block must be passed to kevent for each event.
timeout is the numeric timeout in seconds to wait for nevents. If nil and nevents is positive, kevent will sleep forever. timeout may be in a floating point number if subsecond resolution is required. If nevents is nil or zero and timeout is not specified, timeout is implied to be zero.
If event retrieval is desired, a block taking 6-elements (one for each field of the kevent struct) must be passed.
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 |
# File 'ext/sleepy_penguin/kqueue.c', line 370 static VALUE sp_kevent(int argc, VALUE *argv, VALUE self) { struct timespec ts, *t; VALUE changelist, events, timeout; struct kq_per_thread *kpt; int nchanges, nevents; rb_scan_args(argc, argv, "03", &changelist, &events, &timeout); switch (TYPE(changelist)) { case T_NIL: nchanges = 0; break; case T_STRUCT: nchanges = 1; break; case T_ARRAY: nchanges = RARRAY_LENINT(changelist); break; default: rb_raise(rb_eTypeError, "unhandled type for kevent changelist"); } if (rb_block_given_p()) { if (NIL_P(events)) rb_raise(rb_eArgError, "block given but nevents not specified"); nevents = NUM2INT(events); if (nevents < 0) rb_raise(rb_eArgError, "nevents must be non-negative"); } else { if (!NIL_P(events)) rb_raise(rb_eArgError, "nevents specified but block not given"); nevents = 0; } t = NIL_P(timeout) ? NULL : value2timespec(&ts, timeout); kpt = kpt_get(nchanges, nevents); kpt->ts = t; kpt->changelist = changelist; kpt->io = self; kpt->fd = rb_sp_fileno(kpt->io); return rb_ensure(do_kevent, (VALUE)kpt, rb_sp_puttlsbuf, (VALUE)kpt); } |