polyphony 0.22 → 0.23

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.
Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -0
  3. data/Gemfile.lock +9 -1
  4. data/TODO.md +13 -38
  5. data/docs/summary.md +19 -5
  6. data/docs/technical-overview/faq.md +12 -0
  7. data/examples/core/01-spinning-up-coprocesses.rb +2 -6
  8. data/examples/core/02-awaiting-coprocesses.rb +3 -1
  9. data/examples/core/03-interrupting.rb +3 -1
  10. data/examples/core/04-no-auto-run.rb +1 -3
  11. data/examples/core/cancel.rb +1 -1
  12. data/examples/core/channel_echo.rb +3 -1
  13. data/examples/core/defer.rb +3 -1
  14. data/examples/core/enumerator.rb +3 -1
  15. data/examples/core/error_bubbling.rb +35 -0
  16. data/examples/core/fork.rb +1 -1
  17. data/examples/core/genserver.rb +1 -1
  18. data/examples/core/lock.rb +3 -1
  19. data/examples/core/move_on.rb +1 -1
  20. data/examples/core/move_on_twice.rb +1 -1
  21. data/examples/core/move_on_with_ensure.rb +1 -1
  22. data/examples/core/move_on_with_value.rb +1 -1
  23. data/examples/core/multiple_spin.rb +3 -1
  24. data/examples/core/nested_cancel.rb +1 -1
  25. data/examples/core/nested_multiple_spin.rb +3 -1
  26. data/examples/core/nested_spin.rb +3 -1
  27. data/examples/core/pulse.rb +1 -1
  28. data/examples/core/resource.rb +1 -1
  29. data/examples/core/resource_cancel.rb +2 -2
  30. data/examples/core/resource_delegate.rb +1 -1
  31. data/examples/core/sleep.rb +1 -1
  32. data/examples/core/sleep_spin.rb +3 -1
  33. data/examples/core/snooze.rb +1 -1
  34. data/examples/core/spin_error.rb +2 -1
  35. data/examples/core/spin_error_backtrace.rb +1 -1
  36. data/examples/core/spin_uncaught_error.rb +3 -1
  37. data/examples/core/supervisor.rb +1 -1
  38. data/examples/core/supervisor_with_cancel_scope.rb +1 -1
  39. data/examples/core/supervisor_with_error.rb +3 -1
  40. data/examples/core/supervisor_with_manual_move_on.rb +1 -1
  41. data/examples/core/suspend.rb +1 -1
  42. data/examples/core/thread.rb +3 -3
  43. data/examples/core/thread_cancel.rb +6 -3
  44. data/examples/core/thread_pool.rb +8 -52
  45. data/examples/core/thread_pool_perf.rb +63 -0
  46. data/examples/core/throttle.rb +3 -1
  47. data/examples/core/timeout.rb +1 -1
  48. data/examples/core/wait_for_signal.rb +4 -2
  49. data/examples/fs/read.rb +1 -1
  50. data/examples/http/http2_raw.rb +1 -1
  51. data/examples/http/http_get.rb +1 -1
  52. data/examples/http/http_server.rb +2 -1
  53. data/examples/http/http_server_graceful.rb +3 -1
  54. data/examples/http/http_ws_server.rb +0 -2
  55. data/examples/http/https_wss_server.rb +0 -2
  56. data/examples/http/websocket_secure_server.rb +0 -2
  57. data/examples/http/websocket_server.rb +0 -2
  58. data/examples/interfaces/redis_channels.rb +3 -1
  59. data/examples/interfaces/redis_pubsub.rb +3 -1
  60. data/examples/interfaces/redis_pubsub_perf.rb +3 -1
  61. data/examples/io/backticks.rb +1 -1
  62. data/examples/io/cat.rb +1 -1
  63. data/examples/io/echo_client.rb +1 -1
  64. data/examples/io/echo_client_from_stdin.rb +3 -1
  65. data/examples/io/echo_pipe.rb +1 -1
  66. data/examples/io/echo_server.rb +1 -1
  67. data/examples/io/echo_server_with_timeout.rb +1 -1
  68. data/examples/io/echo_stdin.rb +1 -1
  69. data/examples/io/httparty_multi.rb +1 -1
  70. data/examples/io/io_read.rb +1 -1
  71. data/examples/io/irb.rb +1 -1
  72. data/examples/io/net-http.rb +1 -1
  73. data/examples/io/open.rb +1 -1
  74. data/examples/io/system.rb +1 -1
  75. data/examples/io/tcpserver.rb +1 -1
  76. data/examples/io/tcpsocket.rb +1 -1
  77. data/examples/performance/multi_snooze.rb +1 -1
  78. data/examples/performance/snooze.rb +18 -10
  79. data/ext/gyro/async.c +16 -9
  80. data/ext/gyro/child.c +2 -2
  81. data/ext/gyro/gyro.c +17 -10
  82. data/ext/gyro/gyro.h +2 -2
  83. data/ext/gyro/io.c +2 -2
  84. data/ext/gyro/signal.c +33 -35
  85. data/ext/gyro/timer.c +6 -73
  86. data/lib/polyphony.rb +6 -8
  87. data/lib/polyphony/core/cancel_scope.rb +32 -21
  88. data/lib/polyphony/core/coprocess.rb +26 -23
  89. data/lib/polyphony/core/global_api.rb +86 -0
  90. data/lib/polyphony/core/resource_pool.rb +1 -1
  91. data/lib/polyphony/core/supervisor.rb +47 -13
  92. data/lib/polyphony/core/thread.rb +10 -36
  93. data/lib/polyphony/core/thread_pool.rb +6 -26
  94. data/lib/polyphony/extensions/core.rb +30 -100
  95. data/lib/polyphony/extensions/io.rb +10 -7
  96. data/lib/polyphony/extensions/openssl.rb +18 -28
  97. data/lib/polyphony/http/client/agent.rb +15 -11
  98. data/lib/polyphony/http/client/http2.rb +1 -1
  99. data/lib/polyphony/version.rb +1 -1
  100. data/polyphony.gemspec +1 -0
  101. data/test/coverage.rb +45 -0
  102. data/test/helper.rb +15 -5
  103. data/test/test_async.rb +4 -4
  104. data/test/test_cancel_scope.rb +109 -0
  105. data/test/test_coprocess.rb +80 -36
  106. data/test/{test_core.rb → test_global_api.rb} +67 -13
  107. data/test/test_gyro.rb +1 -5
  108. data/test/test_io.rb +2 -2
  109. data/test/test_resource_pool.rb +19 -0
  110. data/test/test_signal.rb +10 -5
  111. data/test/test_supervisor.rb +168 -0
  112. data/test/test_timer.rb +31 -5
  113. metadata +23 -4
  114. data/lib/polyphony/auto_run.rb +0 -19
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
  require 'polyphony/fs'
