polyphony 0.55.0 → 0.59.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,8 +3,8 @@
3
3
  module Polyphony
4
4
  # Implements a common timer for running multiple timeouts
5
5
  class Timer
6
- def initialize(resolution:)
7
- @fiber = spin_loop(interval: resolution) { update }
6
+ def initialize(tag = nil, resolution:)
7
+ @fiber = spin_loop(tag, interval: resolution) { update }
8
8
  @timeouts = {}
9
9
  end
10
10
 
@@ -262,7 +262,7 @@ module Polyphony
262
262
  @parent = parent
263
263
  @caller = caller
264
264
  @block = block
265
- __fiber_trace__(:fiber_create, self)
265
+ Thread.backend.trace(:fiber_create, self)
266
266
  schedule
267
267
  end
268
268
 
@@ -311,7 +311,7 @@ module Polyphony
311
311
 
312
312
  def finalize(result, uncaught_exception = false)
313
313
  result, uncaught_exception = finalize_children(result, uncaught_exception)
314
- __fiber_trace__(:fiber_terminate, self, result)
314
+ Thread.backend.trace(:fiber_terminate, self, result)
315
315
  @result = result
316
316
  @running = false
317
317
  inform_dependants(result, uncaught_exception)
@@ -105,4 +105,12 @@ class ::Thread
105
105
  main_fiber << value
106
106
  end
107
107
  alias_method :send, :<<
108
+
109
+ def idle_gc_period=(period)
110
+ backend.idle_gc_period = period
111
+ end
112
+
113
+ def on_idle(&block)
114
+ backend.idle_proc = block
115
+ end
108
116
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polyphony
4
- VERSION = '0.55.0'
4
+ VERSION = '0.59.1'
5
5
  end
data/test/test_backend.rb CHANGED
@@ -281,6 +281,97 @@ class BackendTest < MiniTest::Test
281
281
  f.await
282
282
  end
283
283
  end
284
+
285
+
286
+ def test_splice_chunks
287
+ body = 'abcd' * 250
288
+ chunk_size = 750
289
+
290
+ buf = +''
291
+ r, w = IO.pipe
292
+ reader = spin do
293
+ r.read_loop { |data| buf << data }
294
+ end
295
+
296
+ i, o = IO.pipe
297
+ writer = spin do
298
+ o << body
299
+ o.close
300
+ end
301
+ Thread.current.backend.splice_chunks(
302
+ i,
303
+ w,
304
+ "Content-Type: foo\r\n\r\n",
305
+ "0\r\n\r\n",
306
+ ->(len) { "#{len.to_s(16)}\r\n" },
307
+ "\r\n",
308
+ chunk_size
309
+ )
310
+ w.close
311
+ reader.await
312
+
313
+ expected = "Content-Type: foo\r\n\r\n#{750.to_s(16)}\r\n#{body[0..749]}\r\n#{250.to_s(16)}\r\n#{body[750..999]}\r\n0\r\n\r\n"
314
+ assert_equal expected, buf
315
+ ensure
316
+ o.close
317
+ w.close
318
+ end
319
+
320
+ def test_idle_gc
321
+ GC.disable
322
+
323
+ count = GC.count
324
+ snooze
325
+ assert_equal count, GC.count
326
+ sleep 0.01
327
+ assert_equal count, GC.count
328
+
329
+ @backend.idle_gc_period = 0.1
330
+ snooze
331
+ assert_equal count, GC.count
332
+ sleep 0.05
333
+ assert_equal count, GC.count
334
+ # The idle tasks are ran at most once per fiber switch, before the backend
335
+ # is polled. Therefore, the second sleep will not have triggered a GC, since
336
+ # only 0.05s have passed since the gc period was set.
337
+ sleep 0.07
338
+ assert_equal count, GC.count
339
+ # Upon the third sleep the GC should be triggered, at 0.12s post setting the
340
+ # GC period.
341
+ sleep 0.05
342
+ assert_equal count + 1, GC.count
343
+
344
+ @backend.idle_gc_period = 0
345
+ count = GC.count
346
+ sleep 0.001
347
+ sleep 0.002
348
+ sleep 0.003
349
+ assert_equal count, GC.count
350
+ ensure
351
+ GC.enable
352
+ end
353
+
354
+ def test_idle_proc
355
+ counter = 0
356
+
357
+ @backend.idle_proc = proc { counter += 1 }
358
+
359
+ 3.times { snooze }
360
+ assert_equal 0, counter
361
+
362
+ sleep 0.01
363
+ assert_equal 1, counter
364
+ sleep 0.01
365
+ assert_equal 2, counter
366
+
367
+ assert_equal 2, counter
368
+ 3.times { snooze }
369
+ assert_equal 2, counter
370
+
371
+ @backend.idle_proc = nil
372
+ sleep 0.01
373
+ assert_equal 2, counter
374
+ end
284
375
  end
