diff options
author | Eric Wong <e@80x24.org> | 2013-11-07 09:12:58 +0000 |
---|---|---|
committer | Eric Wong <e@80x24.org> | 2013-11-07 09:12:58 +0000 |
commit | 33eaf25f43fd73d8f4f7b0a066b689809d733191 (patch) | |
tree | 125188374272ce1be414b390f7b79f662e8284cd | |
parent | 07e5a1d7e8624e57d640af1d641c7ca51a948ecd (diff) | |
download | yahns-33eaf25f43fd73d8f4f7b0a066b689809d733191.tar.gz |
Our QueueQuitter may race with epoll_wait and GC, potentially triggering memory corruption if a level-trigger object was placed into the ready list and no longer referenced. We'll work around this problem by making the QueueQuitter object a thread-local (on thread failure) to prevent concurency issues where the epoll pointer no longer points to a Ruby object.
-rw-r--r-- | lib/yahns/fdmap.rb | 5 | ||||
-rw-r--r-- | lib/yahns/server.rb | 4 |
2 files changed, 9 insertions, 0 deletions
diff --git a/lib/yahns/fdmap.rb b/lib/yahns/fdmap.rb index a9125e7..5ba4399 100644 --- a/lib/yahns/fdmap.rb +++ b/lib/yahns/fdmap.rb @@ -36,6 +36,11 @@ class Yahns::Fdmap # :nodoc: # as one which got accept-ed (a brand new IO object) so we must prevent # IO#close in worker threads from racing with any threads which may run # __expire + # + # We must never, ever call this while it is capable of being on the + # epoll ready list and returnable by epoll_wait. So we can only call + # this on objects which were epoll_ctl-ed with EPOLLONESHOT (and now + # retrieved). def sync_close(io) @fdmap_mtx.synchronize do @count -= 1 diff --git a/lib/yahns/server.rb b/lib/yahns/server.rb index f956d50..ddba8f2 100644 --- a/lib/yahns/server.rb +++ b/lib/yahns/server.rb @@ -416,6 +416,10 @@ class Yahns::Server # :nodoc: # cleanup, our job is done @queues.each(&:close).clear + + # we must not let quitter get GC-ed if we have any worker threads leftover + @wthr.each { |t| t[:yahns_quitter] = quitter } + quitter.close rescue => e Yahns::Log.exception(@logger, "quit finish", e) |