Class: Kernel::Epoll
- Inherits:
-
Object
- Object
- Kernel::Epoll
- Extended by:
- FFI::Library
- Defined in:
- lib/ktools/epoll.rb
Defined Under Namespace
Classes: Epoll_data, Epoll_event
Constant Summary collapse
- EP_FLAGS =
{ :read => EPOLLIN, :write => EPOLLOUT, :hangup => EPOLLHUP, :priority => EPOLLPRI, :edge => EPOLLET, :oneshot => EPOLLONESHOT, :error => EPOLLERR }
Instance Method Summary collapse
-
#add(type, target, options = {}) ⇒ Object
Generic method for adding events.
-
#add_socket(target, options = {}) ⇒ Object
Add events to a socket-style descriptor (socket or pipe).
- #close ⇒ Object
-
#delete(type, target) ⇒ Object
Stop generating events for the given type and event target, ie: ep.delete(:socket, sock).
-
#initialize(size = 1024) ⇒ Epoll
constructor
Creates a new epoll event queue.
-
#poll(timeout = 0.0) ⇒ Object
Poll for an event.
-
#process_event(ev) ⇒ Object
:nodoc:.
Constructor Details
#initialize(size = 1024) ⇒ Epoll
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.
65 66 67 68 69 70 |
# 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 |
Instance Method Details
#add(type, target, options = {}) ⇒ Object
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.
78 79 80 81 82 83 84 85 |
# File 'lib/ktools/epoll.rb', line 78 def add(type, target, ={}) case type when :socket add_socket(target, ) else raise ArgumentError.new("Epoll only supports socket style descriptors") end end |
#add_socket(target, options = {}) ⇒ Object
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 }
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/ktools/epoll.rb', line 121 def add_socket(target, ={}) fdnum = target.respond_to?(:fileno) ? target.fileno : target events = ([:events] + ([: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 ⇒ Object
198 199 200 |
# File 'lib/ktools/epoll.rb', line 198 def close @epfd.close end |
#delete(type, target) ⇒ Object
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.
189 190 191 192 193 194 195 196 |
# 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) ⇒ Object
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.
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# 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 |
#process_event(ev) ⇒ Object
:nodoc:
170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/ktools/epoll.rb', line 170 def process_event(ev) #:nodoc: h = @fds[ev[:data][:fd]] return nil if h.nil? events = [] events << :read if ev[:events] & EPOLLIN == EPOLLIN events << :write if ev[:events] & EPOLLOUT == EPOLLOUT events << :priority if ev[:events] & EPOLLPRI == EPOLLPRI events << :error if ev[:events] & EPOLLERR == EPOLLERR events << :hangup if ev[:events] & EPOLLHUP == EPOLLHUP events << :remote_hangup if Epoll.const_defined?("EPOLLRDHUP") and ev[:events] & EPOLLRDHUP == EPOLLRDHUP events << :oneshot if h[:event][:events] & EPOLLONESHOT == EPOLLONESHOT delete(:socket, h[:target]) if events.include?(:oneshot) || events.include?(:hangup) || events.include?(:remote_hangup) {:target => h[:target], :events => events, :type => :socket} end |