polyphony 0.41 → 0.42

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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -0
  3. data/Gemfile.lock +5 -5
  4. data/Rakefile +1 -1
  5. data/TODO.md +19 -9
  6. data/docs/_config.yml +56 -7
  7. data/docs/_sass/custom/custom.scss +0 -30
  8. data/docs/_sass/overrides.scss +0 -46
  9. data/docs/{user-guide → _user-guide}/all-about-timers.md +0 -0
  10. data/docs/_user-guide/index.md +9 -0
  11. data/docs/{user-guide → _user-guide}/web-server.md +0 -0
  12. data/docs/api-reference/index.md +9 -0
  13. data/docs/api-reference/polyphony-process.md +1 -1
  14. data/docs/api-reference/thread.md +1 -1
  15. data/docs/faq.md +21 -11
  16. data/docs/getting-started/index.md +10 -0
  17. data/docs/getting-started/installing.md +2 -6
  18. data/docs/getting-started/overview.md +507 -0
  19. data/docs/getting-started/tutorial.md +27 -19
  20. data/docs/index.md +1 -1
  21. data/docs/main-concepts/concurrency.md +0 -5
  22. data/docs/main-concepts/design-principles.md +2 -12
  23. data/docs/main-concepts/index.md +9 -0
  24. data/examples/core/01-spinning-up-fibers.rb +1 -0
  25. data/examples/core/03-interrupting.rb +4 -1
  26. data/examples/core/04-handling-signals.rb +19 -0
  27. data/examples/performance/thread-vs-fiber/polyphony_server.rb +6 -18
  28. data/examples/performance/thread-vs-fiber/polyphony_server_read_loop.rb +58 -0
  29. data/examples/performance/xx-array.rb +11 -0
  30. data/examples/performance/xx-fiber-switch.rb +9 -0
  31. data/examples/performance/xx-snooze.rb +15 -0
  32. data/ext/polyphony/fiber.c +0 -3
  33. data/ext/polyphony/libev_agent.c +234 -19
  34. data/ext/polyphony/libev_queue.c +3 -1
  35. data/ext/polyphony/polyphony.c +0 -10
  36. data/ext/polyphony/polyphony.h +6 -6
  37. data/ext/polyphony/thread.c +8 -36
  38. data/lib/polyphony.rb +5 -2
  39. data/lib/polyphony/core/channel.rb +2 -2
  40. data/lib/polyphony/core/global_api.rb +2 -2
  41. data/lib/polyphony/core/resource_pool.rb +2 -2
  42. data/lib/polyphony/extensions/core.rb +2 -3
  43. data/lib/polyphony/version.rb +1 -1
  44. data/polyphony.gemspec +1 -1
  45. data/test/test_agent.rb +49 -2
  46. metadata +16 -20
  47. data/docs/_includes/head.html +0 -40
  48. data/docs/_includes/nav.html +0 -51
  49. data/docs/_includes/prevnext.html +0 -17
  50. data/docs/_layouts/default.html +0 -106
  51. data/docs/api-reference.md +0 -11
  52. data/docs/api-reference/gyro-async.md +0 -57
  53. data/docs/api-reference/gyro-child.md +0 -29
  54. data/docs/api-reference/gyro-queue.md +0 -44
  55. data/docs/api-reference/gyro-timer.md +0 -51
  56. data/docs/api-reference/gyro.md +0 -25
  57. data/docs/getting-started.md +0 -10
  58. data/docs/main-concepts.md +0 -10
  59. data/docs/user-guide.md +0 -10
  60. data/examples/core/forever_sleep.rb +0 -19
@@ -137,6 +137,8 @@ void async_queue_callback(struct ev_loop *ev_loop, struct ev_async *ev_async, in
137
137
  Fiber_make_runnable(watcher->fiber, Qnil);
138
138
  }
139
139
 
