yahns 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7b73379a257ad0e09cd00b6d1b1b316ca6913992
4
- data.tar.gz: 1e5203cb1d70720bdab3f9624b9766e3d49a9d51
3
+ metadata.gz: 8cc5928f1f563c752e54bb5facb8c9a0ca63bcd1
4
+ data.tar.gz: 4aced2fa3dbe3e094f724961ce9d840e7ce4d44f
5
5
  SHA512:
6
- metadata.gz: 1c7a49cdbe694c1a27bd3f26d6db10b4b1f8ac11cf9307036957ba9df60aab266ef621cf515dcfd9eb592675648a0864b9949ba9b11ffccf083627a392353879
7
- data.tar.gz: 2250ca7bf3fdfffbbb42cbb332cbe08bca48aa4c0e6066d3414e3248a2e666094ba2da07ff27312021558b67e45de59bdb10428fcd089c72bbfaeabd9f3488da
6
+ metadata.gz: 939413895994a570e99fc3d5efa2b7513787ea9a22f40d6ab746778a62c664da079d76a3808bbd4e25a0fd65d7a0e6f38db2b96a3b74cd527e0d305ce464d04a
7
+ data.tar.gz: 2dabbe0e008fb38b2b9cad8cdc0097565dcaa179ba53ee0bb8266a7f1e737634467f7b0ddc05913acd98f14c465274194129c1258bb5394dfa0557e12f7d9a07
@@ -132,7 +132,7 @@ See rackup documentation for more details.
132
132
 
133
133
  # CONTACT
134
134
 
135
- All feedback welcome via plain-text mail to <yahns-public@rubyforge.org>\
135
+ All feedback welcome via plain-text mail to <yahns-public@yhbt.net>\
136
136
  No subscription is necessary to post to the mailing list.
137
137
 
138
138
  # COPYRIGHT
@@ -148,5 +148,5 @@ yahns(1), yahns_config(5)
148
148
  * [Rack RDoc][1]
149
149
  * [Rackup HowTo][2]
150
150
 
151
- [1]: http://rack.rubyforge.org/doc/
151
+ [1]: http://rdoc.info/gems/r#/gems/rack/frames
152
152
  [2]: http://wiki.github.com/rack/rack/tutorial-rackup-howto
@@ -55,7 +55,7 @@ See yahns_config(5) for documentation on the configuration file format.
55
55
 
56
56
  # CONTACT
57
57
 
58
- All feedback welcome via plain-text mail to <yahns-public@rubyforge.org>\
58
+ All feedback welcome via plain-text mail to <yahns-public@yhbt.net>\
59
59
  No subscription is necessary to post to the mailing list.
60
60
 
61
61
  # COPYRIGHT
@@ -4,7 +4,7 @@
4
4
  CONSTANT = "Yahns::VERSION"
5
5
  RVF = "lib/yahns/version.rb"
6
6
  GVF = "GIT-VERSION-FILE"
7
- DEF_VER = "v1.2.0"
7
+ DEF_VER = "v1.3.0"
8
8
  vn = DEF_VER
9
9
 
10
10
  # First see if there is a version file (included in release tarballs),
data/HACKING CHANGED
@@ -46,10 +46,10 @@ contact
46
46
 
47
47
  We use git(7) and develop yahns on a public mailing list like git
48
48
  developers do. Please send patches via git-send-email(1) to the public
49
- mailing list at <yahns-public@rubyforge.org>. Pull requests should be
49
+ mailing list at <yahns-public@yhbt.net>. Pull requests should be
50
50
  formatted using git-request-pull(1).
51
51
 
52
- Mailing list archives: http://rubyforge.org/pipermail/yahns-public/
52
+ Mailing list archives: http://yhbt.net/yahns-public/
53
53
  No subscription is necessary to post to the mailing list.
54
54
  Please remember to Cc: all recipients.
55
55
 
data/README CHANGED
@@ -56,17 +56,19 @@ Contact
56
56
 
57
57
  We are happy to see feedback of all types via plain-text email.
