polyphony 0.41 → 0.42

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