epoll: handle EINTR properly in Ruby-space
[rainbows.git] / lib / rainbows / epoll / server.rb
blob820a6da18ed4082a9ac7d3f3a5cf12f7fc2e54a6
1 # -*- encoding: binary -*-
2 # :nodoc:
3 module Rainbows::Epoll::Server
4   IN = SleepyPenguin::Epoll::IN | SleepyPenguin::Epoll::ET
5   @@nr = 0
6   MAX = Rainbows.server.worker_connections
7   THRESH = MAX - 1
8   LISTENERS = Rainbows::HttpServer::LISTENERS
9   ReRun = []
10   EP = Rainbows::Epoll::EP
12   def self.run
13     LISTENERS.each { |sock| EP.add(sock.extend(self), IN) }
14     begin
15       EP.wait(nil, 1000) { |_, obj| obj.epoll_run }
16       while obj = ReRun.shift
17         obj.epoll_run
18       end
19       Rainbows::Epoll::Client.expire
20     rescue Errno::EINTR
21     rescue => e
22       Rainbows::Error.listen_loop(e)
23     end while Rainbows.tick || @@nr > 0
24   end
26   # rearms all listeners when there's a free slot
27   def self.decr
28     THRESH == (@@nr -= 1) and LISTENERS.each { |sock| EP.set(sock, IN) }
29   end
31   def epoll_run
32     return EP.delete(self) if @@nr >= MAX
33     while io = kgio_tryaccept
34       @@nr += 1
35       # there's a chance the client never even sees epoll for simple apps
36       io.epoll_once
37       return EP.delete(self) if @@nr >= MAX
38     end
39   end
40 end