yahns 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
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