polyphony 0.43.8 → 0.43.9

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bea457e28d23f96570d448855d00cf76250a55fcb02e12c4305cb551cb55faf4
4
- data.tar.gz: dc97409e61ce82c20eef25101a2c53046635461ef81302e54b121e5bb9c25aa1
3
+ metadata.gz: 14930ef46f39537ad6f2233b23691a05d910ecf6c22cd8429a8a82dcf4f2af51
4
+ data.tar.gz: a2c53e7082c35025cce3024113162ed5e67032eed82d49c363516441c3293898
5
5
  SHA512:
6
- metadata.gz: 53d345ee472bc77fc993880a1a725064bb934ec2789fa72bd97ec07b558942369860fb7077e0fcff6c95cfcff0c0d712090f70b1d9ff7f652160d15ddfc77de4
7
- data.tar.gz: 513a79eeb8a7766078d159cf85d367a6f3f50a0870825275408081d9cfe4e446e7f0b0120bd712f6281ccd0787779ec464b20c9e17c3c60178ceb39c061033c7
6
+ metadata.gz: ac9d80b5a0fad4b4d164bed60c42d386fc49e978b381a2a9fd6174bf616cb5a97cb4232c317c62ac0439f534d753e5c9a1e9cbb98be41145a9d288d6d719adcc
7
+ data.tar.gz: 95a8d13b133a0256ffb71df70e4348845dbcbe0c848a94feb0ceaf205e274f918d84529ef7d0773884e51f2e504625a96a4fdf548b17f03fa408c39f763609b6
@@ -1,3 +1,11 @@
1
+ ## 0.43.9 2020-07-22
2
+
3
+ * Rewrite `Channel` using `Queue`
4
+ * Rewrite `Mutex` using `Queue`
5
+ * Reimplement `Event` in C to prevent cross-thread race condition
6
+ * Reimplement `ResourcePool` using `Queue`
7
+ * Implement `Queue#size`
8
+
1
9
  ## 0.43.8 2020-07-21
2
10
 
3
11
  * Rename `LibevQueue` to `Queue`
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- polyphony (0.43.8)
4
+ polyphony (0.43.9)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -1,10 +1,25 @@
1
- <p align="center"><img src="docs/polyphony-logo.png" /></p>
1
+ <h1 align="center">
2
+ <a href="https://digital-fabric.github.io/polyphony/">
3
+ <img src="docs/polyphony-logo.png" alt="Polyphony">
4
+ </a>
5
+ <br>
6
+ Polyphony
7
+ <br>
8
+ </h1>
2
9
 
3
- # Polyphony - Fine-Grained Concurrency for Ruby
10
+ <h4 align="center">Fine-Grained Concurrency for Ruby</h4>
4
11
 
