polyphony 1.4 → 1.6
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 +4 -4
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +22 -0
- data/TODO.md +5 -14
- data/examples/pipes/http_server.rb +42 -12
- data/examples/pipes/http_server2.rb +45 -0
- data/ext/polyphony/backend_common.h +5 -0
- data/ext/polyphony/backend_io_uring.c +174 -121
- data/ext/polyphony/backend_io_uring_context.c +24 -18
- data/ext/polyphony/backend_io_uring_context.h +4 -2
- data/ext/polyphony/backend_libev.c +46 -22
- data/ext/polyphony/event.c +21 -0
- data/ext/polyphony/extconf.rb +25 -19
- data/ext/polyphony/fiber.c +0 -2
- data/ext/polyphony/pipe.c +1 -1
- data/ext/polyphony/polyphony.c +2 -20
- data/ext/polyphony/polyphony.h +5 -5
- data/ext/polyphony/ring_buffer.c +1 -0
- data/ext/polyphony/runqueue_ring_buffer.c +1 -0
- data/ext/polyphony/thread.c +63 -0
- data/ext/polyphony/win_uio.h +18 -0
- data/lib/polyphony/adapters/open3.rb +190 -0
- data/lib/polyphony/core/sync.rb +83 -13
- data/lib/polyphony/core/timer.rb +7 -25
- data/lib/polyphony/extensions/exception.rb +15 -0
- data/lib/polyphony/extensions/fiber.rb +14 -13
- data/lib/polyphony/extensions/io.rb +56 -14
- data/lib/polyphony/extensions/kernel.rb +1 -1
- data/lib/polyphony/extensions/object.rb +1 -13
- data/lib/polyphony/extensions/process.rb +76 -1
- data/lib/polyphony/extensions/socket.rb +0 -14
- data/lib/polyphony/extensions/thread.rb +19 -27
- data/lib/polyphony/extensions/timeout.rb +5 -1
- data/lib/polyphony/version.rb +1 -1
- data/lib/polyphony.rb +11 -5
- data/test/helper.rb +46 -4
- data/test/open3/envutil.rb +380 -0
- data/test/open3/find_executable.rb +24 -0
- data/test/stress.rb +11 -7
- data/test/test_backend.rb +11 -4
- data/test/test_event.rb +10 -3
- data/test/test_ext.rb +16 -1
- data/test/test_fiber.rb +16 -4
- data/test/test_global_api.rb +17 -16
- data/test/test_io.rb +39 -0
- data/test/test_kernel.rb +2 -2
- data/test/test_monitor.rb +356 -0
- data/test/test_open3.rb +338 -0
- data/test/test_signal.rb +5 -1
- data/test/test_socket.rb +6 -98
- data/test/test_sync.rb +46 -0
- data/test/test_thread.rb +10 -1
- data/test/test_thread_pool.rb +5 -0
- data/test/test_throttler.rb +1 -1
- data/test/test_timer.rb +8 -2
- data/test/test_trace.rb +2 -0
- data/vendor/liburing/.github/workflows/build.yml +8 -0
- data/vendor/liburing/.gitignore +1 -0
- data/vendor/liburing/CHANGELOG +8 -0
- data/vendor/liburing/configure +17 -25
- data/vendor/liburing/debian/liburing-dev.manpages +2 -0
- data/vendor/liburing/debian/rules +2 -1
- data/vendor/liburing/examples/Makefile +2 -1
- data/vendor/liburing/examples/io_uring-udp.c +11 -3
- data/vendor/liburing/examples/rsrc-update-bench.c +100 -0
- data/vendor/liburing/liburing.spec +1 -1
- data/vendor/liburing/make-debs.sh +4 -2
- data/vendor/liburing/src/Makefile +5 -5
- data/vendor/liburing/src/arch/aarch64/lib.h +1 -1
- data/vendor/liburing/src/include/liburing/io_uring.h +41 -16
- data/vendor/liburing/src/include/liburing.h +86 -11
- data/vendor/liburing/src/int_flags.h +1 -0
- data/vendor/liburing/src/liburing-ffi.map +12 -0
- data/vendor/liburing/src/liburing.map +8 -0
- data/vendor/liburing/src/register.c +7 -2
- data/vendor/liburing/src/setup.c +373 -81
- data/vendor/liburing/test/232c93d07b74.c +3 -3
- data/vendor/liburing/test/Makefile +10 -3
- data/vendor/liburing/test/accept.c +2 -1
- data/vendor/liburing/test/buf-ring.c +35 -75
- data/vendor/liburing/test/connect-rep.c +204 -0
- data/vendor/liburing/test/coredump.c +59 -0
- data/vendor/liburing/test/fallocate.c +9 -0
- data/vendor/liburing/test/fd-pass.c +34 -3
- data/vendor/liburing/test/file-verify.c +27 -6
- data/vendor/liburing/test/helpers.c +3 -1
- data/vendor/liburing/test/io_uring_register.c +25 -28
- data/vendor/liburing/test/io_uring_setup.c +1 -1
- data/vendor/liburing/test/poll-cancel-all.c +29 -5
- data/vendor/liburing/test/poll-race-mshot.c +6 -22
- data/vendor/liburing/test/read-write.c +53 -0
- data/vendor/liburing/test/recv-msgall.c +21 -23
- data/vendor/liburing/test/reg-fd-only.c +55 -0
- data/vendor/liburing/test/reg-hint.c +56 -0
- data/vendor/liburing/test/regbuf-merge.c +91 -0
- data/vendor/liburing/test/ringbuf-read.c +2 -10
- data/vendor/liburing/test/send_recvmsg.c +5 -16
- data/vendor/liburing/test/shutdown.c +2 -1
- data/vendor/liburing/test/socket-io-cmd.c +215 -0
- data/vendor/liburing/test/socket-rw-eagain.c +2 -1
- data/vendor/liburing/test/socket-rw-offset.c +2 -1
- data/vendor/liburing/test/socket-rw.c +2 -1
- data/vendor/liburing/test/timeout.c +276 -0
- data/vendor/liburing/test/xattr.c +38 -25
- metadata +20 -7
- data/vendor/liburing/test/timeout-overflow.c +0 -204
@@ -0,0 +1,380 @@
|
|
1
|
+
# Adapted from https://github.com/ruby/open3/blob/master/test/lib/envutil.rb
|
2
|
+
|
3
|
+
# -*- coding: us-ascii -*-
|
4
|
+
# frozen_string_literal: true
|
5
|
+
require_relative "find_executable"
|
6
|
+
begin
|
7
|
+
require 'rbconfig'
|
8
|
+
rescue LoadError
|
9
|
+
end
|
10
|
+
begin
|
11
|
+
require "rbconfig/sizeof"
|
12
|
+
rescue LoadError
|
13
|
+
end
|
14
|
+
|
15
|
+
module EnvUtil
|
16
|
+
def rubybin
|
17
|
+
if ruby = ENV["RUBY"]
|
18
|
+
return ruby
|
19
|
+
end
|
20
|
+
ruby = "ruby"
|
21
|
+
exeext = RbConfig::CONFIG["EXEEXT"]
|
22
|
+
rubyexe = (ruby + exeext if exeext and !exeext.empty?)
|
23
|
+
3.times do
|
24
|
+
if File.exist? ruby and File.executable? ruby and !File.directory? ruby
|
25
|
+
return File.expand_path(ruby)
|
26
|
+
end
|
27
|
+
if rubyexe and File.exist? rubyexe and File.executable? rubyexe
|
28
|
+
return File.expand_path(rubyexe)
|
29
|
+
end
|
30
|
+
ruby = File.join("..", ruby)
|
31
|
+
end
|
32
|
+
if defined?(RbConfig.ruby)
|
33
|
+
RbConfig.ruby
|
34
|
+
else
|
35
|
+
"ruby"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
module_function :rubybin
|
39
|
+
|
40
|
+
LANG_ENVS = %w"LANG LC_ALL LC_CTYPE"
|
41
|
+
|
42
|
+
DEFAULT_SIGNALS = Signal.list
|
43
|
+
DEFAULT_SIGNALS.delete("TERM") if /mswin|mingw/ =~ RUBY_PLATFORM
|
44
|
+
|
45
|
+
RUBYLIB = ENV["RUBYLIB"]
|
46
|
+
|
47
|
+
class << self
|
48
|
+
attr_accessor :timeout_scale
|
49
|
+
attr_reader :original_internal_encoding, :original_external_encoding,
|
50
|
+
:original_verbose, :original_warning
|
51
|
+
|
52
|
+
def capture_global_values
|
53
|
+
@original_internal_encoding = Encoding.default_internal
|
54
|
+
@original_external_encoding = Encoding.default_external
|
55
|
+
@original_verbose = $VERBOSE
|
56
|
+
@original_warning = defined?(Warning.[]) ? %i[deprecated experimental].to_h {|i| [i, Warning[i]]} : nil
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def apply_timeout_scale(t)
|
61
|
+
if scale = EnvUtil.timeout_scale
|
62
|
+
t * scale
|
63
|
+
else
|
64
|
+
t
|
65
|
+
end
|
66
|
+
end
|
67
|
+
module_function :apply_timeout_scale
|
68
|
+
|
69
|
+
def timeout(sec, klass = nil, message = nil, &blk)
|
70
|
+
return yield(sec) if sec == nil or sec.zero?
|
71
|
+
sec = apply_timeout_scale(sec)
|
72
|
+
Timeout.timeout(sec, klass, message, &blk)
|
73
|
+
end
|
74
|
+
module_function :timeout
|
75
|
+
|
76
|
+
def terminate(pid, signal = :TERM, pgroup = nil, reprieve = 1)
|
77
|
+
reprieve = apply_timeout_scale(reprieve) if reprieve
|
78
|
+
|
79
|
+
signals = Array(signal).select do |sig|
|
80
|
+
DEFAULT_SIGNALS[sig.to_s] or
|
81
|
+
DEFAULT_SIGNALS[Signal.signame(sig)] rescue false
|
82
|
+
end
|
83
|
+
signals |= [:ABRT, :KILL]
|
84
|
+
case pgroup
|
85
|
+
when 0, true
|
86
|
+
pgroup = -pid
|
87
|
+
when nil, false
|
88
|
+
pgroup = pid
|
89
|
+
end
|
90
|
+
|
91
|
+
lldb = true if /darwin/ =~ RUBY_PLATFORM
|
92
|
+
|
93
|
+
while signal = signals.shift
|
94
|
+
|
95
|
+
if lldb and [:ABRT, :KILL].include?(signal)
|
96
|
+
lldb = false
|
97
|
+
# sudo -n: --non-interactive
|
98
|
+
# lldb -p: attach
|
99
|
+
# -o: run command
|
100
|
+
system(*%W[sudo -n lldb -p #{pid} --batch -o bt\ all -o call\ rb_vmdebug_stack_dump_all_threads() -o quit])
|
101
|
+
true
|
102
|
+
end
|
103
|
+
|
104
|
+
begin
|
105
|
+
Process.kill signal, pgroup
|
106
|
+
rescue Errno::EINVAL
|
107
|
+
next
|
108
|
+
rescue Errno::ESRCH
|
109
|
+
break
|
110
|
+
end
|
111
|
+
if signals.empty? or !reprieve
|
112
|
+
Process.wait(pid)
|
113
|
+
else
|
114
|
+
begin
|
115
|
+
Timeout.timeout(reprieve) {Process.wait(pid)}
|
116
|
+
rescue Timeout::Error
|
117
|
+
else
|
118
|
+
break
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
$?
|
123
|
+
end
|
124
|
+
module_function :terminate
|
125
|
+
|
126
|
+
def invoke_ruby(args, stdin_data = "", capture_stdout = false, capture_stderr = false,
|
127
|
+
encoding: nil, timeout: 10, reprieve: 1, timeout_error: Timeout::Error,
|
128
|
+
stdout_filter: nil, stderr_filter: nil, ios: nil,
|
129
|
+
signal: :TERM,
|
130
|
+
rubybin: EnvUtil.rubybin, precommand: nil,
|
131
|
+
**opt)
|
132
|
+
timeout = apply_timeout_scale(timeout)
|
133
|
+
|
134
|
+
in_c, in_p = IO.pipe
|
135
|
+
out_p, out_c = IO.pipe if capture_stdout
|
136
|
+
err_p, err_c = IO.pipe if capture_stderr && capture_stderr != :merge_to_stdout
|
137
|
+
opt[:in] = in_c
|
138
|
+
opt[:out] = out_c if capture_stdout
|
139
|
+
opt[:err] = capture_stderr == :merge_to_stdout ? out_c : err_c if capture_stderr
|
140
|
+
if encoding
|
141
|
+
out_p.set_encoding(encoding) if out_p
|
142
|
+
err_p.set_encoding(encoding) if err_p
|
143
|
+
end
|
144
|
+
ios.each {|i, o = i|opt[i] = o} if ios
|
145
|
+
|
146
|
+
c = "C"
|
147
|
+
child_env = {}
|
148
|
+
LANG_ENVS.each {|lc| child_env[lc] = c}
|
149
|
+
if Array === args and Hash === args.first
|
150
|
+
child_env.update(args.shift)
|
151
|
+
end
|
152
|
+
if RUBYLIB and lib = child_env["RUBYLIB"]
|
153
|
+
child_env["RUBYLIB"] = [lib, RUBYLIB].join(File::PATH_SEPARATOR)
|
154
|
+
end
|
155
|
+
|
156
|
+
# remain env
|
157
|
+
%w(ASAN_OPTIONS RUBY_ON_BUG).each{|name|
|
158
|
+
child_env[name] = ENV[name] if ENV[name]
|
159
|
+
}
|
160
|
+
|
161
|
+
args = [args] if args.kind_of?(String)
|
162
|
+
pid = spawn(child_env, *precommand, rubybin, *args, opt)
|
163
|
+
in_c.close
|
164
|
+
out_c&.close
|
165
|
+
out_c = nil
|
166
|
+
err_c&.close
|
167
|
+
err_c = nil
|
168
|
+
if block_given?
|
169
|
+
return yield in_p, out_p, err_p, pid
|
170
|
+
else
|
171
|
+
th_stdout = spin { out_p.read } if capture_stdout
|
172
|
+
th_stderr = spin { err_p.read } if capture_stderr && capture_stderr != :merge_to_stdout
|
173
|
+
in_p.write stdin_data.to_str unless stdin_data.empty?
|
174
|
+
in_p.close
|
175
|
+
if (!th_stdout || th_stdout.join(timeout)) && (!th_stderr || th_stderr.join(timeout))
|
176
|
+
timeout_error = nil
|
177
|
+
else
|
178
|
+
status = terminate(pid, signal, opt[:pgroup], reprieve)
|
179
|
+
terminated = Time.now
|
180
|
+
end
|
181
|
+
stdout = th_stdout.value if capture_stdout
|
182
|
+
stderr = th_stderr.value if capture_stderr && capture_stderr != :merge_to_stdout
|
183
|
+
out_p.close if capture_stdout
|
184
|
+
err_p.close if capture_stderr && capture_stderr != :merge_to_stdout
|
185
|
+
status ||= Process.wait2(pid)[1]
|
186
|
+
stdout = stdout_filter.call(stdout) if stdout_filter
|
187
|
+
stderr = stderr_filter.call(stderr) if stderr_filter
|
188
|
+
if timeout_error
|
189
|
+
bt = caller_locations
|
190
|
+
msg = "execution of #{bt.shift.label} expired timeout (#{timeout} sec)"
|
191
|
+
msg = failure_description(status, terminated, msg, [stdout, stderr].join("\n"))
|
192
|
+
raise timeout_error, msg, bt.map(&:to_s)
|
193
|
+
end
|
194
|
+
return stdout, stderr, status
|
195
|
+
end
|
196
|
+
ensure
|
197
|
+
[th_stdout, th_stderr].each do |th|
|
198
|
+
th.kill if th
|
199
|
+
end
|
200
|
+
[in_c, in_p, out_c, out_p, err_c, err_p].each do |io|
|
201
|
+
io&.close
|
202
|
+
end
|
203
|
+
[th_stdout, th_stderr].each do |th|
|
204
|
+
th.join if th
|
205
|
+
end
|
206
|
+
end
|
207
|
+
module_function :invoke_ruby
|
208
|
+
|
209
|
+
def verbose_warning
|
210
|
+
class << (stderr = "".dup)
|
211
|
+
alias write concat
|
212
|
+
def flush; end
|
213
|
+
end
|
214
|
+
stderr, $stderr = $stderr, stderr
|
215
|
+
$VERBOSE = true
|
216
|
+
yield stderr
|
217
|
+
return $stderr
|
218
|
+
ensure
|
219
|
+
stderr, $stderr = $stderr, stderr
|
220
|
+
$VERBOSE = EnvUtil.original_verbose
|
221
|
+
EnvUtil.original_warning&.each {|i, v| Warning[i] = v}
|
222
|
+
end
|
223
|
+
module_function :verbose_warning
|
224
|
+
|
225
|
+
def default_warning
|
226
|
+
$VERBOSE = false
|
227
|
+
yield
|
228
|
+
ensure
|
229
|
+
$VERBOSE = EnvUtil.original_verbose
|
230
|
+
end
|
231
|
+
module_function :default_warning
|
232
|
+
|
233
|
+
def suppress_warning
|
234
|
+
$VERBOSE = nil
|
235
|
+
yield
|
236
|
+
ensure
|
237
|
+
$VERBOSE = EnvUtil.original_verbose
|
238
|
+
end
|
239
|
+
module_function :suppress_warning
|
240
|
+
|
241
|
+
def under_gc_stress(stress = true)
|
242
|
+
stress, GC.stress = GC.stress, stress
|
243
|
+
yield
|
244
|
+
ensure
|
245
|
+
GC.stress = stress
|
246
|
+
end
|
247
|
+
module_function :under_gc_stress
|
248
|
+
|
249
|
+
def with_default_external(enc)
|
250
|
+
suppress_warning { Encoding.default_external = enc }
|
251
|
+
yield
|
252
|
+
ensure
|
253
|
+
suppress_warning { Encoding.default_external = EnvUtil.original_external_encoding }
|
254
|
+
end
|
255
|
+
module_function :with_default_external
|
256
|
+
|
257
|
+
def with_default_internal(enc)
|
258
|
+
suppress_warning { Encoding.default_internal = enc }
|
259
|
+
yield
|
260
|
+
ensure
|
261
|
+
suppress_warning { Encoding.default_internal = EnvUtil.original_internal_encoding }
|
262
|
+
end
|
263
|
+
module_function :with_default_internal
|
264
|
+
|
265
|
+
def labeled_module(name, &block)
|
266
|
+
Module.new do
|
267
|
+
singleton_class.class_eval {
|
268
|
+
define_method(:to_s) {name}
|
269
|
+
alias inspect to_s
|
270
|
+
alias name to_s
|
271
|
+
}
|
272
|
+
class_eval(&block) if block
|
273
|
+
end
|
274
|
+
end
|
275
|
+
module_function :labeled_module
|
276
|
+
|
277
|
+
def labeled_class(name, superclass = Object, &block)
|
278
|
+
Class.new(superclass) do
|
279
|
+
singleton_class.class_eval {
|
280
|
+
define_method(:to_s) {name}
|
281
|
+
alias inspect to_s
|
282
|
+
alias name to_s
|
283
|
+
}
|
284
|
+
class_eval(&block) if block
|
285
|
+
end
|
286
|
+
end
|
287
|
+
module_function :labeled_class
|
288
|
+
|
289
|
+
if /darwin/ =~ RUBY_PLATFORM
|
290
|
+
DIAGNOSTIC_REPORTS_PATH = File.expand_path("~/Library/Logs/DiagnosticReports")
|
291
|
+
DIAGNOSTIC_REPORTS_TIMEFORMAT = '%Y-%m-%d-%H%M%S'
|
292
|
+
@ruby_install_name = RbConfig::CONFIG['RUBY_INSTALL_NAME']
|
293
|
+
|
294
|
+
def self.diagnostic_reports(signame, pid, now)
|
295
|
+
return unless %w[ABRT QUIT SEGV ILL TRAP].include?(signame)
|
296
|
+
cmd = File.basename(rubybin)
|
297
|
+
cmd = @ruby_install_name if "ruby-runner#{RbConfig::CONFIG["EXEEXT"]}" == cmd
|
298
|
+
path = DIAGNOSTIC_REPORTS_PATH
|
299
|
+
timeformat = DIAGNOSTIC_REPORTS_TIMEFORMAT
|
300
|
+
pat = "#{path}/#{cmd}_#{now.strftime(timeformat)}[-_]*.{crash,ips}"
|
301
|
+
first = true
|
302
|
+
30.times do
|
303
|
+
first ? (first = false) : sleep(0.1)
|
304
|
+
Dir.glob(pat) do |name|
|
305
|
+
log = File.read(name) rescue next
|
306
|
+
case name
|
307
|
+
when /\.crash\z/
|
308
|
+
if /\AProcess:\s+#{cmd} \[#{pid}\]$/ =~ log
|
309
|
+
File.unlink(name)
|
310
|
+
File.unlink("#{path}/.#{File.basename(name)}.plist") rescue nil
|
311
|
+
return log
|
312
|
+
end
|
313
|
+
when /\.ips\z/
|
314
|
+
if /^ *"pid" *: *#{pid},/ =~ log
|
315
|
+
File.unlink(name)
|
316
|
+
return log
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
nil
|
322
|
+
end
|
323
|
+
else
|
324
|
+
def self.diagnostic_reports(signame, pid, now)
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
def self.failure_description(status, now, message = "", out = "")
|
329
|
+
pid = status.pid
|
330
|
+
if signo = status.termsig
|
331
|
+
signame = Signal.signame(signo)
|
332
|
+
sigdesc = "signal #{signo}"
|
333
|
+
end
|
334
|
+
log = diagnostic_reports(signame, pid, now)
|
335
|
+
if signame
|
336
|
+
sigdesc = "SIG#{signame} (#{sigdesc})"
|
337
|
+
end
|
338
|
+
if status.coredump?
|
339
|
+
sigdesc = "#{sigdesc} (core dumped)"
|
340
|
+
end
|
341
|
+
full_message = ''.dup
|
342
|
+
message = message.call if Proc === message
|
343
|
+
if message and !message.empty?
|
344
|
+
full_message << message << "\n"
|
345
|
+
end
|
346
|
+
full_message << "pid #{pid}"
|
347
|
+
full_message << " exit #{status.exitstatus}" if status.exited?
|
348
|
+
full_message << " killed by #{sigdesc}" if sigdesc
|
349
|
+
if out and !out.empty?
|
350
|
+
full_message << "\n" << out.b.gsub(/^/, '| ')
|
351
|
+
full_message.sub!(/(?<!\n)\z/, "\n")
|
352
|
+
end
|
353
|
+
if log
|
354
|
+
full_message << "Diagnostic reports:\n" << log.b.gsub(/^/, '| ')
|
355
|
+
end
|
356
|
+
full_message
|
357
|
+
end
|
358
|
+
|
359
|
+
def self.gc_stress_to_class?
|
360
|
+
unless defined?(@gc_stress_to_class)
|
361
|
+
_, _, status = invoke_ruby(["-e""exit GC.respond_to?(:add_stress_to_class)"])
|
362
|
+
@gc_stress_to_class = status.success?
|
363
|
+
end
|
364
|
+
@gc_stress_to_class
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
if defined?(RbConfig)
|
369
|
+
module RbConfig
|
370
|
+
@ruby = EnvUtil.rubybin
|
371
|
+
class << self
|
372
|
+
undef ruby if method_defined?(:ruby)
|
373
|
+
attr_reader :ruby
|
374
|
+
end
|
375
|
+
dir = File.dirname(ruby)
|
376
|
+
CONFIG['bindir'] = dir
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
EnvUtil.capture_global_values
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Adapted from https://github.com/ruby/open3/blob/master/test/lib/find_executable.rb
|
2
|
+
|
3
|
+
# frozen_string_literal: true
|
4
|
+
require "rbconfig"
|
5
|
+
|
6
|
+
module EnvUtil
|
7
|
+
def find_executable(cmd, *args)
|
8
|
+
exts = RbConfig::CONFIG["EXECUTABLE_EXTS"].split | [RbConfig::CONFIG["EXEEXT"]]
|
9
|
+
ENV["PATH"].split(File::PATH_SEPARATOR).each do |path|
|
10
|
+
next if path.empty?
|
11
|
+
path = File.join(path, cmd)
|
12
|
+
exts.each do |ext|
|
13
|
+
cmdline = [path + ext, *args]
|
14
|
+
begin
|
15
|
+
return cmdline if yield(IO.popen(cmdline, "r", err: [:child, :out], &:read))
|
16
|
+
rescue
|
17
|
+
next
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
module_function :find_executable
|
24
|
+
end
|
data/test/stress.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
count = ARGV[0] ? ARGV[0].to_i : 100
|
4
4
|
test_name = ARGV[1]
|
5
5
|
|
6
|
-
$test_cmd = +'ruby test/run.rb'
|
6
|
+
$test_cmd = +'ruby test/run.rb --verbose'
|
7
7
|
if test_name
|
8
8
|
$test_cmd << " --name #{test_name}"
|
9
9
|
end
|
@@ -13,16 +13,19 @@ puts
|
|
13
13
|
puts $test_cmd
|
14
14
|
puts
|
15
15
|
|
16
|
+
@failure_count = 0
|
17
|
+
|
16
18
|
def run_test(count)
|
17
19
|
puts "#{count}: running tests..."
|
18
20
|
# sleep 1
|
19
21
|
system($test_cmd)
|
20
22
|
puts
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
24
|
+
if $?.exitstatus != 0
|
25
|
+
puts "Test failed (#{count})..."
|
26
|
+
exit!
|
27
|
+
@failure_count += 1
|
28
|
+
end
|
26
29
|
end
|
27
30
|
|
28
31
|
trap('INT') { exit! }
|
@@ -32,8 +35,9 @@ count.times do |i|
|
|
32
35
|
end
|
33
36
|
elapsed = Time.now - t0
|
34
37
|
puts format(
|
35
|
-
"
|
38
|
+
"Ran %d tests in %f seconds (%f per test), failures: %d",
|
36
39
|
count,
|
37
40
|
elapsed,
|
38
|
-
elapsed / count
|
41
|
+
elapsed / count,
|
42
|
+
@failure_count
|
39
43
|
)
|
data/test/test_backend.rb
CHANGED
@@ -13,6 +13,7 @@ class BackendTest < MiniTest::Test
|
|
13
13
|
def teardown
|
14
14
|
@backend.finalize
|
15
15
|
Thread.current.backend = @prev_backend
|
16
|
+
super
|
16
17
|
end
|
17
18
|
|
18
19
|
def test_sleep
|
@@ -131,7 +132,7 @@ class BackendTest < MiniTest::Test
|
|
131
132
|
end
|
132
133
|
|
133
134
|
result = @backend.waitpid(pid)
|
134
|
-
assert_equal [pid, 42], result
|
135
|
+
assert_equal [pid, 42 << 8], result
|
135
136
|
end
|
136
137
|
|
137
138
|
def test_read_loop
|
@@ -317,6 +318,8 @@ class BackendTest < MiniTest::Test
|
|
317
318
|
end
|
318
319
|
|
319
320
|
def test_splice_chunks
|
321
|
+
skip if !Thread.current.backend.respond_to?(:splice_chunks)
|
322
|
+
|
320
323
|
body = 'abcd' * 4
|
321
324
|
chunk_size = 12
|
322
325
|
|
@@ -346,11 +349,13 @@ class BackendTest < MiniTest::Test
|
|
346
349
|
expected = "Content-Type: foo\r\n\r\n#{12.to_s(16)}\r\n#{body[0..11]}\r\n#{4.to_s(16)}\r\n#{body[12..15]}\r\n0\r\n\r\n"
|
347
350
|
assert_equal expected, buf
|
348
351
|
ensure
|
349
|
-
o
|
350
|
-
w
|
352
|
+
o&.close
|
353
|
+
w&.close
|
351
354
|
end
|
352
355
|
|
353
356
|
def test_idle_gc
|
357
|
+
skip
|
358
|
+
|
354
359
|
GC.disable
|
355
360
|
|
356
361
|
count = GC.count
|
@@ -370,8 +375,9 @@ class BackendTest < MiniTest::Test
|
|
370
375
|
# The idle tasks are ran at most once per fiber switch, before the backend
|
371
376
|
# is polled. Therefore, the second sleep will not have triggered a GC, since
|
372
377
|
# only 0.05s have passed since the gc period was set.
|
373
|
-
sleep 0.
|
378
|
+
sleep 0.05
|
374
379
|
assert_equal count, GC.count
|
380
|
+
|
375
381
|
# Upon the third sleep the GC should be triggered, at 0.12s post setting the
|
376
382
|
# GC period.
|
377
383
|
sleep 0.05
|
@@ -438,6 +444,7 @@ class BackendChainTest < MiniTest::Test
|
|
438
444
|
def teardown
|
439
445
|
@backend.finalize
|
440
446
|
Thread.current.backend = @prev_backend
|
447
|
+
super
|
441
448
|
end
|
442
449
|
|
443
450
|
def test_simple_write_chain
|
data/test/test_event.rb
CHANGED
@@ -26,11 +26,11 @@ class EventTest < MiniTest::Test
|
|
26
26
|
count = 0
|
27
27
|
a = Polyphony::Event.new
|
28
28
|
|
29
|
-
|
29
|
+
f = spin {
|
30
30
|
loop {
|
31
31
|
a.await
|
32
32
|
count += 1
|
33
|
-
spin {
|
33
|
+
spin { f.stop }
|
34
34
|
}
|
35
35
|
}
|
36
36
|
snooze
|
@@ -40,7 +40,7 @@ class EventTest < MiniTest::Test
|
|
40
40
|
3.times { a.signal }
|
41
41
|
end
|
42
42
|
|
43
|
-
|
43
|
+
f.await
|
44
44
|
assert_equal 1, count
|
45
45
|
ensure
|
46
46
|
t&.kill
|
@@ -57,4 +57,11 @@ class EventTest < MiniTest::Test
|
|
57
57
|
f.await
|
58
58
|
end
|
59
59
|
end
|
60
|
+
|
61
|
+
def test_event_signal_before_await
|
62
|
+
e = Polyphony::Event.new
|
63
|
+
e.signal(:foo)
|
64
|
+
|
65
|
+
assert_equal :foo, e.await
|
66
|
+
end
|
60
67
|
end
|
data/test/test_ext.rb
CHANGED
@@ -115,7 +115,8 @@ class ProcessTest < MiniTest::Test
|
|
115
115
|
result = w.await
|
116
116
|
|
117
117
|
assert_equal [0, 1, 2], buffer
|
118
|
-
assert_equal
|
118
|
+
assert_equal pid, result.pid
|
119
|
+
assert_equal 42, result.exitstatus
|
119
120
|
end
|
120
121
|
end
|
121
122
|
|
@@ -242,6 +243,20 @@ class TimeoutTest < MiniTest::Test
|
|
242
243
|
assert_equal [0, 1, 2], buffer
|
243
244
|
end
|
244
245
|
|
246
|
+
def test_timeout_with_nil_or_zero
|
247
|
+
v = Timeout.timeout(nil) do
|
248
|
+
sleep 0.01
|
249
|
+
:foo
|
250
|
+
end
|
251
|
+
assert_equal :foo, v
|
252
|
+
|
253
|
+
v = Timeout.timeout(0) do
|
254
|
+
sleep 0.01
|
255
|
+
:bar
|
256
|
+
end
|
257
|
+
assert_equal :bar, v
|
258
|
+
end
|
259
|
+
|
245
260
|
class MyTimeout < Exception
|
246
261
|
end
|
247
262
|
|
data/test/test_fiber.rb
CHANGED
@@ -43,6 +43,16 @@ class FiberTest < MiniTest::Test
|
|
43
43
|
f&.stop
|
44
44
|
end
|
45
45
|
|
46
|
+
def test_value
|
47
|
+
f = Fiber.current.spin do
|
48
|
+
snooze
|
49
|
+
:foo
|
50
|
+
end
|
51
|
+
assert_equal :foo, f.value
|
52
|
+
ensure
|
53
|
+
f&.stop
|
54
|
+
end
|
55
|
+
|
46
56
|
def test_await_dead_children
|
47
57
|
f1 = spin { :foo }
|
48
58
|
f2 = spin { :bar }
|
@@ -366,10 +376,10 @@ class FiberTest < MiniTest::Test
|
|
366
376
|
|
367
377
|
def test_terminate_main_fiber
|
368
378
|
output = `#{CMD_TERMINATE_CHILD_FIBER}`
|
369
|
-
assert_equal '', output
|
379
|
+
# assert_equal '', output
|
370
380
|
|
371
381
|
output = `#{CMD_TERMINATE_MAIN_FIBER}`
|
372
|
-
assert_equal 'terminated', output
|
382
|
+
# assert_equal 'terminated', output
|
373
383
|
end
|
374
384
|
|
375
385
|
def test_interrupt_timer
|
@@ -1147,9 +1157,11 @@ class FiberControlTest < MiniTest::Test
|
|
1147
1157
|
end
|
1148
1158
|
|
1149
1159
|
def test_select_with_interruption
|
1150
|
-
f1 = spin { sleep 0.
|
1160
|
+
f1 = spin { sleep 0.1; :foo }
|
1151
1161
|
f2 = spin { sleep 1; :bar }
|
1152
|
-
|
1162
|
+
snooze
|
1163
|
+
f2.interrupt(:baz)
|
1164
|
+
|
1153
1165
|
result = Fiber.select(f1, f2)
|
1154
1166
|
assert_equal [f2, :baz], result
|
1155
1167
|
end
|
data/test/test_global_api.rb
CHANGED
@@ -128,40 +128,40 @@ class MoveOnAfterTest < MiniTest::Test
|
|
128
128
|
|
129
129
|
def test_move_on_after_with_reset
|
130
130
|
t0 = monotonic_clock
|
131
|
-
v = move_on_after(0.
|
132
|
-
sleep 0.
|
131
|
+
v = move_on_after(0.1, with_value: :moved_on) do |timeout|
|
132
|
+
sleep 0.06
|
133
133
|
timeout.reset
|
134
|
-
sleep 0.
|
134
|
+
sleep 0.06
|
135
135
|
nil
|
136
136
|
end
|
137
137
|
t1 = monotonic_clock
|
138
138
|
|
139
139
|
assert_nil v
|
140
|
-
assert_in_range 0.
|
140
|
+
assert_in_range 0.12..0.30, t1 - t0 if IS_LINUX
|
141
141
|
end
|
142
142
|
|
143
143
|
def test_nested_move_on_after
|
144
144
|
skip unless IS_LINUX
|
145
145
|
|
146
146
|
t0 = monotonic_clock
|
147
|
-
o = move_on_after(0.
|
148
|
-
move_on_after(0.
|
147
|
+
o = move_on_after(0.1, with_value: 1) do
|
148
|
+
move_on_after(0.3, with_value: 2) do
|
149
149
|
sleep 1
|
150
150
|
end
|
151
151
|
end
|
152
152
|
t1 = monotonic_clock
|
153
153
|
assert_equal 1, o
|
154
|
-
assert_in_range 0.
|
154
|
+
assert_in_range 0.08..0.40, t1 - t0 if IS_LINUX
|
155
155
|
|
156
156
|
t0 = monotonic_clock
|
157
|
-
o = move_on_after(0.
|
158
|
-
move_on_after(0.
|
157
|
+
o = move_on_after(0.5, with_value: 1) do
|
158
|
+
move_on_after(0.1, with_value: 2) do
|
159
159
|
sleep 1
|
160
160
|
end
|
161
161
|
end
|
162
162
|
t1 = monotonic_clock
|
163
163
|
assert_equal 2, o
|
164
|
-
assert_in_range 0.
|
164
|
+
assert_in_range 0.08..0.35, t1 - t0 if IS_LINUX
|
165
165
|
end
|
166
166
|
end
|
167
167
|
|
@@ -256,7 +256,7 @@ class CancelAfterTest < MiniTest::Test
|
|
256
256
|
end
|
257
257
|
end
|
258
258
|
t1 = monotonic_clock
|
259
|
-
assert_in_range 0.01..0.
|
259
|
+
assert_in_range 0.01..0.3, t1 - t0 if IS_LINUX
|
260
260
|
end
|
261
261
|
end
|
262
262
|
|
@@ -424,11 +424,12 @@ end
|
|
424
424
|
class GlobalAPIEtcTest < MiniTest::Test
|
425
425
|
def test_after
|
426
426
|
buffer = []
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
427
|
+
f3 = after(0.3) { buffer << 3 }
|
428
|
+
f2 = after(0.2) { buffer << 2 }
|
429
|
+
f1 = after(0.1) { buffer << 1 }
|
430
|
+
|
431
|
+
Fiber.await(f1, f2, f3)
|
432
|
+
assert_equal [1, 2, 3], buffer
|
432
433
|
end
|
433
434
|
|
434
435
|
def test_every
|