58
58
  Please send comments, user/dev discussion, patches, bug reports,
59
- and pull requests to the public mailing list at:
59
+ and pull requests to the public inbox/mailing list at:
60
60
 
61
- yahns-public@rubyforge.org
61
+ yahns-public@yhbt.net
62
62
 
63
63
  No subscription is necessary to post. Please Cc: all recipients as
64
64
  subscription is not necessary.
65
65
 
66
- You may subscribe by sending a request to:
66
+ You may subscribe by sending an email to:
67
67
 
68
- yahns-public-request@rubyforge.org
69
- with the Subject line: "subscribe"
68
+ yahns-public+subscribe@yhbt.net
69
+
70
+ You may also subscribe to the public-inbox at git://yhbt.net/yahns-public
71
+ using ssoma <http://ssoma.public-inbox.org/>
70
72
 
71
73
  This README is our homepage, we would rather be working on HTTP servers
72
74
  all day than worrying about the next browser vulnerability because
@@ -62,9 +62,11 @@ class ExecCgi
62
62
  SERVER_PORT
63
63
  SERVER_PROTOCOL
64
64
  SERVER_SOFTWARE
65
+ SCRIPT_NAME
65
66
  ).map(&:freeze) # frozen strings are faster for Hash assignments
66
67
 
67
68
  def initialize(*args)
69
+ @env = Hash === args[0] ? args.shift : {}
68
70
  @args = args
69
71
  first = args[0] or
70
72
  raise ArgumentError, "need path to executable"
@@ -75,12 +77,12 @@ class ExecCgi
75
77
 
76
78
  # Calls the app
77
79
  def call(env)
78
- cgi_env = { "SCRIPT_NAME" => @args[0], "GATEWAY_INTERFACE" => "CGI/1.1" }
80
+ cgi_env = { "GATEWAY_INTERFACE" => "CGI/1.1" }
79
81
  PASS_VARS.each { |key| val = env[key] and cgi_env[key] = val }
80
82
  env.each { |key,val| cgi_env[key] = val if key =~ /\AHTTP_/ }
81
83
  pipe = MyIO.pipe
82
84
  errbody = pipe[0]
