about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2015-05-08 02:42:54 +0000
committerEric Wong <e@80x24.org>2015-05-08 02:44:33 +0000
commita25a203038bba9769ada5afd478d6250a44f543b (patch)
tree36f352ffbc6a878a71ac837088a5d793220055d1
parent9e3217b0522315d2d115e53309f3563e9554ffc9 (diff)
downloadyahns-a25a203038bba9769ada5afd478d6250a44f543b.tar.gz
Reactivating a client socket after the proxied response is
complete requires the object remain visible to the Ruby GC while
no thread is accessing it.  So we must place the object back
into the fdmap to prevent the GC from eating it (and having
epoll return an invalid pointer).
-rw-r--r--lib/yahns/fdmap.rb9
-rw-r--r--lib/yahns/proxy_http_response.rb3
-rw-r--r--lib/yahns/queue_epoll.rb2
-rw-r--r--lib/yahns/queue_kqueue.rb2
4 files changed, 13 insertions, 3 deletions
diff --git a/lib/yahns/fdmap.rb b/lib/yahns/fdmap.rb
index d1f752a..523b003 100644
--- a/lib/yahns/fdmap.rb
+++ b/lib/yahns/fdmap.rb
@@ -59,6 +59,15 @@ class Yahns::Fdmap # :nodoc:
     end
   end
 
+  # used by proxy to re-enable an existing client
+  def remember(io)
+    fd = io.fileno
+    @fdmap_mtx.synchronize do
+      @count += 1
+      @fdmap_ary[fd] = io
+    end
+  end
+
   # this is only called in Errno::EMFILE/Errno::ENFILE situations
   # and graceful shutdown
   def desperate_expire(timeout)
diff --git a/lib/yahns/proxy_http_response.rb b/lib/yahns/proxy_http_response.rb
index 4801008..5bb0608 100644
--- a/lib/yahns/proxy_http_response.rb
+++ b/lib/yahns/proxy_http_response.rb
@@ -228,6 +228,7 @@ module Yahns::HttpResponse # :nodoc:
   end
 
   def proxy_wait_next(qflags)
+    Thread.current[:yahns_fdmap].remember(self)
     # We must allocate a new, empty request object here to avoid a TOCTTOU
     # in the following timeline
     #
@@ -261,7 +262,7 @@ module Yahns::HttpResponse # :nodoc:
     case http_response_done(alive)
     when :wait_readable then proxy_wait_next(Yahns::Queue::QEV_RD)
     when :wait_writable then proxy_wait_next(Yahns::Queue::QEV_WR)
-    when :close then Thread.current[:yahns_fdmap].sync_close(self)
+    when :close then close
     end
 
     nil # close the req_res, too
diff --git a/lib/yahns/queue_epoll.rb b/lib/yahns/queue_epoll.rb
index 10ff607..4f3289e 100644
--- a/lib/yahns/queue_epoll.rb
+++ b/lib/yahns/queue_epoll.rb
@@ -58,7 +58,7 @@ class Yahns::Queue < SleepyPenguin::Epoll::IO # :nodoc:
             # expected to work, so we had to erase it from fdmap before hijack
           when nil, :close
             # this must be the ONLY place where we call IO#close on
-            # things that got inside the queue
+            # things that got inside the queue AND fdmap
             @fdmap.sync_close(io)
           else
             raise "BUG: #{io.inspect}#yahns_step returned: #{rv.inspect}"
diff --git a/lib/yahns/queue_kqueue.rb b/lib/yahns/queue_kqueue.rb
index c0667b7..4176f7a 100644
--- a/lib/yahns/queue_kqueue.rb
+++ b/lib/yahns/queue_kqueue.rb
@@ -66,7 +66,7 @@ class Yahns::Queue < SleepyPenguin::Kqueue::IO # :nodoc:
             # expected to work, so we had to erase it from fdmap before hijack
           when nil, :close
             # this must be the ONLY place where we call IO#close on
-            # things that got inside the queue
+            # things that got inside the queue AND fdmap
             @fdmap.sync_close(io)
           else
             raise "BUG: #{io.inspect}#yahns_step returned: #{rv.inspect}"