285
376
 
286
377
  class BackendChainTest < MiniTest::Test
data/test/test_thread.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'helper'
4
- require 'polyphony/adapters/trace'
5
4
 
6
5
  class ThreadTest < MiniTest::Test
7
6
  def test_thread_spin
@@ -130,18 +129,13 @@ class ThreadTest < MiniTest::Test
130
129
 
131
130
  def test_that_suspend_returns_immediately_if_no_watchers
132
131
  records = []
133
- t = Polyphony::Trace.new(:fiber_all) do |r|
134
- records << r if r[:event] =~ /^fiber_/
135
- end
136
- t.enable
137
- Polyphony.trace(true)
138
-
132
+ Thread.backend.trace_proc = proc {|*r| records << r }
139
133
  suspend
140
- t.disable
141
- assert_equal [:fiber_switchpoint], records.map { |r| r[:event] }
134
+ assert_equal [
135
+ [:fiber_switchpoint, Fiber.current]
136
+ ], records
142
137
  ensure
143
- t&.disable
144
- Polyphony.trace(false)
138
+ Thread.backend.trace_proc = nil
145
139
  end
146
140
 
147
141
  def test_thread_child_fiber_termination
@@ -171,4 +165,56 @@ class ThreadTest < MiniTest::Test
171
165
  t&.kill
172
166
  t&.join
173
167
  end
168
+
169
+ def test_idle_gc
170
+ GC.disable
171
+
172
+ count = GC.count
173
+ snooze
174
+ assert_equal count, GC.count
175
+ sleep 0.01
176
+ assert_equal count, GC.count
177
+
178
+ Thread.current.idle_gc_period = 0.1
179
+ snooze
180
+ assert_equal count, GC.count
181
+ sleep 0.05
182
+ assert_equal count, GC.count
183
+ # The idle tasks are ran at most once per fiber switch, before the backend
184
+ # is polled. Therefore, the second sleep will not have triggered a GC, since
185
+ # only 0.05s have passed since the gc period was set.
186
+ sleep 0.07
187
+ assert_equal count, GC.count
188
+ # Upon the third sleep the GC should be triggered, at 0.12s post setting the
189
+ # GC period.
190
+ sleep 0.05
191
+ assert_equal count + 1, GC.count
192
+
193
+ Thread.current.idle_gc_period = 0
194
+ count = GC.count
195
+ sleep 0.001
196
+ sleep 0.002
197
+ sleep 0.003
198
+ assert_equal count, GC.count
199
+ ensure
200
+ GC.enable
201
+ end
202
+
203
+ def test_on_idle
204
+ counter = 0
205
+
206
+ Thread.current.on_idle { counter += 1 }
207
+
208
+ 3.times { snooze }
209
+ assert_equal 0, counter
210
+
211
+ sleep 0.01
212
+ assert_equal 1, counter
213
+ sleep 0.01
214
+ assert_equal 2, counter
215
+
216
+ assert_equal 2, counter
217
+ 3.times { snooze }
218
+ assert_equal 2, counter
219
+ end
174
220
  end
data/test/test_timer.rb CHANGED
@@ -48,7 +48,7 @@ class TimerMoveOnAfterTest < MiniTest::Test
48
48
  t1 = Time.now
49
49
 
50
50
  assert_nil v
51
- assert_in_range 0.015..0.03, t1 - t0
51
+ assert_in_range 0.015..0.04, t1 - t0
52
52
  end
