about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2010-08-28 05:30:46 +0000
committerEric Wong <normalperson@yhbt.net>2010-08-28 06:28:04 +0000
commit4b23693b9082a84433a9e6c1f358b58420176b27 (patch)
tree180cf66753e78fcb0615b11c62f95aa4abd76863
parent096afc1a8e958cc09b4ce8b3bfe76ce056c7ed69 (diff)
downloadunicorn-4b23693b9082a84433a9e6c1f358b58420176b27.tar.gz
IOError may occur due to race conditions as another thread
may close the file immediately after we call File#closed?
to check.

Errno::EBADF may occur in some applications that close a file
descriptor without notifying Ruby (or if two IO objects refer to
the same descriptor, possibly one of them using IO#for_fd).
-rw-r--r--lib/unicorn/util.rb18
1 files changed, 16 insertions, 2 deletions
diff --git a/lib/unicorn/util.rb b/lib/unicorn/util.rb
index e8c09d0..a735c68 100644
--- a/lib/unicorn/util.rb
+++ b/lib/unicorn/util.rb
@@ -24,6 +24,8 @@ module Unicorn
           fp.sync &&
           fp.path[0] == ?/ &&
           (fp.fcntl(Fcntl::F_GETFL) & append_flags) == append_flags
+        rescue IOError, Errno::EBADF
+          false
       end
 
       def chown_logs(uid, gid)
@@ -46,19 +48,31 @@ module Unicorn
         ObjectSpace.each_object(File) { |fp| is_log?(fp) and to_reopen << fp }
 
         to_reopen.each do |fp|
-          orig_st = fp.stat
+          orig_st = begin
+            fp.stat
+          rescue IOError, Errno::EBADF
+            next
+          end
+
           begin
             b = File.stat(fp.path)
             next if orig_st.ino == b.ino && orig_st.dev == b.dev
           rescue Errno::ENOENT
           end
 
-          File.open(fp.path, 'a') { |tmpfp| fp.reopen(tmpfp) }
+          begin
+            File.open(fp.path, 'a') { |tmpfp| fp.reopen(tmpfp) }
+          rescue IOError, Errno::EBADF
+            next
+          end
           fp.sync = true
           new_st = fp.stat
+
+          # this should only happen in the master:
           if orig_st.uid != new_st.uid || orig_st.gid != new_st.gid
             fp.chown(orig_st.uid, orig_st.gid)
           end
+
           nr += 1
         end