polyphony 0.22 → 0.23

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