polyphony 0.76 → 0.77

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
  SHA256:
3
- metadata.gz: ad0cf72d2ae4acd2673cff5b4c5a2fa627cd2833e3131fa4504a2dc1e4cef6ea
4
- data.tar.gz: 69bb3e3bf2dfdffc3806c442a1d095b018f865f6c3d966ce7f5b4d789ba2bc9f
3
+ metadata.gz: 10f049946dc02d9cdd984cc8658687d2319e0fd85f6f2cce74aa0a887bc714cb
4
+ data.tar.gz: 5118859d4640aebeddb9186c43d58617e9b455a63ea97c1dc8283432db954fd1
5
5
  SHA512:
6
- metadata.gz: 306e7c56b5fa00a078e725e508bf99934f6ea12c738cb1e1c66130b20037ad4862f8aeefe0a53fec214387579955dfde9f74b92487653af8f501c80a6a16bb1b
7
- data.tar.gz: 3c807f56e677355ae3193db5a641caa660ab2f18cc2d7a5f8a4b38ef2b59463b0bf732cf4878cd7c93e19198f1eb330797b82f1ea69089f5ec055a3545e4d04c
6
+ metadata.gz: e107e21d6c42f9cd9e91521e288dfee37a6f0da4b7d8a8d311924bf88ccf732d2cc94de834dbbaa3c7a974e5bb84ce1d8d20efd68870c9f2dac9b73155d28558
7
+ data.tar.gz: 8e4f7005c9cbc46cd084bbe66a4e8f7145f6a4a3062ce027a70eee07c0e648f79289515591ef4b48010580b7125c403ab09e45417781346ebf6da4b2d528ec45
data/CHANGELOG.md CHANGED
@@ -1,6 +1,10 @@
1
+ ## 0.77 2022-02-07
2
+
3
+ - Fix behaviour of signal traps (#71)
4
+
1
5
  ## 0.76 2022-02-06
2
6
 
3
- - Comment out `Backend_close` API
7
+ - Comment out `Backend_close` API (#70)
4
8
 
5
9
  ## 0.75 2022-02-04
6
10
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- polyphony (0.76)
4
+ polyphony (0.77)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ pid = Process.pid
4
+ fork do
5
+ sleep 1
6
+ Process.kill('SIGINT', pid)
7
+ # sleep 10
8
+ # Process.kill(-9, pid)
9
+ end
10
+
11
+ require 'bundler/setup'
12
+ require 'polyphony'
13
+
14
+ Thread.backend.trace_proc = proc { |*e| STDOUT.orig_write("#{e.inspect}\n") }
15
+ trap('SIGINT') { STDOUT.orig_write("* recv SIGINT\n") }
16
+ # trap('SIGCHLD') { STDOUT.orig_write("* recv SIGCHLD\n") }
17
+ STDOUT.orig_write("* pre gets\n")
18
+ # STDIN.wait_readable
19
+ s = gets
20
+ p s
21
+ STDOUT.orig_write("* post gets\n")
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ pid = Process.pid
4
+ fork do
5
+ sleep 1
6
+ Process.kill('SIGINT', pid)
7
+ # sleep 10
8
+ # Process.kill(-9, pid)
9
+ end
10
+
11
+ trap('SIGINT') {}
12
+ p :before
13
+ result = IO.select([STDIN])
14
+ p :after
@@ -191,10 +191,14 @@ void io_uring_backend_poll(Backend_t *backend) {
191
191
  io_uring_submit(&backend->ring);
192
192
  }
193
193
 
194
+ wait_cqe:
194
195
  backend->base.currently_polling = 1;
195
196
  rb_thread_call_without_gvl(io_uring_backend_poll_without_gvl, (void *)&poll_ctx, RUBY_UBF_IO, 0);
196
197
  backend->base.currently_polling = 0;
197
- if (poll_ctx.result < 0) return;
198
+ if (poll_ctx.result < 0) {
199
+ if (poll_ctx.result == -EINTR && runqueue_empty_p(&backend->base.runqueue)) goto wait_cqe;
200
+ return;
201
+ }
198
202
 
199
203
  io_uring_backend_handle_completion(poll_ctx.cqe, backend);
200
204
  io_uring_cqe_seen(&backend->ring, poll_ctx.cqe);
@@ -169,9 +169,14 @@ inline VALUE Backend_poll(VALUE self, VALUE blocking) {
169
169
  backend->base.poll_count++;
170
170
 
171
171
  COND_TRACE(&backend->base, 2, SYM_fiber_event_poll_enter, rb_fiber_current());
172
+
173
+ ev_run:
172
174
  backend->base.currently_polling = 1;
175
+ errno = 0;
173
176
  ev_run(backend->ev_loop, blocking == Qtrue ? EVRUN_ONCE : EVRUN_NOWAIT);
174
177
  backend->base.currently_polling = 0;
178
+ if (errno == EINTR && runqueue_empty_p(&backend->base.runqueue)) goto ev_run;
179
+
175
180
  COND_TRACE(&backend->base, 2, SYM_fiber_event_poll_leave, rb_fiber_current());
176
181
 
177
182
  return self;
data/ext/test_eintr.c ADDED
@@ -0,0 +1,50 @@
1
+ #include <stdio.h>
2
+ #include <unistd.h>
3
+ #include <signal.h>
4
+ #include <poll.h>
5
+ #include "./liburing/liburing.h"
6
+
7
+ void sig_handler(int sig) {
8
+ printf("handle signal %d!\n", sig);
9
+ }
10
+
11
+ int main(int argc, char *argv[])
12
+ {
13
+ int pid = getpid();
14
+ int child_pid = fork();
15
+ if (!child_pid) {
16
+ sleep(1);
17
+ kill(pid, SIGINT);
18
+ sleep(1);
19
+ kill(pid, SIGINT);
20
+ }
21
+ else {
22
+ struct sigaction sa;
23
+
24
+ sa.sa_handler = sig_handler;
25
+ sa.sa_flags = SA_SIGINFO | SA_ONSTACK;//0;
26
+ sigemptyset(&sa.sa_mask);
27
+ sigaction(SIGINT, &sa, NULL);
28
+
29
+ printf("pid: %d\n", pid);
30
+
31
+ struct io_uring ring;
32
+ int ret = io_uring_queue_init(16, &ring, 0);
33
+ printf("io_uring_queue_init: %d\n", ret);
34
+
35
+ struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
36
+ io_uring_prep_poll_add(sqe, STDIN_FILENO, POLLIN);
37
+ ret = io_uring_submit(&ring);
38
+ printf("io_uring_submit: %d\n", ret);
39
+
40
+ struct io_uring_cqe *cqe;
41
+
42
+ wait_cqe:
43
+ ret = io_uring_wait_cqe(&ring, &cqe);
44
+ printf("io_uring_wait_cqe: %d\n", ret);
45
+ if (ret == -EINTR) goto wait_cqe;
46
+
47
+ printf("done\n");
48
+ return 0;
49
+ }
50
+ }
@@ -248,21 +248,27 @@ module Polyphony
248
248
  # also be scheduled with priority. This method is mainly used trapping
249
249
  # signals (see also the patched `Kernel#trap`)
250
250
  def schedule_priority_oob_fiber(&block)
251
- f = Fiber.new do
251
+ oob_fiber = Fiber.new do
252
252
  Fiber.current.setup_raw
253
253
  result = block.call
254
254
  rescue Exception => e
255
255
  Thread.current.schedule_and_wakeup(Thread.main.main_fiber, e)
256
256
  result = e
257
257
  ensure
258
- Thread.backend.trace(:fiber_terminate, f, result)
258
+ Thread.backend.trace(:fiber_terminate, Fiber.current, result)
259
259
  suspend
260
260
  end
261
- f.oob = true
261
+ prepare_oob_fiber(oob_fiber, block)
262
+ Thread.backend.trace(:fiber_create, oob_fiber)
263
+ oob_fiber.schedule_with_priority(nil)
264
+ end
265
+
266
+ def prepare_oob_fiber(fiber, block)
267
+ fiber.oob = true
268
+ fiber.tag = :oob
269
+ fiber.thread = Thread.current
262
270
  location = block.source_location
263
- f.set_caller(["#{location.join(':')}"])
264
- Thread.backend.trace(:fiber_create, f)
265
- Thread.current.schedule_and_wakeup(f, nil)
271
+ fiber.set_caller(["#{location.join(':')}"])
266
272
  end
267
273
  end
268
274
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polyphony
4
- VERSION = '0.76'
4
+ VERSION = '0.77'
5
5
  end
data/test/helper.rb CHANGED
@@ -46,10 +46,11 @@ class MiniTest::Test
46
46
  Thread.current.backend.finalize
47
47
  Thread.current.backend = Polyphony::Backend.new
48
48
  sleep 0.001
49
+ @__stamp = Time.now
49
50
  end
50
51
 
51
52
  def teardown
52
- # trace "* teardown #{self.name}"
53
+ # trace "* teardown #{self.name} (#{Time.now - @__stamp}s)"
53
54
  Fiber.current.shutdown_all_children
54
55
  if Fiber.current.children.size > 0
55
56
  puts "Children left after #{self.name}: #{Fiber.current.children.inspect}"
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 --name test_receive_cross_thread_exception'
6
+ $test_cmd = +'ruby test/run.rb --name test_cross_thread_send_receive'
7
7
  if test_name
8
8
  $test_cmd << " --name #{test_name}"
9
9
  end
data/test/test_fiber.rb CHANGED
@@ -923,18 +923,20 @@ class MailboxTest < MiniTest::Test
923
923
  def test_cross_thread_send_receive
924
924
  ping_receive_buffer = []
925
925
  pong_receive_buffer = []
926
+ master = Fiber.current
926
927
 
927
928
  pong = Thread.new do
928
- sleep 0.05
929
- loop do
929
+ master << :pong_ready
930
+ 3.times do
930
931
  peer, data = receive
931
932
  pong_receive_buffer << data
932
933
  peer << 'pong'
933
934
  end
934
935
  end
935
936
 
937
+ assert_equal :pong_ready, receive
938
+
936
939
  ping = Thread.new do
937
- sleep 0.05
938
940
  3.times do
939
941
  pong << [Fiber.current, 'ping']
940
942
  data = receive
@@ -943,7 +945,7 @@ class MailboxTest < MiniTest::Test
943
945
  end
944
946
 
945
947
  ping.join
946
- pong.kill
948
+ pong.join
947
949
  ping = pong = nil
948
950
 
949
951
  assert_equal %w{pong pong pong}, ping_receive_buffer
data/test/test_signal.rb CHANGED
@@ -3,6 +3,63 @@
3
3
  require_relative 'helper'
4
4
 
5
5
  class SignalTrapTest < Minitest::Test
6
+ def test_signal_handler_trace
7
+ i1, o1 = IO.pipe
8
+ i2, o2 = IO.pipe
9
+ pid = Process.pid
10
+ child_pid = Polyphony.fork do
11
+ i1.gets
12
+ Process.kill('SIGINT', pid)
13
+ sleep 0.1
14
+ o2.puts "done"
15
+ o2.close
16
+ end
17
+
18
+ events = []
19
+ begin
20
+ Thread.backend.trace_proc = proc { |*e| events << [e[0], e[1].tag] }
21
+ trap ('SIGINT') { }
22
+
23
+ o1.orig_write("\n")
24
+ o1.close
25
+
26
+ msg = i2.gets
27
+ assert_equal "done\n", msg
28
+ ensure
29
+ Thread.backend.trace_proc = nil
30
+ trap ('SIGINT') { raise Interrupt }
31
+ end
32
+
33
+ Fiber.current.tag = :main
34
+
35
+ expected = [
36
+ [:fiber_switchpoint, :main],
37
+ [:fiber_event_poll_enter, :main],
38
+ [:fiber_create, :oob],
39
+ [:fiber_schedule, :oob],
40
+ [:fiber_event_poll_leave, :main],
41
+ [:fiber_run, :oob],
42
+ [:fiber_terminate, :oob],
43
+ [:fiber_switchpoint, :oob],
44
+ [:fiber_event_poll_enter, :oob],
45
+ [:fiber_schedule, :main],
46
+ [:fiber_event_poll_leave, :oob],
47
+ [:fiber_run, :main]
48
+ ]
49
+ if Thread.backend.kind == :libev
50
+ expected += [
51
+ [:fiber_schedule, :main],
52
+ [:fiber_switchpoint, :main],
53
+ [:fiber_run, :main]
54
+ ]
55
+ end
56
+
57
+ assert_equal expected, events
58
+ ensure
59
+ Process.kill('SIGTERM', child_pid) rescue nil
60
+ Process.wait(child_pid) rescue nil
61
+ end
62
+
6
63
  def test_int_signal
7
64
  Thread.new { sleep 0.001; Process.kill('INT', Process.pid) }
8
65
  assert_raises(Interrupt) { sleep 5 }
data/test/test_timer.rb CHANGED
@@ -78,7 +78,7 @@ class TimerCancelAfterTest < MiniTest::Test
78
78
 
79
79
  def test_timer_cancel_after_with_reset
80
80
  buf = []
81
- @timer.cancel_after(0.13) do
81
+ @timer.cancel_after(0.15) do
82
82
  sleep 0.05
83
83
  buf << 1
84
84
  @timer.reset
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: polyphony
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.76'
4
+ version: '0.77'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-06 00:00:00.000000000 Z
11
+ date: 2022-02-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler
@@ -245,6 +245,8 @@ files:
245
245
  - examples/core/thread_pool.rb
246
246
  - examples/core/throttling.rb
247
247
  - examples/core/timeout.rb
248
+ - examples/core/trap1.rb
249
+ - examples/core/trap2.rb
248
250
  - examples/core/using-a-mutex.rb
249
251
  - examples/core/worker-thread.rb
250
252
  - examples/io/backticks.rb
@@ -346,6 +348,7 @@ files:
346
348
  - ext/polyphony/runqueue_ring_buffer.h
347
349
  - ext/polyphony/socket_extensions.c
348
350
  - ext/polyphony/thread.c
351
+ - ext/test_eintr.c
349
352
  - lib/polyphony.rb
350
353
  - lib/polyphony/adapters/fs.rb
351
354
  - lib/polyphony/adapters/irb.rb