5
- [![Gem Version](https://badge.fury.io/rb/polyphony.svg)](http://rubygems.org/gems/polyphony)
6
- [![Modulation Test](https://github.com/digital-fabric/polyphony/workflows/Tests/badge.svg)](https://github.com/digital-fabric/polyphony/actions?query=workflow%3ATests)
7
- [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/digital-fabric/polyphony/blob/master/LICENSE)
12
+ <p align="center">
13
+ <a href="http://rubygems.org/gems/polyphony">
14
+ <img src="https://badge.fury.io/rb/polyphony.svg" alt="Ruby gem">
15
+ </a>
16
+ <a href="https://github.com/digital-fabric/polyphony/actions?query=workflow%3ATests">
17
+ <img src="https://github.com/digital-fabric/polyphony/workflows/Tests/badge.svg" alt="Tests">
18
+ </a>
19
+ <a href="https://github.com/digital-fabric/polyphony/blob/master/LICENSE">
20
+ <img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT License">
21
+ </a>
22
+ </p>
8
23
 
9
24
  [DOCS](https://digital-fabric.github.io/polyphony/) |
10
25
  [EXAMPLES](examples)
data/TODO.md CHANGED
@@ -1,5 +1,5 @@
1
1
  - Implement `LibevAgent#connect` API
2
- - Reimplement ResourcePool, Channel, Mutex using Queue
2
+
3
3
  -- Add `Fiber#schedule_with_priority` method, aliased by `Fiber#wakeup`
4
4
  - Implement agent interface is virtual function table
5
5
  - Implement proxy agent for plugging in a user-provided agent class
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ `rake recompile`
5
+
6
+ count = ARGV[0] ? ARGV[0].to_i : 100
7
+
8
+ TEST_CMD = 'ruby test/run.rb'
9
+
10
+ def run_test(count)
11
+ puts "#{count}: running tests..."
12
+ system(TEST_CMD)
13
+ return if $?.exitstatus == 0
14
+
15
+ puts "Failure after #{count} tests"
16
+ exit!
17
+ end
18
+
19
+ trap('INT') { exit! }
20
+ t0 = Time.now
21
+ count.times { |i| run_test(i + 1) }
22
+ elapsed = Time.now - t0
23
+ puts format(
24
+ "Successfully ran %d tests in %f seconds (%f per test)",
25
+ count,
26
+ elapsed,
27
+ elapsed / count
28
+ )
@@ -2,10 +2,12 @@
2
2
 
3
3
  require 'bundler/setup'
4
4
  require 'polyphony'
5
+ require 'polyphony/core/channel'
5
6
 
6
7
  def echo(cin, cout)
7
8
  puts 'start echoer'
8
9
  while (msg = cin.receive)
10
+ puts "echoer received #{msg}"
9
11
  cout << "you said: #{msg}"
10
12
  end
11
13
  ensure
@@ -20,7 +22,7 @@ spin do
20
22
  puts 'start receiver'
21
23
  while (msg = chan2.receive)
22
24
  puts msg
23
- $main.resume if msg =~ /world/
25
+ $main.schedule if msg =~ /world/
24
26
  end
25
27
  ensure
26
28
  puts 'receiver stopped'
@@ -42,4 +44,4 @@ $main = spin do
42
44
  puts "done #{Time.now - t0}"
43
45
  end
44
46
 
45
- suspend
47
+ $main.await
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'bundler/setup'
4
4
  require 'polyphony'
5
+ require 'polyphony/core/sync'
5
6
 
6
7
  def loop_it(number, lock)
7
8
  loop do
@@ -13,7 +14,7 @@ def loop_it(number, lock)
13
14
  end
14
15
  end
15
16
 
16
- lock = Polyphony::Sync::Mutex.new
17
+ lock = Polyphony::Mutex.new
17
18
  spin { loop_it(1, lock) }
18
19
  spin { loop_it(2, lock) }
19
20
  spin { loop_it(3, lock) }
@@ -0,0 +1,86 @@
1
+ #include "polyphony.h"
2
+ #include "ring_buffer.h"
3
+
4
+ typedef struct event {
5
+ VALUE waiting_fiber;
6
+ } Event_t;
7
+
8
+ VALUE cEvent = Qnil;
9
+
10
+ static void Event_mark(void *ptr) {
11
+ Event_t *event = ptr;
12
+ rb_gc_mark(event->waiting_fiber);
13
+ }
14
+
15
+ static void Event_free(void *ptr) {
16
+ xfree(ptr);
17
+ }
18
+
19
+ static size_t Event_size(const void *ptr) {
20
+ return sizeof(Event_t);
21
+ }
22
+
23
+ static const rb_data_type_t Event_type = {
24
+ "Event",
25
+ {Event_mark, Event_free, Event_size,},
26
+ 0, 0, 0
27
+ };
28
+
29
+ static VALUE Event_allocate(VALUE klass) {
30
+ Event_t *event;
31
+
32
+ event = ALLOC(Event_t);
33
+ return TypedData_Wrap_Struct(klass, &Event_type, event);
34
+ }
35
+
36
+ #define GetEvent(obj, event) \
37
+ TypedData_Get_Struct((obj), Event_t, &Event_type, (event))
38
+
39
+ static VALUE Event_initialize(VALUE self) {
40
+ Event_t *event;
41
+ GetEvent(self, event);
42
+
43
+ event->waiting_fiber = Qnil;
44
+
45
+ return self;
46
+ }
47
+
48
+ VALUE Event_signal(int argc, VALUE *argv, VALUE self) {
49
+ VALUE value = argc > 0 ? argv[0] : Qnil;
50
+ Event_t *event;
51
+ GetEvent(self, event);
52
+
53
+ if (event->waiting_fiber != Qnil) {
54
+ Fiber_make_runnable(event->waiting_fiber, value);
55
+ event->waiting_fiber = Qnil;
56
+ }
57
+ return self;
58
+ }
59
+
60
+ VALUE Event_await(VALUE self) {
61
+ Event_t *event;
62
+ GetEvent(self, event);
63
+
64
+ if (event->waiting_fiber != Qnil)
65
+ rb_raise(rb_eRuntimeError, "Event is already awaited by another fiber");
66
+
67
+ VALUE agent = rb_ivar_get(rb_thread_current(), ID_ivar_agent);
68
+ event->waiting_fiber = rb_fiber_current();
69
+ VALUE switchpoint_result = LibevAgent_wait_event(agent, Qnil);
70
+ event->waiting_fiber = Qnil;
71
+
72
+ TEST_RESUME_EXCEPTION(switchpoint_result);
73
+ RB_GC_GUARD(agent);
74
+ RB_GC_GUARD(switchpoint_result);
75
+
76
+ return switchpoint_result;
77
+ }
78
+
79
+ void Init_Event() {
80
+ cEvent = rb_define_class_under(mPolyphony, "Event", rb_cData);
81
+ rb_define_alloc_func(cEvent, Event_allocate);
82
+
83
+ rb_define_method(cEvent, "initialize", Event_initialize, 0);
84
+ rb_define_method(cEvent, "await", Event_await, 0);
85
+ rb_define_method(cEvent, "signal", Event_signal, -1);
86
+ }
@@ -9,8 +9,6 @@ ID ID_trace_runnable;
9
9
  ID ID_trace_terminate;
10
10
  ID ID_trace_wait;
11
11
 
12
- VALUE cEvent = Qnil;
13
-
14
12
  VALUE SYM_dead;
15
13
  VALUE SYM_running;
16
14
  VALUE SYM_runnable;
@@ -35,9 +33,6 @@ static VALUE Fiber_safe_transfer(int argc, VALUE *argv, VALUE self) {
35
33
 
36
34
  inline VALUE Fiber_auto_watcher(VALUE self) {
37
35
  VALUE watcher;
38
- if (cEvent == Qnil) {
39
- cEvent = rb_const_get(mPolyphony, rb_intern("Event"));
40
- }
41
36
 
42
37
  watcher = rb_ivar_get(self, ID_ivar_auto_watcher);
43
38
  if (watcher == Qnil) {
@@ -4,6 +4,7 @@ void Init_Fiber();
4
4
  void Init_Polyphony();
5
5
  void Init_LibevAgent();
6
6
  void Init_Queue();
7
+ void Init_Event();
7
8
  void Init_Thread();
8
9
  void Init_Tracing();
9
10
 
@@ -13,6 +14,7 @@ void Init_polyphony_ext() {
13
14
  Init_Polyphony();
14
15
  Init_LibevAgent();
15
16
  Init_Queue();
17
+ Init_Event();
16
18
 
17
19
  Init_Fiber();
18
20
  Init_Thread();
@@ -139,6 +139,18 @@ VALUE Queue_shift_all(VALUE self) {
139
139
  return ring_buffer_shift_all(&queue->values);
140
140
  }
141
141
 
142
+ VALUE Queue_flush_waiters(VALUE self, VALUE value) {
143
+ Queue_t *queue;
144
+ GetQueue(self, queue);
145
+
146
+ while(1) {
147
+ VALUE fiber = ring_buffer_shift(&queue->shift_queue);
148
+ if (fiber == Qnil) return self;
149
+
150
+ Fiber_make_runnable(fiber, value);
151
+ }
152
+ }
153
+
142
154
  VALUE Queue_empty_p(VALUE self) {
143
155
  Queue_t *queue;
144
156
  GetQueue(self, queue);
@@ -146,6 +158,13 @@ VALUE Queue_empty_p(VALUE self) {
146
158
  return (queue->values.count == 0) ? Qtrue : Qfalse;
147
159
  }
148
160
 
161
+ VALUE Queue_size_m(VALUE self) {
162
+ Queue_t *queue;
163
+ GetQueue(self, queue);
164
+
165
+ return INT2NUM(queue->values.count);
166
+ }
167
+
149
168
  void Init_Queue() {
150
169
  cQueue = rb_define_class_under(mPolyphony, "Queue", rb_cData);
151
170
  rb_define_alloc_func(cQueue, Queue_allocate);
@@ -162,7 +181,7 @@ void Init_Queue() {
162
181
 
163
182
  rb_define_method(cQueue, "shift_each", Queue_shift_each, 0);
164
183
  rb_define_method(cQueue, "shift_all", Queue_shift_all, 0);
184
+ rb_define_method(cQueue, "flush_waiters", Queue_flush_waiters, 1);
165
185
  rb_define_method(cQueue, "empty?", Queue_empty_p, 0);
186
+ rb_define_method(cQueue, "size", Queue_size_m, 0);
166
187
  }
167
-
168
-
@@ -53,11 +53,9 @@ VALUE Thread_schedule_fiber(VALUE self, VALUE fiber, VALUE value) {
53
53
  if (rb_fiber_alive_p(fiber) != Qtrue) return self;
54
54
 
55
55
  FIBER_TRACE(3, SYM_fiber_schedule, fiber, value);
56
- // if fiber is already scheduled, just set the scheduled value, then return
57
56
  rb_ivar_set(fiber, ID_runnable_value, value);
58
- if (rb_ivar_get(fiber, ID_runnable) != Qnil) {
59
- return self;
60
- }
57
+ // if fiber is already scheduled, just set the scheduled value, then return
58
+ if (rb_ivar_get(fiber, ID_runnable) != Qnil) return self;
61
59
 
62
60
  queue = rb_ivar_get(self, ID_run_queue);
63
61
  Queue_push(queue, fiber);
@@ -23,7 +23,6 @@ require_relative './polyphony/core/global_api'
23
23
  require_relative './polyphony/core/resource_pool'
24
24
  require_relative './polyphony/net'
25
25
  require_relative './polyphony/adapters/process'
26
- require_relative './polyphony/event'
27
26
 
28
27
  # Main Polyphony API
29
28
  module Polyphony
@@ -5,42 +5,11 @@ require_relative './exceptions'
5
5
  module Polyphony
6
6
  # Implements a unidirectional communication channel along the lines of Go
7
7
  # (buffered) channels.
8
- class Channel
9
- def initialize
10
- @payload_queue = []
11
- @waiting_queue = []
12
- end
8
+ class Channel < Polyphony::Queue
9
+ alias_method :receive, :shift
13
10
 
14
11
  def close
15
- stop = Polyphony::MoveOn.new
16
- @waiting_queue.slice(0..-1).each { |f| f.schedule(stop) }
17
- end
18
-
19
- def <<(value)
20
- if @waiting_queue.empty?
21
- @payload_queue << value
22
- else
23
- @waiting_queue.shift&.schedule(value)
24
- end
25
- snooze
26
- end
27
-
28
- def receive
29
- Thread.current.agent.ref
30
- if @payload_queue.empty?
31
- @waiting_queue << Fiber.current
32
- suspend
33
- else
34
- receive_from_queue
35
- end
36
- ensure
37
- Thread.current.agent.unref
38
- end
39
-
40
- def receive_from_queue
41
- payload = @payload_queue.shift
42
- snooze
43
- payload
12
+ flush_waiters(Polyphony::MoveOn.new)
44
13
  end
45
14
  end
46
15
  end
@@ -10,13 +10,10 @@ module Polyphony
10
10
  # @param &block [Proc] allocator block
11
11
  def initialize(opts, &block)
12
12
  @allocator = block
13
-
14
- @stock = []
15
- @queue = []
16
- @acquired_resources = {}
17
-
18
13
  @limit = opts[:limit] || 4
19
14
  @size = 0
15
+ @stock = Polyphony::Queue.new
16
+ @acquired_resources = {}
20
17
  end
21
18
 
22
19
  def available
@@ -25,58 +22,17 @@ module Polyphony
25
22
 
26
23
  def acquire
27
24
  fiber = Fiber.current
28
- if @acquired_resources[fiber]
29
- yield @acquired_resources[fiber]
30
- else
31
- begin
32
- Thread.current.agent.ref
33
- resource = wait_for_resource
34
- return unless resource
35
-
36
- @acquired_resources[fiber] = resource
37
- yield resource
38
- ensure
39
- @acquired_resources.delete fiber
40
- Thread.current.agent.unref
41
- release(resource) if resource
42
- end
43
- end
44
- end
45
-
46
- def wait_for_resource
47
- fiber = Fiber.current
48
- @queue << fiber
49
- ready_resource = from_stock
50
- return ready_resource if ready_resource
25
+ return @acquired_resources[fiber] if @acquired_resources[fiber]
51
26
 
52
- suspend
27
+ add_to_stock if @size < @limit && @stock.empty?
28
+ resource = @stock.shift
29
+ @acquired_resources[fiber] = resource
30
+ yield resource
53
31
  ensure
54
- @queue.delete(fiber)
55
- end
56
-
57
- def release(resource)
58
- if resource.__discarded__
59
- @size -= 1
60
- elsif resource
61
- return_to_stock(resource)
62
- dequeue
63
- end
64
- end
65
-
66
- def dequeue
67
- return if @queue.empty? || @stock.empty?
68
-
69
- @queue.shift.schedule(@stock.shift)
32
+ @acquired_resources.delete(fiber)
33
+ @stock.push resource if resource
70
34
  end
71
-
72
- def return_to_stock(resource)
73
- @stock << resource
74
- end
75
-
76
- def from_stock
77
- @stock.shift || (@size < @limit && allocate)
78
- end
79
-
35
+
80
36
  def method_missing(sym, *args, &block)
81
37
  acquire { |r| r.send(sym, *args, &block) }
82
38
  end
@@ -85,33 +41,15 @@ module Polyphony
85
41
  true
86
42
  end
87
43
 
88
- # Extension to allow discarding of resources
89
- module ResourceExtensions
90
- def __discarded__
91
- @__discarded__
92
- end
93
-
94
- def __discard__
95
- @__discarded__ = true
96
- end
97
- end
98
-
99
44
  # Allocates a resource
100
45
  # @return [any] allocated resource
101
- def allocate
102
- @size += 1
103
- @allocator.().tap { |r| r.extend ResourceExtensions }
104
- end
105
-
106
- def <<(resource)
46
+ def add_to_stock
107
47
  @size += 1
108
- resource.extend ResourceExtensions
109
- @stock << resource
110
- dequeue
48
+ @stock << @allocator.call
111
49
  end
112
50
 
113
51
  def preheat!
114
- (@limit - @size).times { @stock << allocate }
52
+ add_to_stock while @size < @limit
115
53
  end
116
54
  end
117
55
  end
@@ -4,18 +4,21 @@ module Polyphony
4
4
  # Implements mutex lock for synchronizing access to a shared resource
5
5
  class Mutex
6
6
  def initialize
7
- @waiting_fibers = Polyphony::Queue.new
7
+ @store = Queue.new
8
+ @store << :token
8
9
  end
9
10
 
10
11
  def synchronize
11
- fiber = Fiber.current
12
- @waiting_fibers << fiber
13
- suspend if @waiting_fibers.size > 1
14
- yield
15
- ensure
16
- @waiting_fibers.delete(fiber)
17
- @waiting_fibers.first&.schedule
18
- snooze
12
+ return yield if @holding_fiber == Fiber.current
13
+
14
+ begin
15
+ token = @store.shift
16
+ @holding_fiber = Fiber.current
17
+ yield
18
+ ensure
19
+ @holding_fiber = nil
20
+ @store << token
21
+ end
19
22
  end
20
23
  end
21
24
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polyphony
4
- VERSION = '0.43.8'
4
+ VERSION = '0.43.9'
5
5
  end
@@ -34,6 +34,7 @@ class EventTest < MiniTest::Test
34
34
  }
35
35
  }
36
36
  snooze
37
+
37
38
  t = Thread.new do
38
39
  orig_sleep 0.001
39
40
  3.times { a.signal }
@@ -109,4 +109,24 @@ class QueueTest < MiniTest::Test
109
109
  @queue << :foo
110
110
  assert_nil f1.await
111
111
  end
112
+
113
+ def test_queue_size
114
+ assert_equal 0, @queue.size
115
+
116
+ @queue.push 1
117
+
118
+ assert_equal 1, @queue.size
119
+
120
+ @queue.push 2
121
+
122
+ assert_equal 2, @queue.size
123
+
124
+ @queue.shift
125
+
126
+ assert_equal 1, @queue.size
127
+
128
+ @queue.shift
129
+
130
+ assert_equal 0, @queue.size
131
+ end
112
132
  end
@@ -37,49 +37,6 @@ class ResourcePoolTest < MiniTest::Test
37
37
  assert_equal 2, pool.size
38
38
  end
39
39
 
40
- def test_discard
41
- resources = [+'a', +'b']
42
- pool = Polyphony::ResourcePool.new(limit: 2) { resources.shift }
43
-
44
- results = []
45
- 4.times {
46
- spin {
47
- snooze
48
- pool.acquire { |resource|
49
- results << resource
50
- resource.__discard__ if resource == 'b'
51
- snooze
52
- }
53
- }
54
- }
55
- 6.times { snooze }
56
-
57
- assert_equal ['a', 'b', 'a', 'a'], results
58
- assert_equal 1, pool.size
59
- end
60
-
61
- def test_add
62
- resources = [+'a', +'b']
63
- pool = Polyphony::ResourcePool.new(limit: 2) { resources.shift }
64
-
65
- pool << +'c'
66
-
67
- results = []
68
- 4.times {
69
- spin {
70
- snooze
71
- pool.acquire { |resource|
72
- results << resource
73
- resource.__discard__ if resource == 'b'
74
- snooze
75
- }
76
- }
77
- }
78
- 6.times { snooze }
79
-
80
- assert_equal ['c', 'a', 'c', 'a'], results
81
- end
82
-
83
40
  def test_single_resource_limit
84
41
  resources = [+'a', +'b']
85
42
  pool = Polyphony::ResourcePool.new(limit: 1) { resources.shift }
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.43.8
4
+ version: 0.43.9
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-07-21 00:00:00.000000000 Z
11
+ date: 2020-07-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -241,6 +241,7 @@ files:
241
241
  - Rakefile
242
242
  - TODO.md
243
243
  - bin/polyphony-debug
244
+ - bin/stress.rb
244
245
  - docs/_config.yml
245
246
  - docs/_includes/head.html
246
247
  - docs/_includes/title.html
@@ -388,6 +389,7 @@ files:
388
389
  - ext/libev/ev_win32.c
389
390
  - ext/libev/ev_wrap.h
390
391
  - ext/libev/test_libev_win32.c
392
+ - ext/polyphony/event.c
391
393
  - ext/polyphony/extconf.rb
392
394
  - ext/polyphony/fiber.c
393
395
  - ext/polyphony/libev.c
@@ -415,7 +417,6 @@ files:
415
417
  - lib/polyphony/core/sync.rb
416
418
  - lib/polyphony/core/thread_pool.rb
417
419
  - lib/polyphony/core/throttler.rb
418
- - lib/polyphony/event.rb
419
420
  - lib/polyphony/extensions/core.rb
420
421
  - lib/polyphony/extensions/fiber.rb
421
422
  - lib/polyphony/extensions/io.rb
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Polyphony
4
- # Event watcher for thread-safe synchronisation
5
- class Event
6
- def await
7
- @fiber = Fiber.current
8
- Thread.current.agent.wait_event(true)
9
- end
10
-
11
- def signal(value = nil)
12
- @fiber&.schedule(value)
13
- ensure
14
- @fiber = nil
15
- end
16
- end
17
- end