83
- errbody.my_pid = Process.spawn(cgi_env, *@args,
85
+ errbody.my_pid = Process.spawn(cgi_env.merge!(@env), *@args,
84
86
  out: pipe[1], close_others: true)
85
87
  pipe[1].close
86
88
  pipe = pipe[0]
@@ -79,6 +79,7 @@ class Yahns::Fdmap # :nodoc:
79
79
  # We should not be calling this too frequently, it is expensive
80
80
  # This is called while @fdmap_mtx is held
81
81
  def __expire(timeout)
82
+ return if @count == 0
82
83
  nr = 0
83
84
  now = Time.now.to_f
84
85
  (now - @last_expire) >= 1.0 or return # don't expire too frequently
@@ -26,7 +26,7 @@ class Yahns::Queue < SleepyPenguin::Kqueue::IO # :nodoc:
26
26
  # flags: QEV_RD/QEV_WR (usually QEV_RD)
27
27
  def queue_add(io, flags)
28
28
  # order is very important here, this thread cannot do anything with
29
- # io once we've issued epoll_ctl() because another thread may use it
29
+ # io once we've issued kevent EV_ADD because another thread may use it
30
30
  @fdmap.add(io)
31
31
  fflags = ADD_ONESHOT
32
32
  if flags == QEV_QUIT
@@ -54,8 +54,8 @@ class Yahns::Queue < SleepyPenguin::Kqueue::IO # :nodoc:
54
54
  begin
55
55
  kevent(nil, max_events) do |_,_,_,_,_,io| # don't care for flags for now
56
56
  # Note: we absolutely must not do anything with io after
57
- # we've called epoll_ctl on it, io is exclusive to this
58
- # thread only until epoll_ctl is called on it.
57
+ # we've called kevent(...,EV_ADD) on it, io is exclusive to this
58
+ # thread only until kevent(...,EV_ADD) is called on it.
59
59
  case rv = io.yahns_step
60
60
  when :wait_readable
61
61
  kevent(Kevent[io.fileno, QEV_RD, ADD_ONESHOT, 0, 0, io])
@@ -203,7 +203,11 @@ class Yahns::Server # :nodoc:
203
203
 
204
204
  def daemon_ready
205
205
  @daemon_pipe.respond_to?(:syswrite) or return
206
- @daemon_pipe.syswrite("#$$")
206
+ begin
207
+ @daemon_pipe.syswrite("#$$")
208
+ rescue => e
209
+ @logger.warn("grandparent died too soon?: #{e.message} (#{e.class})")
210
+ end
207
211
  @daemon_pipe.close
208
212
  @daemon_pipe = true # for SIGWINCH
209
213
  end
@@ -281,7 +285,7 @@ class Yahns::Server # :nodoc:
281
285
  @logger.info "reloading config_file=#{@config.config_file}"
282
286
  @config.config_reload!
283
287
  @config.commit!(self)
284
- kill_each_worker(:QUIT)
288
+ soft_kill_each_worker("QUIT")
285
289
  Yahns::Log.reopen_all
286
290
  @logger.info "done reloading config_file=#{@config.config_file}"
287
291
  rescue StandardError, LoadError, SyntaxError => e
@@ -7,14 +7,15 @@ module Yahns::ServerMP # :nodoc:
7
7
  def maintain_worker_count
8
8
  (off = @workers.size - @worker_processes) == 0 and return
9
9
  off < 0 and return spawn_missing_workers
10
- @workers.each do |wpid, worker|
11
- worker.nr >= @worker_processes and Process.kill(:QUIT, wpid)
10
+ @workers.each_value do |worker|
11
+ worker.nr >= @worker_processes and worker.soft_kill(Signal.list["QUIT"])
12
12
  end
13
13
  end
14
14
 
15
- # delivers a signal to each worker
16
- def kill_each_worker(signal)
17
- @workers.each_key { |wpid| Process.kill(signal, wpid) }
15
+ # fakes delivery of a signal to each worker
16
+ def soft_kill_each_worker(sig)
17
+ sig = Signal.list[sig]
18
+ @workers.each_value { |worker| worker.soft_kill(sig) }
18
19
  end
19
20
 
20
21
  # this is the first thing that runs after forking in a child
@@ -94,18 +95,18 @@ module Yahns::ServerMP # :nodoc:
94
95
  case @sig_queue.shift
95
96
  when *EXIT_SIGS # graceful shutdown (twice for non graceful)
96
97
  @listeners.each(&:close).clear
97
- kill_each_worker(:QUIT)
98
+ soft_kill_each_worker("QUIT")
98
99
  state = :QUIT
99
100
  when :USR1 # rotate logs
100
101
  usr1_reopen("master ")
101
- kill_each_worker(:USR1)
102
+ soft_kill_each_worker("USR1")
102
103
  when :USR2 # exec binary, stay alive in case something went wrong
103
104
  reexec
104
105
  when :WINCH
105
106
  if @daemon_pipe
106
107
  state = :WINCH
107
108
  @logger.info "gracefully stopping all workers"
108
- kill_each_worker(:QUIT)
109
+ soft_kill_each_worker("QUIT")
109
110
  @worker_processes = 0
110
111
  else
111
112
  @logger.info "SIGWINCH ignored because we're not daemonized"
@@ -157,7 +158,7 @@ module Yahns::ServerMP # :nodoc:
157
158
  # not performance critical
158
159
  watch.delete_if { |io| io.to_io.closed? }
159
160
  if r = IO.select(watch, nil, nil, alive ? nil : 0.01)
160
- r[0].each { |io| io.yahns_step }
161
+ r[0].each(&:yahns_step)
161
162
  end
162
163
  case @sig_queue.shift
163
164
  when *EXIT_SIGS
@@ -8,7 +8,7 @@ class Yahns::Sigevent < SleepyPenguin::EventFD # :nodoc:
8
8
  end
9
9
 
10
10
  def sev_signal
11
- incr(1) # eventfd_write
11
+ incr(1, true) # eventfd_write
12
12
  end
13
13
 
14
14
  def yahns_step
@@ -13,7 +13,7 @@ class Yahns::Sigevent # :nodoc:
13
13
  end
14
14
 
15
15
  def sev_signal
16
- @wr.kgio_write(".")
16
+ @wr.kgio_trywrite(".")
17
17
  end
18
18
 
19
19
  def yahns_step
@@ -23,15 +23,44 @@ class Yahns::Worker # :nodoc:
23
23
  # This causes the worker to gracefully exit if the master
24
24
  # dies unexpectedly.
25
25
  def yahns_step
26
- if @to_io.kgio_tryread(11) == nil
27
- Process.kill(:QUIT, $$)
26
+ case buf = @to_io.kgio_tryread(4)
27
+ when String
28
+ # unpack the buffer and trigger the signal handler
29
+ signum = buf.unpack('l')
30
+ fake_sig(signum[0])
31
+ # keep looping, more signals may be queued
32
+ when nil # EOF: master died, but we are at a safe place to exit
33
+ fake_sig(:QUIT)
28
34
  @to_io.close
29
- end
30
- :ignore
35
+ return :ignore
36
+ when :wait_readable # keep waiting
37
+ return :ignore
38
+ end while true # loop, as multiple signals may be sent
31
39
  end
32
40
 
33
41
  # worker objects may be compared to just plain Integers
34
42
  def ==(other_nr) # :nodoc:
35
43
  @nr == other_nr
36
44
  end
45
+
46
+ # call a signal handler immediately without triggering EINTR
47
+ # We do not use the more obvious Process.kill(sig, $$) here since
48
+ # that signal delivery may be deferred. We want to avoid signal delivery
49
+ # while the Rack app.call is running because some database drivers
50
+ # (e.g. ruby-pg) may cancel pending requests.
51
+ def fake_sig(sig) # :nodoc:
52
+ old_cb = trap(sig, "IGNORE")
53
+ old_cb.call
54
+ ensure
55
+ trap(sig, old_cb)
56
+ end
57
+
58
+ # master sends fake signals to children
59
+ def soft_kill(signum) # :nodoc:
60
+ # writing and reading 4 bytes on a pipe is atomic on all POSIX platforms
61
+ # Do not care in the odd case the buffer is full, here.
62
+ @wr.kgio_trywrite([signum].pack('l'))
63
+ rescue Errno::EPIPE
64
+ # worker will be reaped soon
65
+ end
37
66
  end
@@ -75,6 +75,7 @@ module ServerHelper
75
75
  def mkserver(cfg)
76
76
  fork do
77
77
  ENV["YAHNS_FD"] = @srv.fileno.to_s
78
+ @srv.autoclose = false
78
79
  yield if block_given?
79
80
  Yahns::Server.new(cfg).start.join
80
81
  end
@@ -227,6 +227,7 @@ class TestServer < Testcase
227
227
  pid = fork do
228
228
  bpipe[1].close
229
229
  ENV["YAHNS_FD"] = unix_srv.fileno.to_s
230
+ unix_srv.autoclose = false
230
231
  srv.start.join
231
232
  end
232
233
  bpipe[0].close
@@ -15,6 +15,7 @@ class TestWbuf < Testcase
15
15
  end
16
16
 
17
17
  def test_wbuf
18
+ skip "sendfile not Linux-compatible" if RUBY_PLATFORM !~ /linux/
18
19
  buf = "*" * (16384 * 2)
19
20
  nr = 1000
20
21
  [ true, false ].each do |persist|
@@ -59,6 +60,7 @@ class TestWbuf < Testcase
59
60
 
60
61
  def test_wbuf_blocked
61
62
  a, b = socketpair
63
+ skip "sendfile not Linux-compatible" if RUBY_PLATFORM !~ /linux/
62
64
  buf = "." * 4096
63
65
  4.times do
64
66
  begin
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yahns
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - yahns hackers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-15 00:00:00.000000000 Z
11
+ date: 2014-05-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: kgio