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

new() click to toggle source

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

close → nil click to toggle source

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
closed? → true or false click to toggle source

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
kevent(changelist = nil, *args) { |kevent| ... } click to toggle source

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
to_io() click to toggle source

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