53
53
  end
54
54
 
@@ -76,17 +76,17 @@ class TimerCancelAfterTest < MiniTest::Test
76
76
 
77
77
  def test_timer_cancel_after_with_reset
78
78
  buf = []
79
- @timer.cancel_after(0.01) do
80
- sleep 0.005
79
+ @timer.cancel_after(0.13) do
80
+ sleep 0.05
81
81
  buf << 1
82
82
  @timer.reset
83
- sleep 0.005
83
+ sleep 0.05
84
84
  buf << 2
85
85
  @timer.reset
86
- sleep 0.005
86
+ sleep 0.05
87
87
  buf << 3
88
88
  @timer.reset
89
- sleep 0.005
89
+ sleep 0.05
90
90
  buf << 4
91
91
  end
92
92
  assert_equal [1, 2, 3, 4], buf
@@ -158,6 +158,6 @@ class TimerMiscTest < MiniTest::Test
158
158
  end
159
159
  sleep 0.05
160
160
  f.stop
161
- assert_in_range 4..6, buffer.size
161
+ assert_in_range 3..7, buffer.size
162
162
  end
163
163
  end
data/test/test_trace.rb CHANGED
@@ -1,70 +1,48 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'helper'
4
- require 'polyphony/adapters/trace'
5
4
 
6
5
  class TraceTest < MiniTest::Test
7
- def test_tracing_disabled
8
- records = []
9
- t = Polyphony::Trace.new { |r| records << r if r[:event] =~ /^fiber_/ }
10
- t.enable
11
- snooze
12
- assert_equal 0, records.size
13
- ensure
14
- t&.disable
15
- Polyphony.trace(nil)
16
- end
17
-
18
6
  def test_tracing_enabled
19
- records = []
20
- t = Polyphony::Trace.new(:fiber_all) { |r| records << r if r[:event] =~ /^fiber_/ }
21
- Polyphony.trace(true)
22
- t.enable
7
+ events = []
8
+ Thread.backend.trace_proc = proc { |*e| events << e }
23
9
  snooze
24
- t.disable
25
10
 
26
- assert_equal 3, records.size
27
- events = records.map { |r| r[:event] }
28
- assert_equal [:fiber_schedule, :fiber_switchpoint, :fiber_run], events
29
- assert_equal [Fiber.current], records.map { |r| r[:fiber] }.uniq
11
+ assert_equal [
12
+ [:fiber_schedule, Fiber.current, nil],
13
+ [:fiber_switchpoint, Fiber.current],
14
+ [:fiber_run, Fiber.current, nil]
15
+ ], events
30
16
  ensure
31
- t&.disable
32
- Polyphony.trace(nil)
17
+ Thread.backend.trace_proc = nil
33
18
  end
34
19
 
35
20
  def test_2_fiber_trace
36
- records = []
37
- thread = Thread.current
38
- t = Polyphony::Trace.new(:fiber_all) do |r|
39
- records << r if Thread.current == thread && r[:event] =~ /^fiber_/
40
- end
41
- t.enable
42
- Polyphony.trace(true)
21
+ events = []
22
+ Thread.backend.trace_proc = proc { |*e| events << e }
43
23
 
44
- f = spin { sleep 0 }
24
+ f = spin { sleep 0; :byebye }
45
25
  suspend
46
26
  sleep 0
47
27
 
