Class Kernel::Epoll

  1. lib/ktools/epoll.rb
Parent: Object

Methods

public class

  1. new

public instance

  1. add
  2. add_socket
  3. close
  4. delete
  5. poll

Constants

EP_FLAGS = { :read => EPOLLIN, :write => EPOLLOUT, :hangup => EPOLLHUP, :priority => EPOLLPRI, :edge => EPOLLET, :oneshot => EPOLLONESHOT, :error => EPOLLERR }

Public class methods

new (size=1024)

Creates a new epoll event queue. Takes an optional size parameter (default 1024) that is a hint to the kernel about how many descriptors it will be handling. Read man epoll_create for details on this. Raises an error if the operation fails.

[show source]
# File lib/ktools/epoll.rb, line 65
    def initialize(size=1024)
      @fds = {}
      @epfd = epoll_create(size)
      raise SystemCallError.new("Error creating epoll descriptor", get_errno) unless @epfd > 0
      @epfd = IO.for_fd(@epfd)
    end

Public instance methods

add (type, target, options={})

Generic method for adding events. This simply calls the proper add_foo method specified by the type symbol. Example:

ep.add(:socket, sock, :events => [:read])
calls -> ep.add_socket(sock, events => [:read])

Note: even though epoll only supports :socket style descriptors, we keep this for consistency with other APIs.

[show source]
# File lib/ktools/epoll.rb, line 78
    def add(type, target, options={})
      case type
      when :socket
        add_socket(target, options)
      else
        raise ArgumentError.new("Epoll only supports socket style descriptors")
      end
    end
add_socket (target, options={})

Add events to a socket-style descriptor (socket or pipe). Your target can be either an IO object (socket, pipe), or a file descriptor number.

Supported :events are:

  • :read - The descriptor has become readable.
  • :write - The descriptor has become writeable.
  • :priority - There is urgent data available for read operations.
  • :error - Error condition happened on the associated file descriptor. (Always active)
  • :hangup - Hang up happened on the associated file descriptor. (Always active)
  • :remote_hangup - Stream socket peer closed the connection, or shut down writing half of connection. (Missing from some kernel verions)

Supported :flags are:

  • :edge - Sets the Edge Triggered behavior for the associated file descriptor. (see manpage)
  • :oneshot - Sets the one-shot behaviour for the associated file descriptor. (Event only fires once)

Example:

irb(main):001:0> require 'ktools'
=> true
irb(main):002:0> r, w = IO.pipe
=> [#<IO:0x89be38c>, #<IO:0x89be378>]
irb(main):003:0> ep = Epoll.new
=> #<Kernel::Epoll:0x89bca3c @fds={}, @epfd=5>
irb(main):004:0> ep.add(:socket, r, :events => [:read])
=> true
irb(main):005:0> ep.poll
=> []
irb(main):006:0> w.write 'foo'
=> 3
irb(main):007:0> ep.poll
=> [{:target=>#<IO:0x89be38c>, :events=>[:read], :type=>:socket}]
irb(main):008:0> [r, w, ep].each{|x| x.close }
[show source]
# File lib/ktools/epoll.rb, line 121
    def add_socket(target, options={})
      fdnum = target.respond_to?(:fileno) ? target.fileno : target
      events = (options[:events] + (options[:flags] || [])).inject(0){|m,i| m | EP_FLAGS[i]}

      ev = Epoll_event.new
      ev[:events] = events
      ev[:data] = Epoll_data.new
      ev[:data][:fd] = fdnum

      if epoll_ctl(@epfd.fileno, EPOLL_CTL_ADD, fdnum, ev) == -1
        return false
      else
        @fds[fdnum] = {:target => target, :event => ev}
        return true
      end
    end
close ()
[show source]
# File lib/ktools/epoll.rb, line 198
    def close
      @epfd.close
    end
delete (type, target)

Stop generating events for the given type and event target, ie:

ep.delete(:socket, sock)

Note: even though epoll only supports :socket style descriptors, we keep this for consistency with other APIs.

[show source]
# File lib/ktools/epoll.rb, line 189
    def delete(type, target)
      ident = target.respond_to?(:fileno) ? target.fileno : target
      h = @fds[ident]
      return false if h.nil?
      epoll_ctl(@epfd.fileno, EPOLL_CTL_DEL, ident, h[:event])
      @fds.delete(ident)
      return true
    end
poll (timeout=0.0)

Poll for an event. Pass an optional timeout float as number of seconds to wait for an event. Default is 0.0 (do not wait).

Using a timeout will block the current thread for the duration of the timeout. We use select() on the epoll descriptor and then call epoll_wait() with 0 timeout, instead of blocking the whole interpreter with epoll_wait().

This call returns an array of hashes, similar to the following:

=> [{:type=>:socket, :target=>#<IO:0x4fa90c>, :events=>[:read]}]
  • :type - will be the type of event target, i.e. an event set with add_socket will have :type => :socket
  • :target - the ‘target’ or ‘subject’ of the event. This can be a File, IO, process or signal number.
  • :event - the event that occurred on the target. This is one or more of the symbols you passed as :events => [:foo] when adding the event.

Note: even though epoll only supports :socket style descriptors, we keep :type for consistency with other APIs.

[show source]
# File lib/ktools/epoll.rb, line 151
    def poll(timeout=0.0)
      ev = Epoll_event.new

      r, w, e = IO.select([@epfd], nil, nil, timeout)

      if r.nil? || r.empty?
        return []
      else
        case epoll_wait(@epfd.fileno, ev, 1, 0)
        when -1
          [errno]
        when 0
          []
        else
          [process_event(ev)]
        end
      end
    end