class SleepyPenguin::Kqueue
The high-level Kqueue
interface. This provides fork-safety; as underlying kqueue descriptors are closed by the OS upon fork. This also provides memory protection from bugs due to not storing an external reference to an object, but still requires the user to store their own object references. Events registered to a Kqueue
object cannot be shared across fork due to the underlying implementation of kqueue in *BSDs.
Public Class Methods
Initialize a new Kqueue
object, this allocates an underlying Kqueue::IO
object and may fail if the system is out of file descriptors or kernel memory
# File lib/sleepy_penguin/kqueue.rb, line 16 def initialize @io = SleepyPenguin::Kqueue::IO.new @mtx = Mutex.new @pid = $$ @copies = { @io => self } end
Public Instance Methods
Closes an existing Kqueue
object and returns memory back to the kernel. Raises IOError if object is already closed.
# File lib/sleepy_penguin/kqueue.rb, line 106 def close @mtx.synchronize do @copies.delete(@io) @io.close end end
Returns whether or not an Kqueue
object is closed.
# File lib/sleepy_penguin/kqueue.rb, line 117 def closed? @mtx.synchronize do @io.closed? end end
A high-level wrapper around Kqueue::IO#kevent
Users are responsible for ensuring udata
objects remain visible to the Ruby GC, otherwise ObjectSpace._id2ref may return invalid objects. Unlike the low-level Kqueue::IO#kevent
, the block given yields only a single Kevent struct, not a 6-element array.
As of sleepy_penguin 3.5.0+, it is possible to nest kevent
calls within the same thread.
# File lib/sleepy_penguin/kqueue.rb, line 58 def kevent(changelist = nil, *args) @mtx.synchronize { __kq_check } if changelist changelist = [ changelist ] if Struct === changelist # store the object_id instead of the raw VALUE itself in kqueue and # use _id2ref to safely recover the object without the possibility of # invalid memory acccess. # # We may still raise and drop events due to user error changelist = changelist.map do |item| item = item.dup item[5] = item[5].object_id item end end if block_given? @io.kevent(changelist, *args) do |ident,filter,flags, fflags,data,udata| # This may raise and cause events to be lost, # that's the users' fault/problem udata = ObjectSpace._id2ref(udata) yield SleepyPenguin::Kevent.new(ident, filter, flags, fflags, data, udata) end else @io.kevent(changelist, *args) end end
Kqueue
objects may be watched by IO.select and similar methods
# File lib/sleepy_penguin/kqueue.rb, line 24 def to_io @mtx.synchronize do __kq_check @io end end