48
- events = records.map { |r| [r[:fiber] == f ? :f : :current, r[:event]] }
49
28
  assert_equal [
50
- [:f, :fiber_create],
51
- [:f, :fiber_schedule],
52
- [:current, :fiber_switchpoint],
53
- [:f, :fiber_run],
54
- [:f, :fiber_switchpoint],
55
- [:f, :fiber_event_poll_enter],
56
- [:f, :fiber_schedule],
57
- [:f, :fiber_event_poll_leave],
58
- [:f, :fiber_run],
59
- [:f, :fiber_terminate],
60
- [:current, :fiber_switchpoint],
61
- [:current, :fiber_event_poll_enter],
62
- [:current, :fiber_schedule],
63
- [:current, :fiber_event_poll_leave],
64
- [:current, :fiber_run]
29
+ [:fiber_create, f],
30
+ [:fiber_schedule, f, nil],
31
+ [:fiber_switchpoint, Fiber.current],
32
+ [:fiber_run, f, nil],
33
+ [:fiber_switchpoint, f],
34
+ [:fiber_event_poll_enter, f],
35
+ [:fiber_schedule, f, nil],
36
+ [:fiber_event_poll_leave, f],
37
+ [:fiber_run, f, nil],
38
+ [:fiber_terminate, f, :byebye],
39
+ [:fiber_switchpoint, Fiber.current],
40
+ [:fiber_event_poll_enter, Fiber.current],
41
+ [:fiber_schedule, Fiber.current, nil],
42
+ [:fiber_event_poll_leave, Fiber.current],
43
+ [:fiber_run, Fiber.current, nil]
65
44
  ], events
66
45
  ensure
67
- t&.disable
68
- Polyphony.trace(nil)
46
+ Thread.backend.trace_proc = nil
69
47
  end
70
48
  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.55.0
4
+ version: 0.59.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-17 00:00:00.000000000 Z
11
+ date: 2021-06-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler
@@ -324,6 +324,7 @@ files:
324
324
  - examples/core/erlang-style-genserver.rb
325
325
  - examples/core/forking.rb
326
326
  - examples/core/handling-signals.rb
327
+ - examples/core/idle_gc.rb
327
328
  - examples/core/interrupt.rb
328
329
  - examples/core/nested.rb
329
330
  - examples/core/pingpong.rb
@@ -355,10 +356,12 @@ files:
355
356
  - examples/io/irb.rb
356
357
  - examples/io/net-http.rb
357
358
  - examples/io/open.rb
359
+ - examples/io/pipe.rb
358
360
  - examples/io/pry.rb
359
361
  - examples/io/rack_server.rb
360
362
  - examples/io/raw.rb
361
363
  - examples/io/reline.rb
364
+ - examples/io/splice_chunks.rb
362
365
  - examples/io/stdio.rb
363
366
  - examples/io/system.rb
364
367
  - examples/io/tcp_proxy.rb
@@ -414,6 +417,7 @@ files:
414
417
  - ext/liburing/setup.c
415
418
  - ext/liburing/syscall.c
416
419
  - ext/liburing/syscall.h
420
+ - ext/polyphony/backend_common.c
417
421
  - ext/polyphony/backend_common.h
418
422
  - ext/polyphony/backend_io_uring.c
419
423
  - ext/polyphony/backend_io_uring_context.c
@@ -433,11 +437,11 @@ files:
433
437
  - ext/polyphony/ring_buffer.c
434
438
  - ext/polyphony/ring_buffer.h
435
439
  - ext/polyphony/runqueue.c
440
+ - ext/polyphony/runqueue.h
436
441
  - ext/polyphony/runqueue_ring_buffer.c
437
442
  - ext/polyphony/runqueue_ring_buffer.h
438
443
  - ext/polyphony/socket_extensions.c
439
444
  - ext/polyphony/thread.c
440
- - ext/polyphony/tracing.c
441
445
  - lib/polyphony.rb
442
446
  - lib/polyphony/adapters/fs.rb
443
447
  - lib/polyphony/adapters/irb.rb
@@ -447,7 +451,6 @@ files:
447
451
  - lib/polyphony/adapters/readline.rb
448
452
  - lib/polyphony/adapters/redis.rb
449
453
  - lib/polyphony/adapters/sequel.rb
450
- - lib/polyphony/adapters/trace.rb
451
454
  - lib/polyphony/core/channel.rb
452
455
  - lib/polyphony/core/exceptions.rb
453
456
  - lib/polyphony/core/global_api.rb
@@ -1,11 +0,0 @@
1
- #include "polyphony.h"
2
-
3
- int __tracing_enabled__ = 0;
4
-
5
- VALUE __fiber_trace__(int argc, VALUE *argv, VALUE self) {
6
- return rb_ary_new4(argc, argv);
7
- }
8
-
9
- void Init_Tracing() {
10
- rb_define_global_function("__fiber_trace__", __fiber_trace__, -1);
11
- }