140
+ VALUE libev_agent_await(VALUE self);
141
+
140
142
  VALUE LibevQueue_shift(VALUE self) {
141
143
  LibevQueue_t *queue;
142
144
  GetQueue(self, queue);
@@ -152,7 +154,7 @@ VALUE LibevQueue_shift(VALUE self) {
152
154
  ev_async_init(&watcher.async, async_queue_callback);
153
155
  ev_async_start(watcher.ev_loop, &watcher.async);
154
156
 
155
- switchpoint_result = Polyphony_switchpoint();
157
+ switchpoint_result = libev_agent_await(agent);
156
158
  ev_async_stop(watcher.ev_loop, &watcher.async);
157
159
 
158
160
  if (RTEST(rb_obj_is_kind_of(switchpoint_result, rb_eException))) {
@@ -36,14 +36,6 @@ VALUE Polyphony_snooze(VALUE self) {
36
36
  return ret;
37
37
  }
38
38
 
39
- static VALUE Polyphony_ref(VALUE self) {
40
- return Thread_ref(rb_thread_current());
41
- }
42
-
43
- static VALUE Polyphony_unref(VALUE self) {
44
- return Thread_unref(rb_thread_current());
45
- }
46
-
47
39
  static VALUE Polyphony_suspend(VALUE self) {
48
40
  VALUE ret = Thread_switch_fiber(rb_thread_current());
49
41
 
@@ -60,9 +52,7 @@ VALUE Polyphony_trace(VALUE self, VALUE enabled) {
60
52
  void Init_Polyphony() {
61
53
  mPolyphony = rb_define_module("Polyphony");
62
54
 
63
- rb_define_singleton_method(mPolyphony, "ref", Polyphony_ref, 0);
64
55
  rb_define_singleton_method(mPolyphony, "trace", Polyphony_trace, 1);
65
- rb_define_singleton_method(mPolyphony, "unref", Polyphony_unref, 0);
66
56
 
67
57
  rb_define_global_function("snooze", Polyphony_snooze, 0);
68
58
  rb_define_global_function("suspend", Polyphony_suspend, 0);
@@ -7,7 +7,7 @@
7
7
 
8
8
  // debugging
9
9
  #define OBJ_ID(obj) (NUM2LONG(rb_funcall(obj, rb_intern("object_id"), 0)))
10
- #define INSPECT(...) (rb_funcall(rb_cObject, rb_intern("p"), __VA_ARGS__))
10
+ #define INSPECT(obj) { VALUE s = rb_funcall(obj, rb_intern("inspect"), 0); printf("%s\n", StringValueCStr(s));}
11
11
  #define FIBER_TRACE(...) if (__tracing_enabled__) { \
12
12
  rb_funcall(rb_cObject, ID_fiber_trace, __VA_ARGS__); \
13
13
  }
@@ -66,22 +66,22 @@ enum {
66
66
  VALUE Fiber_auto_watcher(VALUE self);
67
67
  void Fiber_make_runnable(VALUE fiber, VALUE value);
68
68
 
69
- VALUE Polyphony_switchpoint();
70
-
71
69
  VALUE LibevAgent_poll(VALUE self, VALUE nowait, VALUE current_fiber, VALUE queue);
72
70
  VALUE LibevAgent_break(VALUE self);
73
71
  VALUE LibevAgent_pending_count(VALUE self);
74
72
  VALUE LibevAgent_wait_io(VALUE self, VALUE io, VALUE write);
75
73
 
74
+ VALUE LibevAgent_ref(VALUE self);
75
+ VALUE LibevAgent_unref(VALUE self);
76
+ int LibevAgent_ref_count(VALUE self);
77
+ void LibevAgent_reset_ref_count(VALUE self);
78
+
76
79
  VALUE Polyphony_snooze(VALUE self);
77
80
 
78
81
  VALUE Polyphony_Queue_push(VALUE self, VALUE value);
79
82
 
80
- VALUE Thread_post_fork(VALUE thread);
81
- VALUE Thread_ref(VALUE thread);
82
83
  VALUE Thread_schedule_fiber(VALUE thread, VALUE fiber, VALUE value);
83
84
  VALUE Thread_switch_fiber(VALUE thread);
84
- VALUE Thread_unref(VALUE thread);
85
85
 
86
86
  int io_setstrbuf(VALUE *str, long len);
87
87
  void io_set_read_length(VALUE str, long n, int shrinkable);
@@ -2,7 +2,6 @@
2
2
 
3
3
  ID ID_deactivate_all_watchers_post_fork;
4
4
  ID ID_empty;
5
- ID ID_fiber_ref_count;
6
5
  ID ID_ivar_agent;
7
6
  ID ID_ivar_join_wait_queue;
8
7
  ID ID_ivar_main_fiber;
@@ -18,34 +17,20 @@ static VALUE Thread_setup_fiber_scheduling(VALUE self) {
18
17
  VALUE queue;
19
18
 
20
19
  rb_ivar_set(self, ID_ivar_main_fiber, rb_fiber_current());
21
- rb_ivar_set(self, ID_fiber_ref_count, INT2NUM(0));
22
20
  queue = rb_ary_new();
23
21
  rb_ivar_set(self, ID_run_queue, queue);
24
22
 
25
23
  return self;
26
24
  }
27
25
 
28
- VALUE Thread_ref(VALUE self) {
29
- VALUE count = rb_ivar_get(self, ID_fiber_ref_count);
30
- int new_count = NUM2INT(count) + 1;
31
- rb_ivar_set(self, ID_fiber_ref_count, INT2NUM(new_count));
32
- return self;
33
- }
34
-
35
- VALUE Thread_unref(VALUE self) {
36
- VALUE count = rb_ivar_get(self, ID_fiber_ref_count);
37
- int new_count = NUM2INT(count) - 1;
38
- rb_ivar_set(self, ID_fiber_ref_count, INT2NUM(new_count));
39
- return self;
40
- }
41
-
42
26
  int Thread_fiber_ref_count(VALUE self) {
43
- VALUE count = rb_ivar_get(self, ID_fiber_ref_count);
44
- return NUM2INT(count);
27
+ VALUE agent = rb_ivar_get(self, ID_ivar_agent);
28
+ return NUM2INT(LibevAgent_ref_count(agent));
45
29
  }
46
30
 
47
- void Thread_fiber_reset_ref_count(VALUE self) {
48
- rb_ivar_set(self, ID_fiber_ref_count, INT2NUM(0));
31
+ inline void Thread_fiber_reset_ref_count(VALUE self) {
32
+ VALUE agent = rb_ivar_get(self, ID_ivar_agent);
33
+ LibevAgent_reset_ref_count(agent);
49
34
  }
50
35
 
51
36
  static VALUE SYM_scheduled_fibers;
@@ -140,8 +125,8 @@ VALUE Thread_switch_fiber(VALUE self) {
140
125
  }
141
126
  }
142
127
 
128
+ ref_count = LibevAgent_ref_count(agent);
143
129
  while (1) {
144
- ref_count = Thread_fiber_ref_count(self);
145
130
  next_fiber = rb_ary_shift(queue);
146
131
  if (next_fiber != Qnil) {
147
132
  if (ref_count > 0) {
@@ -165,7 +150,8 @@ VALUE Thread_switch_fiber(VALUE self) {
165
150
  rb_ivar_set(next_fiber, ID_runnable, Qnil);
166
151
  RB_GC_GUARD(next_fiber);
167
152
  RB_GC_GUARD(value);
168
- return rb_funcall(next_fiber, ID_transfer, 1, value);
153
+ return (next_fiber == current_fiber) ?
154
+ value : rb_funcall(next_fiber, ID_transfer, 1, value);
169
155
  }
170
156
 
171
157
  VALUE Thread_reset_fiber_scheduling(VALUE self) {
@@ -175,16 +161,6 @@ VALUE Thread_reset_fiber_scheduling(VALUE self) {
175
161
  return self;
176
162
  }
177
163
 
178
- VALUE Polyphony_switchpoint() {
179
- VALUE ret;
180
- VALUE thread = rb_thread_current();
181
- Thread_ref(thread);
182
- ret = Thread_switch_fiber(thread);
183
- Thread_unref(thread);
184
- RB_GC_GUARD(ret);
185
- return ret;
186
- }
187
-
188
164
  VALUE Thread_fiber_break_out_of_ev_loop(VALUE self, VALUE fiber, VALUE resume_obj) {
189
165
  VALUE agent = rb_ivar_get(self, ID_ivar_agent);
190
166
  if (fiber != Qnil) {
@@ -200,9 +176,6 @@ VALUE Thread_fiber_break_out_of_ev_loop(VALUE self, VALUE fiber, VALUE resume_ob
200
176
  }
201
177
 
202
178
  void Init_Thread() {
203
- rb_define_method(rb_cThread, "fiber_ref", Thread_ref, 0);
204
- rb_define_method(rb_cThread, "fiber_unref", Thread_unref, 0);
205
-
206
179
  rb_define_method(rb_cThread, "setup_fiber_scheduling", Thread_setup_fiber_scheduling, 0);
207
180
  rb_define_method(rb_cThread, "reset_fiber_scheduling", Thread_reset_fiber_scheduling, 0);
208
181
  rb_define_method(rb_cThread, "fiber_scheduling_stats", Thread_fiber_scheduling_stats, 0);
@@ -215,7 +188,6 @@ void Init_Thread() {
215
188
 
216
189
  ID_deactivate_all_watchers_post_fork = rb_intern("deactivate_all_watchers_post_fork");
217
190
  ID_empty = rb_intern("empty?");
218
- ID_fiber_ref_count = rb_intern("fiber_ref_count");
219
191
  ID_ivar_agent = rb_intern("@agent");
220
192
  ID_ivar_join_wait_queue = rb_intern("@join_wait_queue");
221
193
  ID_ivar_main_fiber = rb_intern("@main_fiber");
@@ -26,14 +26,17 @@ require_relative './polyphony/event'
26
26
  module Polyphony
27
27
  class << self
28
28
  def wait_for_signal(sig)
29
+ raise "should be reimplemented"
30
+
29
31
  fiber = Fiber.current
30
- Polyphony.ref
32
+ # Polyphony.ref
31
33
  old_trap = trap(sig) do
32
- Polyphony.unref
34
+ # Polyphony.unref
33
35
  fiber.schedule(sig)
34
36
  trap(sig, old_trap)
35
37
  end
36
38
  suspend
39
+
37
40
  end
38
41
 
39
42
  def fork(&block)
@@ -26,7 +26,7 @@ module Polyphony
26
26
  end
27
27
 
28
28
  def receive
29
- Polyphony.ref
29
+ Thread.current.agent.ref
30
30
  if @payload_queue.empty?
31
31
  @waiting_queue << Fiber.current
32
32
  suspend
@@ -34,7 +34,7 @@ module Polyphony
34
34
  receive_from_queue
35
35
  end
36
36
  ensure
37
- Polyphony.unref
37
+ Thread.current.agent.unref
38
38
  end
39
39
 
40
40
  def receive_from_queue
@@ -100,10 +100,10 @@ module Polyphony
100
100
  end
101
101
 
102
102
  def sleep_forever
103
- Thread.current.fiber_ref
103
+ Thread.current.agent.ref
104
104
  suspend
105
105
  ensure
106
- Thread.current.fiber_unref
106
+ Thread.current.agent.unref
107
107
  end
108
108
 
109
109
  def throttled_loop(rate, count: nil, &block)
@@ -23,13 +23,13 @@ module Polyphony
23
23
  end
24
24
 
25
25
  def acquire
26
- Polyphony.ref
26
+ Thread.current.agent.ref
27
27
  resource = wait_for_resource
28
28
  return unless resource
29
29
 
30
30
  yield resource
31
31
  ensure
32
- Polyphony.unref
32
+ Thread.current.agent.unref
33
33
  release(resource) if resource
34
34
  end
35
35
 
@@ -8,8 +8,6 @@ require_relative '../core/exceptions'
8
8
 
9
9
  # Exeption overrides
10
10
  class ::Exception
11
- EXIT_EXCEPTION_CLASSES = [::Interrupt, ::SystemExit].freeze
12
-
13
11
  class << self
14
12
  attr_accessor :__disable_sanitized_backtrace__
15
13
  end
@@ -24,7 +22,7 @@ class ::Exception
24
22
 
25
23
  alias_method :orig_backtrace, :backtrace
26
24
  def backtrace
27
- unless @first_backtrace_call || EXIT_EXCEPTION_CLASSES.include?(self.class)
25
+ unless @first_backtrace_call
28
26
  @first_backtrace_call = true
29
27
  return orig_backtrace
30
28
  end
@@ -93,6 +91,7 @@ module ::Kernel
93
91
  def gets(*_args)
94
92
  if !ARGV.empty? || @gets_fiber
95
93
  @gets_fiber ||= Fiber.new(&ARGV_GETS_LOOP)
94
+ @gets_fiber.thread = Thread.current
96
95
  result = @gets_fiber.alive? && @gets_fiber.safe_transfer(Fiber.current)
97
96
  return result if result
98
97
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polyphony
4
- VERSION = '0.41'
4
+ VERSION = '0.42'
5
5
  end
@@ -36,5 +36,5 @@ Gem::Specification.new do |s|
36
36
  s.add_development_dependency 'jekyll', '~>3.8.6'
37
37
  s.add_development_dependency 'jekyll-remote-theme', '~>0.4.1'
38
38
  s.add_development_dependency 'jekyll-seo-tag', '~>2.6.1'
39
- s.add_development_dependency 'just-the-docs', '~>0.2.7'
39
+ s.add_development_dependency 'just-the-docs', '~>0.3.0'
40
40
  end
@@ -5,11 +5,14 @@ require_relative 'helper'
5
5
  class AgentTest < MiniTest::Test
6
6
  def setup
7
7
  super
8
+ @prev_agent = Thread.current.agent
8
9
  @agent = Polyphony::LibevAgent.new
10
+ Thread.current.agent = @agent
9
11
  end
10
12
 
11
13
  def teardown
12
14
  @agent.finalize
15
+ Thread.current.agent = @prev_agent
13
16
  end
14
17
 
15
18
  def test_sleep
@@ -67,11 +70,55 @@ class AgentTest < MiniTest::Test
67
70
 
68
71
  def test_waitpid
69
72
  pid = fork do
70
- Thread.current.agent.post_fork
73
+ @agent.post_fork
71
74
  exit(42)
72
75
  end
73
76
 
74
- result = Thread.current.agent.waitpid(pid)
77
+ result = @agent.waitpid(pid)
75
78
  assert_equal [pid, 42], result
76
79
  end
80
+
81
+ def test_read_loop
82
+ i, o = IO.pipe
83
+
84
+ buf = []
85
+ spin do
86
+ buf << :ready
87
+ @agent.read_loop(i) { |d| buf << d }
88
+ buf << :done
89
+ end
90
+
91
+ o << 'foo'
92
+ o << 'bar'
93
+ o.close
94
+ snooze
95
+
96
+ assert_equal [:ready, 'foo', 'bar', :done], buf
97
+ end
98
+
99
+ def test_accept_loop
100
+ server = TCPServer.new('127.0.0.1', 1234)
101
+
102
+ clients = []
103
+ server_fiber = spin do
104
+ @agent.accept_loop(server) { |c| clients << c }
105
+ end
106
+
107
+ c1 = TCPSocket.new('127.0.0.1', 1234)
108
+ snooze
109
+
110
+ assert_equal 1, clients.size
111
+
112
+ c2 = TCPSocket.new('127.0.0.1', 1234)
113
+ snooze
114
+
115
+ assert_equal 2, clients.size
116
+
117
+ ensure
118
+ c1&.close
119
+ c2&.close
120
+ server_fiber.stop
121
+ snooze
122
+ server&.close
123
+ end
77
124
  end
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.41'
4
+ version: '0.42'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-27 00:00:00.000000000 Z
11
+ date: 2020-07-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -212,14 +212,14 @@ dependencies:
212
212
  requirements:
213
213
  - - "~>"
214
214
  - !ruby/object:Gem::Version
215
- version: 0.2.7
215
+ version: 0.3.0
216
216
  type: :development
217
217
  prerelease: false
218
218
  version_requirements: !ruby/object:Gem::Requirement
219
219
  requirements:
220
220
  - - "~>"
221
221
  - !ruby/object:Gem::Version
222
- version: 0.2.7
222
+ version: 0.3.0
223
223
  description:
224
224
  email: ciconia@gmail.com
225
225
  executables: []
@@ -242,20 +242,14 @@ files:
242
242
  - TODO.md
243
243
  - bin/polyphony-debug
244
244
  - docs/_config.yml
245
- - docs/_includes/head.html
246
- - docs/_includes/nav.html
247
- - docs/_includes/prevnext.html
248
- - docs/_layouts/default.html
249
245
  - docs/_sass/custom/custom.scss
250
246
  - docs/_sass/overrides.scss
251
- - docs/api-reference.md
247
+ - docs/_user-guide/all-about-timers.md
248
+ - docs/_user-guide/index.md
249
+ - docs/_user-guide/web-server.md
252
250
  - docs/api-reference/exception.md
253
251
  - docs/api-reference/fiber.md
254
- - docs/api-reference/gyro-async.md
255
- - docs/api-reference/gyro-child.md
256
- - docs/api-reference/gyro-queue.md
257
- - docs/api-reference/gyro-timer.md
258
- - docs/api-reference/gyro.md
252
+ - docs/api-reference/index.md
259
253
  - docs/api-reference/io.md
260
254
  - docs/api-reference/object.md
261
255
  - docs/api-reference/polyphony-baseexception.md
@@ -273,19 +267,17 @@ files:
273
267
  - docs/assets/img/echo-fibers.svg
274
268
  - docs/assets/img/sleeping-fiber.svg
275
269
  - docs/faq.md
276
- - docs/getting-started.md
270
+ - docs/getting-started/index.md
277
271
  - docs/getting-started/installing.md
272
+ - docs/getting-started/overview.md
278
273
  - docs/getting-started/tutorial.md
279
274
  - docs/index.md
280
- - docs/main-concepts.md
281
275
  - docs/main-concepts/concurrency.md
282
276
  - docs/main-concepts/design-principles.md
283
277
  - docs/main-concepts/exception-handling.md
284
278
  - docs/main-concepts/extending.md
285
279
  - docs/main-concepts/fiber-scheduling.md
286
- - docs/user-guide.md
287
- - docs/user-guide/all-about-timers.md
288
- - docs/user-guide/web-server.md
280
+ - docs/main-concepts/index.md
289
281
  - examples/adapters/pg_client.rb
290
282
  - examples/adapters/pg_notify.rb
291
283
  - examples/adapters/pg_pool.rb
@@ -297,7 +289,7 @@ files:
297
289
  - examples/core/01-spinning-up-fibers.rb
298
290
  - examples/core/02-awaiting-fibers.rb
299
291
  - examples/core/03-interrupting.rb
300
- - examples/core/forever_sleep.rb
292
+ - examples/core/04-handling-signals.rb
301
293
  - examples/core/xx-agent.rb
302
294
  - examples/core/xx-at_exit.rb
303
295
  - examples/core/xx-caller.rb
@@ -361,10 +353,14 @@ files:
361
353
  - examples/performance/snooze_raw.rb
362
354
  - examples/performance/thread-vs-fiber/polyphony_mt_server.rb
363
355
  - examples/performance/thread-vs-fiber/polyphony_server.rb
356
+ - examples/performance/thread-vs-fiber/polyphony_server_read_loop.rb
364
357
  - examples/performance/thread-vs-fiber/threaded_server.rb
365
358
  - examples/performance/thread-vs-fiber/xx-httparty_multi.rb
366
359
  - examples/performance/thread-vs-fiber/xx-httparty_threaded.rb
367
360
  - examples/performance/thread_pool_perf.rb
361
+ - examples/performance/xx-array.rb
362
+ - examples/performance/xx-fiber-switch.rb
363
+ - examples/performance/xx-snooze.rb
368
364
  - ext/libev/Changes
369
365
  - ext/libev/LICENSE
370
366
  - ext/libev/README