yahns Ruby server user/dev discussion
 help / color / mirror / code / Atom feed
From: Eric Wong <e@80x24.org>
To: yahns-public@yhbt.net
Subject: [PATCH] tests: thread-safety fixes
Date: Tue,  1 May 2018 19:42:22 +0000	[thread overview]
Message-ID: <20180501194222.11732-1-e@80x24.org> (raw)

We can't require 'proxy_pass' in both a parent and forked child,
so require it up front (as kcar will become a hard dependency
in place of unicorn).

Then, rely on GTL (global test lock) to synchronize around fork
since the VM may not always be able to protect that.

However, there's no need to synchronize around
spawn/system/`backtick`, as the VM should always be using those
in a thread-safe way (via vfork).
---
 test/helper.rb                       | 4 ++++
 test/server_helper.rb                | 2 +-
 test/test_bin.rb                     | 8 ++++----
 test/test_config.rb                  | 4 ++--
 test/test_extras_try_gzip_static.rb  | 2 +-
 test/test_proxy_pass.rb              | 3 +--
 test/test_proxy_pass_no_buffering.rb | 2 +-
 test/test_server.rb                  | 2 +-
 8 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/test/helper.rb b/test/helper.rb
index 634f63e..3023dee 100644
--- a/test/helper.rb
+++ b/test/helper.rb
@@ -136,6 +136,10 @@ def require_exec(cmd)
   false
 end
 
+def xfork
+  GTL.synchronize { fork { yield } }
+end
+
 class DieIfUsed
   @@n = 0
   def each
diff --git a/test/server_helper.rb b/test/server_helper.rb
index 9ef15c6..91d7208 100644
--- a/test/server_helper.rb
+++ b/test/server_helper.rb
@@ -91,7 +91,7 @@ def server_helper_setup
   end
 
   def mkserver(cfg, srv = @srv)
-    fork do
+    xfork do
       ENV["YAHNS_FD"] = srv.fileno.to_s
       srv.autoclose = false
       yield if block_given?
