about summary refs log tree commit homepage
path: root/lib/yahns/acceptor.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/yahns/acceptor.rb')
-rw-r--r--lib/yahns/acceptor.rb75
1 files changed, 44 insertions, 31 deletions
diff --git a/lib/yahns/acceptor.rb b/lib/yahns/acceptor.rb
index 76fcc26..268393c 100644
--- a/lib/yahns/acceptor.rb
+++ b/lib/yahns/acceptor.rb
@@ -3,48 +3,61 @@
 # License: GPLv3 or later (see COPYING for details)
 module Yahns::Acceptor # :nodoc:
   def __ac_quit_done?
-    @thr.join(0.01) ? close.nil? : false
-  rescue
-    @thr.alive? ? false : close.nil?
+    @thrs.delete_if do |t|
+      begin
+        t.join(0.01)
+      rescue
+        ! t.alive?
+      end
+    end
+    return false if @thrs[0]
+    close
+    true
   end
 
   # just keep looping this on every acceptor until the associated thread dies
   def ac_quit
-    @thr[:yahns_quit] = true
+    @thrs.each { |t| t[:yahns_quit] = true }
     return true if __ac_quit_done?
 
-    # try to connect to kick it out of the blocking accept() syscall
-    killer = Kgio::Socket.start(getsockname)
-    killer.kgio_write("G") # first byte of "GET / HTTP/1.0\r\n\r\n"
+    @thrs.each do
+      begin
+        # try to connect to kick it out of the blocking accept() syscall
+        killer = Kgio::Socket.start(getsockname)
+        killer.kgio_write("G") # first byte of "GET / HTTP/1.0\r\n\r\n"
+      ensure
+        killer.close if killer
+      end
+    end
     false # now hope __ac_quit_done? is true next time around
   rescue SystemCallError
-    __ac_quit_done?
-  ensure
-    killer.close if killer
+    return __ac_quit_done?
   end
 
-  def spawn_acceptor(logger, client_class, queue)
-    @thr = Thread.new do
-      t = Thread.current
-      accept_flags = Kgio::SOCK_NONBLOCK | Kgio::SOCK_CLOEXEC
-      qev_flags = client_class.superclass::QEV_FLAGS
-      begin
-        # We want the accept/accept4 syscall to be _blocking_
-        # so it can distribute work evenly between processes
-        if client = kgio_accept(client_class, accept_flags)
-          client.yahns_init
+  def spawn_acceptor(nr, logger, client_class, queue)
+    @thrs = nr.times.map do
+      Thread.new do
+        t = Thread.current
+        accept_flags = Kgio::SOCK_NONBLOCK | Kgio::SOCK_CLOEXEC
+        qev_flags = client_class.superclass::QEV_FLAGS
+        begin
+          # We want the accept/accept4 syscall to be _blocking_
+          # so it can distribute work evenly between processes
+          if client = kgio_accept(client_class, accept_flags)
+            client.yahns_init
 
-          # it is not safe to touch client in this thread after this,
-          # a worker thread may grab client right away
-          queue.queue_add(client, qev_flags)
-        end
-      rescue Errno::EMFILE, Errno::ENFILE => e
-        logger.error("#{e.message}, consider raising open file limits")
-        queue.fdmap.desperate_expire_for(nil, 5)
-        sleep 1 # let other threads do some work
-      rescue => e
-        Yahns::Log.exception(logger, "accept loop", e)
-      end until t[:yahns_quit]
+            # it is not safe to touch client in this thread after this,
+            # a worker thread may grab client right away
+            queue.queue_add(client, qev_flags)
+          end
+        rescue Errno::EMFILE, Errno::ENFILE => e
+          logger.error("#{e.message}, consider raising open file limits")
+          queue.fdmap.desperate_expire_for(nil, 5)
+          sleep 1 # let other threads do some work
+        rescue => e
+          Yahns::Log.exception(logger, "accept loop", e)
+        end until t[:yahns_quit]
+      end
     end
   end
 end