about summary refs log tree commit homepage
path: root/lib/yahns
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2013-10-30 01:50:17 +0000
committerEric Wong <normalperson@yhbt.net>2013-10-30 07:01:01 +0000
commit61f325506c699292bf6ec7982ab824bc375ca03f (patch)
tree2a3412f24e538966bcc07a3eb649de93591baeb6 /lib/yahns
parent666d1936c72ae73b9f02d73000015135cdc4a716 (diff)
downloadyahns-61f325506c699292bf6ec7982ab824bc375ca03f.tar.gz
This saves about 200 bytes of unswappable kernel memory,
so it might matter for systems with many connections
when hijacking.
Diffstat (limited to 'lib/yahns')
-rw-r--r--lib/yahns/acceptor.rb3
-rw-r--r--lib/yahns/http_client.rb15
-rw-r--r--lib/yahns/http_context.rb2
-rw-r--r--lib/yahns/http_response.rb5
-rw-r--r--lib/yahns/queue_epoll.rb4
-rw-r--r--lib/yahns/server.rb4
-rw-r--r--lib/yahns/wbuf_common.rb3
7 files changed, 26 insertions, 10 deletions
diff --git a/lib/yahns/acceptor.rb b/lib/yahns/acceptor.rb
index 22a58ee..2a212cf 100644
--- a/lib/yahns/acceptor.rb
+++ b/lib/yahns/acceptor.rb
@@ -35,9 +35,10 @@ module Yahns::Acceptor # :nodoc:
     return __ac_quit_done?
   end
 
-  def spawn_acceptor(nr, logger, client_class, queue)
+  def spawn_acceptor(nr, logger, client_class)
     @thrs = nr.times.map do
       Thread.new do
+        queue = client_class.queue
         t = Thread.current
         accept_flags = Kgio::SOCK_NONBLOCK | Kgio::SOCK_CLOEXEC
         qev_flags = client_class.superclass::QEV_FLAGS
diff --git a/lib/yahns/http_client.rb b/lib/yahns/http_client.rb
index 3af18cf..721be04 100644
--- a/lib/yahns/http_client.rb
+++ b/lib/yahns/http_client.rb
@@ -226,7 +226,10 @@ class Yahns::HttpClient < Kgio::Socket # :nodoc:
   end
 
   def hijack_proc(env)
-    proc { env[RACK_HIJACK_IO] = self }
+    proc do
+      self.class.queue.queue_del(self) # EPOLL_CTL_DEL
+      env[RACK_HIJACK_IO] = self
+    end
   end
 
   # called automatically by kgio_write
@@ -251,6 +254,16 @@ class Yahns::HttpClient < Kgio::Socket # :nodoc:
     end while true
   end
 
+  def response_hijacked(fn)
+    # we must issue EPOLL_CTL_DEL before hijacking (if we issue it at all),
+    # because the hijacker may close use before we get back to the epoll worker
+    # loop.  EPOLL_CTL_DEL saves about 200 bytes of unswappable kernel memory,
+    # so it can matter if we have lots of hijacked sockets.
+    self.class.queue.queue_del(self)
+    fn.call(self)
+    :ignore
+  end
+
   # if we get any error, try to write something back to the client
   # assuming we haven't closed the socket, but don't get hung up
   # if the socket is already closed or broken.  We'll always return
diff --git a/lib/yahns/http_context.rb b/lib/yahns/http_context.rb
index 651cb08..605989f 100644
--- a/lib/yahns/http_context.rb
+++ b/lib/yahns/http_context.rb
@@ -15,6 +15,7 @@ module Yahns::HttpContext # :nodoc:
   attr_accessor :persistent_connections # true or false only
   attr_accessor :client_timeout
   attr_accessor :qegg
+  attr_accessor :queue # set right before spawning acceptors
   attr_reader :app
   attr_reader :app_defaults
 
@@ -30,6 +31,7 @@ module Yahns::HttpContext # :nodoc:
     @persistent_connections = true
     @client_timeout = 15
     @qegg = nil
+    @queue = nil
   end
 
   # call this after forking
diff --git a/lib/yahns/http_response.rb b/lib/yahns/http_response.rb
index 6b97038..6ddb1c8 100644
--- a/lib/yahns/http_response.rb
+++ b/lib/yahns/http_response.rb
@@ -146,10 +146,7 @@ module Yahns::HttpResponse # :nodoc:
       end while true
     end
 
-    if hijack
-      hijack.call(self)
-      return :ignore
-    end
+    return response_hijacked(hijack) if hijack
 
     if body.respond_to?(:to_path)
       @state = body = Yahns::StreamFile.new(body, alive, offset, count)
diff --git a/lib/yahns/queue_epoll.rb b/lib/yahns/queue_epoll.rb
index c22a624..3d2e33f 100644
--- a/lib/yahns/queue_epoll.rb
+++ b/lib/yahns/queue_epoll.rb
@@ -27,6 +27,10 @@ class Yahns::Queue < SleepyPenguin::Epoll::IO # :nodoc:
     Thread.current[:yahns_fdmap] = @fdmap
   end
 
+  def queue_del(io)
+    epoll_ctl(Epoll::CTL_DEL, io, 0)
+  end
+
   # returns an array of infinitely running threads
   def worker_thread(logger, max_events)
     Thread.new do
diff --git a/lib/yahns/server.rb b/lib/yahns/server.rb
index 462717b..4bd523f 100644
--- a/lib/yahns/server.rb
+++ b/lib/yahns/server.rb
@@ -344,10 +344,10 @@ class Yahns::Server # :nodoc:
       opts = sock_opts(l)
       ctx = opts[:yahns_app_ctx]
       qegg = ctx.qegg || @config.qeggs[:default]
-      q = queues[qegg] ||= qegg_vivify(qegg, fdmap)
+      ctx.queue = queues[qegg] ||= qegg_vivify(qegg, fdmap)
 
       # acceptors feed the the queues
-      l.spawn_acceptor(opts[:threads] || 1, @logger, ctx, q)
+      l.spawn_acceptor(opts[:threads] || 1, @logger, ctx)
     end
     fdmap
   end
diff --git a/lib/yahns/wbuf_common.rb b/lib/yahns/wbuf_common.rb
index 20f6e18..cfafaa2 100644
--- a/lib/yahns/wbuf_common.rb
+++ b/lib/yahns/wbuf_common.rb
@@ -23,8 +23,7 @@ module Yahns::WbufCommon # :nodoc:
   def wbuf_close_common(client)
     @body.close if @body.respond_to?(:close)
     if @wbuf_persist.respond_to?(:call) # hijack
-      @wbuf_persist.call(client)
-      :ignore
+      client.response_hijacked(@wbuf_persist) # :ignore
     else
       @wbuf_persist # true or false or Yahns::StreamFile
     end