6
6
 
7
7
  def raw_read_file(x)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
  require 'http/2'
6
6
 
7
7
  # Response = import '../../lib/polyphony/http/client/response'
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'bundler/setup'
4
4
  require 'polyphony/http'
5
- require 'polyphony/auto_run'
5
+ require 'polyphony'
6
6
 
7
7
  Exception.__disable_sanitized_backtrace__ = true
8
8
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
  require 'polyphony/http'
6
6
 
7
7
  opts = {
@@ -25,3 +25,4 @@ end
25
25
 
26
26
  puts "pid: #{Process.pid}"
27
27
  puts 'Listening on port 1234...'
28
+ suspend
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
  require 'polyphony/http'
6
6
 
7
7
  opts = {
@@ -23,3 +23,5 @@ end
23
23
  puts "pid: #{Process.pid}"
24
24
  puts 'Send HUP to stop gracefully'
25
25
  puts 'Listening on port 1234...'
26
+
27
+ suspend
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- STDOUT.sync = true
4
-
5
3
  require 'bundler/setup'
6
4
  require 'polyphony/http'
7
5
  require 'polyphony/websocket'
@@ -4,8 +4,6 @@ require 'bundler/setup'
4
4
  require 'polyphony/http'
5
5
  require 'localhost/authority'
6
6
 
7
- STDOUT.sync = true
8
-
9
7
  def ws_handler(conn)
10
8
  timer = spin do
11
9
  throttled_loop(1) do
@@ -4,8 +4,6 @@ require 'bundler/setup'
4
4
  require 'polyphony/http'
5
5
  require 'localhost/authority'
6
6
 
7
- STDOUT.sync = true
8
-
9
7
  def ws_handler(conn)
10
8
  while (msg = conn.recv)
11
9
  conn << "you said: #{msg}"
@@ -3,8 +3,6 @@
3
3
  require 'bundler/setup'
4
4
  require 'polyphony/http'
5
5
 
6
- STDOUT.sync = true
7
-
8
6
  def ws_handler(conn)
9
7
  while (msg = conn.recv)
10
8
  conn << "you said: #{msg}"
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
  require 'polyphony/redis'
6
6
 
7
7
  class RedisChannel < Polyphony::Channel
@@ -119,3 +119,5 @@ spin do
119
119
  channel.close
120
120
  RedisChannel.stop_monitor
121
121
  end
122
+
123
+ suspend
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
  require 'polyphony/redis'
6
6
 
7
7
  spin do
@@ -23,3 +23,5 @@ spin do
23
23
  end
24
24
  redis.publish('redis-channel', 'exit')
25
25
  end
26
+
27
+ suspend
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
  require 'polyphony/redis'
6
6
  require 'json'
7
7
 
@@ -65,3 +65,5 @@ trap(:int) do
65
65
  puts 'bye...'
66
66
  exit!
67
67
  end
68
+
69
+ suspend
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  timer = spin do
7
7
  throttled_loop(5) { STDOUT << '.' }
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  File.open(__FILE__, 'r') do |f|
7
7
  line_number = 1
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
  require 'polyphony/extensions/backtrace'
6
6
 
7
7
  socket = Polyphony::Net.tcp_connect('127.0.0.1', 1234)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
  require 'polyphony/extensions/backtrace'
6
6
 
7
7
  socket = Polyphony::Net.tcp_connect('127.0.0.1', 1234)
@@ -18,3 +18,5 @@ spin do
18
18
  end
19
19
  writer.interrupt
20
20
  end
21
+
22
+ suspend
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  i, o = IO.pipe
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  server = TCPServer.open('127.0.0.1', 1234)
7
7
  puts "Pid: #{Process.pid}"
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  begin
7
7
  server = Polyphony::Net.tcp_listen(
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  puts 'Write something...'
7
7
  move_on_after(5) do |scope|
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
  require 'httparty'
6
6
 
7
7
  url = 'http://127.0.0.1:4411/?q=time'
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  s = IO.read(__FILE__)
7
7
  puts "encoding: #{s.encoding.inspect}"
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
  require 'irb'
6
6
 
7
7
  $counter = 0
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
  require 'net/http'
6
6
 
7
7
  uri = URI('http://realiteq.net/?q=time')
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
  require 'irb'
6
6
 
7
7
  stdin = IO.open(STDIN.to_i)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  timer = spin do
7
7
  throttled_loop(5) { STDOUT << '.' }
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  server = TCPServer.new('127.0.0.1', 1234)
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
  require 'polyphony/extensions/backtrace'
6
6
 
7
7
  socket = TCPSocket.new('google.com', 80)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  def bm(fibers, iterations)
7
7
  count = 0
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  X = 1_000_000
7
7
 
8
- STDOUT << 'Fiber.yield: '
8
+ STDOUT << 'Fiber.yield: '
9
9
  f = Fiber.new do
10
10
  loop { Fiber.yield }
11
11
  end
@@ -14,16 +14,24 @@ X.times { f.resume }
14
14
  dt = Time.now - t0
15
15
  puts format('%d/s', (X / dt))
16
16
 
17
- # STDOUT << "Kernel#sleep: "
18
- # t0 = Time.now
19
- # X.times { sleep(0) }
20
- # dt = Time.now - t0
21
- # puts "%d/s" % (X / dt)
22
-
23
- trap('SIGINT') { exit! }
17
+ STDOUT << 'Fiber.transfer: '
18
+ main = Fiber.current
19
+ f = Fiber.new do
20
+ loop { main.transfer }
21
+ end
22
+ t0 = Time.now
23
+ X.times { f.transfer }
24
+ dt = Time.now - t0
25
+ puts format('%d/s', (X / dt))
24
26
 
25
- STDOUT << 'Kernel#snooze: '
27
+ STDOUT << 'Kernel#snooze: '
26
28
  t0 = Time.now
27
29
  X.times { snooze }
28
30
  dt = Time.now - t0
29
31
  puts format('%d/s', (X / dt))
32
+
33
+ STDOUT << 'Kernel#sleep: '
34
+ t0 = Time.now
35
+ X.times { sleep(0) }
36
+ dt = Time.now - t0
37
+ puts "%d/s" % (X / dt)
@@ -4,6 +4,7 @@ struct Gyro_Async {
4
4
  struct ev_async ev_async;
5
5
  int active;
6
6
  VALUE fiber;
7
+ VALUE value;
7
8
  };
8
9
 
9
10
  static VALUE cGyro_Async = Qnil;
@@ -17,7 +18,7 @@ static size_t Gyro_Async_size(const void *ptr);
17
18
  /* Methods */
18
19
  static VALUE Gyro_Async_initialize(VALUE self);
19
20
 
20
- static VALUE Gyro_Async_signal(VALUE self);
21
+ static VALUE Gyro_Async_signal(int argc, VALUE *argv, VALUE self);
21
22
  static VALUE Gyro_Async_await(VALUE self);
22
23
 
23
24
  void Gyro_Async_callback(struct ev_loop *ev_loop, struct ev_async *async, int revents);
@@ -28,7 +29,7 @@ void Init_Gyro_Async() {
28
29
  rb_define_alloc_func(cGyro_Async, Gyro_Async_allocate);
29
30
 
30
31
  rb_define_method(cGyro_Async, "initialize", Gyro_Async_initialize, 0);
31
- rb_define_method(cGyro_Async, "signal!", Gyro_Async_signal, 0);
32
+ rb_define_method(cGyro_Async, "signal!", Gyro_Async_signal, -1);
32
33
  rb_define_method(cGyro_Async, "await", Gyro_Async_await, 0);
33
34
  }
34
35
 
@@ -49,6 +50,9 @@ static void Gyro_Async_mark(void *ptr) {
49
50
  if (async->fiber != Qnil) {
50
51
  rb_gc_mark(async->fiber);
51
52
  }
53
+ if (async->value != Qnil) {
54
+ rb_gc_mark(async->value);
55
+ }
52
56
  }
53
57
 
54
58
  static void Gyro_Async_free(void *ptr) {
@@ -69,6 +73,7 @@ static VALUE Gyro_Async_initialize(VALUE self) {
69
73
  GetGyro_Async(self, async);
70
74
 
71
75
  async->fiber = Qnil;
76
+ async->value = Qnil;
72
77
  async->active = 0;
73
78
 
74
79
  ev_async_init(&async->ev_async, Gyro_Async_callback);
@@ -83,16 +88,17 @@ void Gyro_Async_callback(struct ev_loop *ev_loop, struct ev_async *ev_async, int
83
88
  async->active = 0;
84
89
 
85
90
  if (async->fiber != Qnil) {
86
- VALUE fiber = async->fiber;
91
+ Gyro_schedule_fiber(async->fiber, async->value);
87
92
  async->fiber = Qnil;
88
- Gyro_schedule_fiber(fiber, Qnil);
93
+ async->value = Qnil;
89
94
  }
90
95
  }
91
96
 
92
- static VALUE Gyro_Async_signal(VALUE self) {
97
+ static VALUE Gyro_Async_signal(int argc, VALUE *argv, VALUE self) {
93
98
  struct Gyro_Async *async;
94
99
  GetGyro_Async(self, async);
95
100
 
101
+ async->value = (argc == 1) ? argv[0] : Qnil;
96
102
  ev_async_send(EV_DEFAULT, &async->ev_async);
97
103
 
98
104
  return Qnil;
@@ -110,18 +116,19 @@ static VALUE Gyro_Async_await(VALUE self) {
110
116
  ev_async_start(EV_DEFAULT, &async->ev_async);
111
117
  }
112
118
 
113
- ret = Gyro_yield();
119
+ ret = Gyro_await();
114
120
 
115
121
  // fiber is resumed
116
- async->fiber = Qnil;
117
122
  if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) {
118
123
  if (async->active) {
119
124
  async->active = 0;
120
125
  ev_async_stop(EV_DEFAULT, &async->ev_async);
126
+ async->fiber = Qnil;
127
+ async->value = Qnil;
121
128
  }
122
- return rb_funcall(ret, ID_raise, 1, ret);
129
+ return rb_funcall(rb_mKernel, ID_raise, 1, ret);
123
130
  }
124
131
  else {
125
- return Qnil;
132
+ return ret;
126
133
  }
127
134
  }