diff --git a/test/test_bin.rb b/test/test_bin.rb
index e59c9b4..6d4faf6 100644
--- a/test/test_bin.rb
+++ b/test/test_bin.rb
@@ -22,7 +22,7 @@ def test_listen_fd3
     [ %w(-O listen=inherit), %W(-p #{port} -o #{host}) ].each do |opt|
       @srv.setsockopt(:SOL_SOCKET, :SO_KEEPALIVE, 0)
       begin
-        pid = fork do # emulate a systemd environment
+        pid = xfork do # emulate a systemd environment
           env = { 'LISTEN_PID' => $$.to_s, 'LISTEN_FDS' => '1' }
           cmd.concat(opt)
           exec env, *cmd, 3 => @srv, err: @err.path
@@ -77,7 +77,7 @@ def bin_daemon(worker, inherit)
     cfg.puts "end"
     @cmd.concat(%W(-D -c #{cfg.path}))
     addr = cloexec_pipe
-    pid = fork do
+    pid = xfork do
       opts = { close_others: true }
       addr[0].close
       if inherit
@@ -159,7 +159,7 @@ def usr2_dir(tmpdir, preload, worker)
     # need to fork here since tests are MT and the FD can leak out and go to
     # other processes which fork (but do not exec), causing ETXTBUSY on
     # Process.spawn
-    pid = fork do
+    pid = xfork do
       File.open(exe, "w") { |y|
         lines = File.readlines("bin/yahns")
         lines[0] = "#!#{RbConfig.ruby}\n"
@@ -190,7 +190,7 @@ def usr2_dir(tmpdir, preload, worker)
     }
     cmd = %W(#{exe} -D -c #{cfg.path})
     cmd << { @srv => @srv, close_others: true }
-    pid = GTL.synchronize { Process.spawn(env, *cmd) }
+    pid = Process.spawn(env, *cmd)
     res = Net::HTTP.start(host, port) { |h| h.get("/") }
     assert_equal 200, res.code.to_i
     orig = res.body
diff --git a/test/test_config.rb b/test/test_config.rb
index 73d9456..c609d5a 100644
--- a/test/test_config.rb
+++ b/test/test_config.rb
@@ -13,7 +13,7 @@ def test_initialize
   end
 
   def test_multi_conf_example
-    pid = fork do
+    pid = xfork do
       tmpdir = yahns_mktmpdir
 
       # modify the example config file for testing
@@ -37,7 +37,7 @@ def test_multi_conf_example
   end
 
   def test_rack_basic_conf_example
-    pid = fork do
+    pid = xfork do
       tmpdir = yahns_mktmpdir
 
       # modify the example config file for testing
diff --git a/test/test_extras_try_gzip_static.rb b/test/test_extras_try_gzip_static.rb
index b6d5943..5901c9d 100644
--- a/test/test_extras_try_gzip_static.rb
+++ b/test/test_extras_try_gzip_static.rb
@@ -52,7 +52,7 @@ def test_gzip_static
       File.symlink "COPYING", "#{tmpdir}/COPYING.relsymlink"
       gplgz = "#{tmpdir}/COPYING.gz"
       FileUtils.cp("COPYING", gpl)
-      _, status = Process.waitpid2(fork do
+      _, status = Process.waitpid2(xfork do
         File.open(gplgz, "w") do |fp|
           Zlib::GzipWriter.wrap(fp.dup) { |io| io.write(GPL_TEXT) }
         end
diff --git a/test/test_proxy_pass.rb b/test/test_proxy_pass.rb
index 22f1802..51d0d3f 100644
--- a/test/test_proxy_pass.rb
+++ b/test/test_proxy_pass.rb
@@ -6,6 +6,7 @@
 require 'digest'
 begin
   require 'kcar'
+  require 'yahns/proxy_pass'
 rescue LoadError
 end
 
@@ -188,7 +189,6 @@ def test_unix_socket_no_path
     pid = mkserver(cfg) do
       @srv.autoclose = @srv2.autoclose = false
       ENV["YAHNS_FD"] = "#{@srv.fileno},#{@srv2.fileno}"
-      require 'yahns/proxy_pass'
       cfg.instance_eval do
         app(:rack, Yahns::ProxyPass.new("unix:#{unix_path}:/$fullpath")) do
           listen "#{host}:#{port}"
@@ -251,7 +251,6 @@ def test_proxy_pass
     err, cfg, host, port = @err, Yahns::Config.new, @srv.addr[3], @srv.addr[1]
     host2, port2 = @srv2.addr[3], @srv2.addr[1]
     pid = mkserver(cfg) do
-      require 'yahns/proxy_pass'
       @srv2.close
       cfg.instance_eval do
         app(:rack, Yahns::ProxyPass.new("http://#{host2}:#{port2}")) do
diff --git a/test/test_proxy_pass_no_buffering.rb b/test/test_proxy_pass_no_buffering.rb
index 356623f..61f2959 100644
--- a/test/test_proxy_pass_no_buffering.rb
+++ b/test/test_proxy_pass_no_buffering.rb
@@ -4,6 +4,7 @@
 require_relative 'server_helper'
 begin
   require 'kcar'
+  require 'yahns/proxy_pass'
 rescue LoadError
 end
 require 'digest/md5'
@@ -39,7 +40,6 @@ def setup
     @srv2 = TCPServer.new(ENV["TEST_HOST"] || "127.0.0.1", 0)
     server_helper_setup
     skip "kcar missing yahns/proxy_pass" unless defined?(Kcar)
-    require 'yahns/proxy_pass'
     @tmpdir = yahns_mktmpdir
   end
 
diff --git a/test/test_server.rb b/test/test_server.rb
index c6d70cb..a113b43 100644
--- a/test/test_server.rb
+++ b/test/test_server.rb
@@ -225,7 +225,7 @@ def a.each
     assert_equal 1, eggs.size
     assert_equal 1, eggs.first[1].instance_variable_get(:@worker_threads)
 
-    pid = fork do
+    pid = xfork do
       bpipe[1].close
       ENV["YAHNS_FD"] = unix_srv.fileno.to_s
       unix_srv.autoclose = false
-- 
EW


                 reply	other threads:[~2018-05-01 19:42 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://yhbt.net/yahns/README

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180501194222.11732-1-e@80x24.org \
    --to=e@80x24.org \
    --cc=yahns-public@yhbt.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://yhbt.net/yahns.git/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).