polyphony 0.79 → 0.80
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/Gemfile.lock +2 -1
- data/examples/core/zlib_stream.rb +15 -0
- data/ext/polyphony/backend_common.c +2 -1
- data/ext/polyphony/backend_common.h +7 -2
- data/lib/polyphony/adapters/fs.rb +4 -0
- data/lib/polyphony/adapters/process.rb +14 -1
- data/lib/polyphony/adapters/redis.rb +28 -0
- data/lib/polyphony/adapters/sequel.rb +19 -1
- data/lib/polyphony/core/debug.rb +129 -72
- data/lib/polyphony/core/exceptions.rb +21 -6
- data/lib/polyphony/core/global_api.rb +228 -73
- data/lib/polyphony/core/resource_pool.rb +65 -20
- data/lib/polyphony/core/sync.rb +57 -12
- data/lib/polyphony/core/thread_pool.rb +42 -5
- data/lib/polyphony/core/throttler.rb +21 -5
- data/lib/polyphony/core/timer.rb +125 -1
- data/lib/polyphony/extensions/exception.rb +36 -6
- data/lib/polyphony/extensions/fiber.rb +238 -57
- data/lib/polyphony/extensions/io.rb +4 -2
- data/lib/polyphony/extensions/kernel.rb +9 -4
- data/lib/polyphony/extensions/object.rb +8 -0
- data/lib/polyphony/extensions/openssl.rb +3 -1
- data/lib/polyphony/extensions/socket.rb +458 -39
- data/lib/polyphony/extensions/thread.rb +108 -43
- data/lib/polyphony/extensions/timeout.rb +12 -1
- data/lib/polyphony/extensions.rb +1 -0
- data/lib/polyphony/net.rb +59 -0
- data/lib/polyphony/version.rb +1 -1
- data/lib/polyphony.rb +0 -2
- data/test/test_backend.rb +6 -2
- data/test/test_global_api.rb +0 -23
- data/test/test_resource_pool.rb +1 -1
- data/test/test_throttler.rb +0 -6
- data/test/test_trace.rb +87 -0
- metadata +9 -8
- data/lib/polyphony/core/channel.rb +0 -15
@@ -5,8 +5,11 @@ require_relative '../core/exceptions'
|
|
5
5
|
# Thread extensions
|
6
6
|
class ::Thread
|
7
7
|
attr_reader :main_fiber, :result
|
8
|
+
attr_accessor :backend
|
8
9
|
|
9
10
|
alias_method :orig_initialize, :initialize
|
11
|
+
|
12
|
+
# Initializes the thread.
|
10
13
|
def initialize(*args, &block)
|
11
14
|
@join_wait_queue = []
|
12
15
|
@finalization_mutex = Mutex.new
|
@@ -15,53 +18,30 @@ class ::Thread
|
|
15
18
|
orig_initialize { execute }
|
16
19
|
end
|
17
20
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
raise_error = false
|
22
|
-
begin
|
23
|
-
@backend = Polyphony::Backend.new
|
24
|
-
rescue Exception => e
|
25
|
-
raise_error = true
|
26
|
-
raise e
|
27
|
-
end
|
28
|
-
setup
|
29
|
-
@ready = true
|
30
|
-
result = @block.(*@args)
|
31
|
-
rescue Polyphony::MoveOn, Polyphony::Terminate => e
|
32
|
-
result = e.value
|
33
|
-
rescue Exception => e
|
34
|
-
raise_error ? (raise e) : (result = e)
|
35
|
-
ensure
|
36
|
-
@ready = true
|
37
|
-
finalize(result)
|
38
|
-
end
|
39
|
-
|
40
|
-
attr_accessor :backend
|
41
|
-
|
21
|
+
# Sets up the thread and its main fiber.
|
22
|
+
#
|
23
|
+
# @return [void]
|
42
24
|
def setup
|
43
25
|
@main_fiber = Fiber.current
|
44
26
|
@main_fiber.setup_main_fiber
|
45
27
|
setup_fiber_scheduling
|
46
28
|
end
|
47
29
|
|
48
|
-
def finalize(result)
|
49
|
-
unless Fiber.current.children.empty?
|
50
|
-
Fiber.current.shutdown_all_children
|
51
|
-
end
|
52
|
-
@finalization_mutex.synchronize do
|
53
|
-
@terminated = true
|
54
|
-
@result = result
|
55
|
-
signal_waiters(result)
|
56
|
-
end
|
57
|
-
@backend&.finalize
|
58
|
-
end
|
59
|
-
|
60
|
-
def signal_waiters(result)
|
61
|
-
@join_wait_queue.each { |w| w.signal(result) }
|
62
|
-
end
|
63
|
-
|
64
30
|
alias_method :orig_join, :join
|
31
|
+
|
32
|
+
# call-seq:
|
33
|
+
# thread.join -> result
|
34
|
+
# thread.join(timeout) -> result
|
35
|
+
# thread.await -> result
|
36
|
+
# thread.await(timeout) -> result
|
37
|
+
#
|
38
|
+
# Waits for the thread to terminate and returns its return value. If the
|
39
|
+
# thread terminated with an uncaught exception, it is propagated to the
|
40
|
+
# waiting fiber. If a timeout interval is specified, the thread will be
|
41
|
+
# terminated without propagating the timeout exception.
|
42
|
+
#
|
43
|
+
# @param timeout [Number] timeout interval
|
44
|
+
# @return [any] thread's return value
|
65
45
|
def join(timeout = nil)
|
66
46
|
watcher = Fiber.current.auto_watcher
|
67
47
|
|
@@ -77,6 +57,16 @@ class ::Thread
|
|
77
57
|
alias_method :await, :join
|
78
58
|
|
79
59
|
alias_method :orig_raise, :raise
|
60
|
+
|
61
|
+
# call-seq:
|
62
|
+
# thread.raise
|
63
|
+
# thread.raise(exception_class)
|
64
|
+
# thread.raise(exception_instance)
|
65
|
+
#
|
66
|
+
# Raises an exception in the context of the thread. If no exception is given,
|
67
|
+
# a `RuntimeError` is raised.
|
68
|
+
#
|
69
|
+
# @param error [Exception, Class, nil] exception spec
|
80
70
|
def raise(error = nil)
|
81
71
|
Thread.pass until @main_fiber
|
82
72
|
error = RuntimeError.new if error.nil?
|
@@ -88,13 +78,22 @@ class ::Thread
|
|
88
78
|
end
|
89
79
|
|
90
80
|
alias_method :orig_kill, :kill
|
81
|
+
|
82
|
+
# Terminates the thread.
|
83
|
+
#
|
84
|
+
# @return [Thread] self
|
91
85
|
def kill
|
92
|
-
return if @terminated
|
86
|
+
return self if @terminated
|
93
87
|
|
94
88
|
raise Polyphony::Terminate
|
89
|
+
self
|
95
90
|
end
|
96
91
|
|
97
92
|
alias_method :orig_inspect, :inspect
|
93
|
+
|
94
|
+
# Returns a string representation of the thread for debugging purposes.
|
95
|
+
#
|
96
|
+
# @return [String] string representation
|
98
97
|
def inspect
|
99
98
|
return orig_inspect if self == Thread.main
|
100
99
|
|
@@ -103,20 +102,86 @@ class ::Thread
|
|
103
102
|
end
|
104
103
|
alias_method :to_s, :inspect
|
105
104
|
|
105
|
+
# Returns the source location of the thread's block.
|
106
|
+
#
|
107
|
+
# @return [String] source location
|
106
108
|
def location
|
107
109
|
@block.source_location.join(':')
|
108
110
|
end
|
109
111
|
|
110
|
-
|
111
|
-
|
112
|
+
# Sends a message to the thread's main fiber.
|
113
|
+
#
|
114
|
+
# @param msg [any] message
|
115
|
+
# @return [Fiber] main fiber
|
116
|
+
def <<(msg)
|
117
|
+
main_fiber << msg
|
112
118
|
end
|
113
119
|
alias_method :send, :<<
|
114
120
|
|
121
|
+
# Sets the idle GC period for the thread's backend.
|
122
|
+
#
|
123
|
+
# @param period [Number] GC period in seconds
|
124
|
+
# @return [Number] GC period
|
115
125
|
def idle_gc_period=(period)
|
116
126
|
backend.idle_gc_period = period
|
117
127
|
end
|
118
128
|
|
129
|
+
# Sets the idle handler for the thread's backend.
|
130
|
+
#
|
131
|
+
# @param &block [Proc] idle handler
|
132
|
+
# @return [Proc] idle handler
|
119
133
|
def on_idle(&block)
|
120
134
|
backend.idle_proc = block
|
121
135
|
end
|
136
|
+
|
137
|
+
private
|
138
|
+
|
139
|
+
# Runs the thread's block, handling any uncaught exceptions.
|
140
|
+
#
|
141
|
+
# @return [void]
|
142
|
+
def execute
|
143
|
+
# backend must be created in the context of the new thread, therefore it
|
144
|
+
# cannot be created in Thread#initialize
|
145
|
+
raise_error = false
|
146
|
+
begin
|
147
|
+
@backend = Polyphony::Backend.new
|
148
|
+
rescue Exception => e
|
149
|
+
raise_error = true
|
150
|
+
raise e
|
151
|
+
end
|
152
|
+
setup
|
153
|
+
@ready = true
|
154
|
+
result = @block.(*@args)
|
155
|
+
rescue Polyphony::MoveOn, Polyphony::Terminate => e
|
156
|
+
result = e.value
|
157
|
+
rescue Exception => e
|
158
|
+
raise_error ? (raise e) : (result = e)
|
159
|
+
ensure
|
160
|
+
@ready = true
|
161
|
+
finalize(result)
|
162
|
+
end
|
163
|
+
|
164
|
+
# Finalizes the thread.
|
165
|
+
#
|
166
|
+
# @param result [any] thread's return value
|
167
|
+
# @return [void]
|
168
|
+
def finalize(result)
|
169
|
+
unless Fiber.current.children.empty?
|
170
|
+
Fiber.current.shutdown_all_children
|
171
|
+
end
|
172
|
+
@finalization_mutex.synchronize do
|
173
|
+
@terminated = true
|
174
|
+
@result = result
|
175
|
+
signal_waiters(result)
|
176
|
+
end
|
177
|
+
@backend&.finalize
|
178
|
+
end
|
179
|
+
|
180
|
+
# Signals all fibers waiting for the thread to terminate.
|
181
|
+
#
|
182
|
+
# @param result [any] thread's return value
|
183
|
+
# @return [void]
|
184
|
+
def signal_waiters(result)
|
185
|
+
@join_wait_queue.each { |w| w.signal(result) }
|
186
|
+
end
|
122
187
|
end
|
@@ -2,8 +2,19 @@
|
|
2
2
|
|
3
3
|
require 'timeout'
|
4
4
|
|
5
|
-
#
|
5
|
+
# Timeout extensions
|
6
6
|
module ::Timeout
|
7
|
+
|
8
|
+
# Sets a timeout for the given block. This method provides an equivalent API
|
9
|
+
# to the stock Timeout API provided by Ruby. In case of a timeout, the block
|
10
|
+
# will be interrupted and an exception will be raised according to the given
|
11
|
+
# arguments.
|
12
|
+
#
|
13
|
+
# @param sec [Number] timeout period in seconds
|
14
|
+
# @param klass [Class] exception class
|
15
|
+
# @param message [String] exception message
|
16
|
+
# @param &block [Proc] code to run
|
17
|
+
# @return [any] block's return value
|
7
18
|
def self.timeout(sec, klass = Timeout::Error, message = 'execution expired', &block)
|
8
19
|
cancel_after(sec, with_exception: [klass, message], &block)
|
9
20
|
end
|
data/lib/polyphony/extensions.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require_relative './extensions/exception'
|
4
4
|
require_relative './extensions/fiber'
|
5
5
|
require_relative './extensions/io'
|
6
|
+
require_relative './extensions/object'
|
6
7
|
require_relative './extensions/kernel'
|
7
8
|
require_relative './extensions/process'
|
8
9
|
require_relative './extensions/thread'
|
data/lib/polyphony/net.rb
CHANGED
@@ -4,9 +4,25 @@ require_relative './extensions/socket'
|
|
4
4
|
require_relative './extensions/openssl'
|
5
5
|
|
6
6
|
module Polyphony
|
7
|
+
|
7
8
|
# A more elegant networking API
|
8
9
|
module Net
|
9
10
|
class << self
|
11
|
+
|
12
|
+
# call-seq:
|
13
|
+
# Polyphony::Net.tcp_connect(host, port) -> TCPSocket
|
14
|
+
# Polyphony::Net.tcp_connect(host, port, secure: true) -> SSLSocket
|
15
|
+
# Polyphony::Net.tcp_connect(host, port, secure_context: ctx) -> SSLSocket
|
16
|
+
#
|
17
|
+
# Create a TCP connection to the given host and port, returning the new
|
18
|
+
# socket. If `opts[:secure]` is true, or if an SSL context is given in
|
19
|
+
# `opts[:secure_context]`, a TLS handshake is performed, and an SSLSocket
|
20
|
+
# is returned.
|
21
|
+
#
|
22
|
+
# @param host [String] hostname
|
23
|
+
# @param port [Integer] port number
|
24
|
+
# @param opts [Hash] connection options
|
25
|
+
# @return [TCPSocket, SSLSocket] connected socket
|
10
26
|
def tcp_connect(host, port, opts = {})
|
11
27
|
socket = TCPSocket.new(host, port)
|
12
28
|
if opts[:secure_context] || opts[:secure]
|
@@ -16,6 +32,15 @@ module Polyphony
|
|
16
32
|
end
|
17
33
|
end
|
18
34
|
|
35
|
+
# Creates a server socket for accepting incoming connection on the given
|
36
|
+
# host and port. If `opts[:secure]` is true, or if an SSL context is given
|
37
|
+
# in `opts[:secure_context]`, a TLS handshake is performed, and an
|
38
|
+
# SSLSocket is returned.
|
39
|
+
#
|
40
|
+
# @param host [String] hostname
|
41
|
+
# @param port [Integer] port number
|
42
|
+
# @param opts [Hash] connection options
|
43
|
+
# @return [TCPServer, SSLServer] listening socket
|
19
44
|
def tcp_listen(host = nil, port = nil, opts = {})
|
20
45
|
host ||= '0.0.0.0'
|
21
46
|
raise 'Port number not specified' unless port
|
@@ -28,6 +53,14 @@ module Polyphony
|
|
28
53
|
end
|
29
54
|
end
|
30
55
|
|
56
|
+
private
|
57
|
+
|
58
|
+
# Creates a listening `Socket` instance.
|
59
|
+
#
|
60
|
+
# @param host [String] hostname
|
61
|
+
# @param port [Integer] port number
|
62
|
+
# @param opts [Hash] connection options
|
63
|
+
# @return [Socket] listening socket
|
31
64
|
def listening_socket_from_options(host, port, opts)
|
32
65
|
::Socket.new(:INET, :STREAM).tap do |s|
|
33
66
|
s.reuse_addr if opts[:reuse_addr]
|
@@ -39,6 +72,12 @@ module Polyphony
|
|
39
72
|
end
|
40
73
|
end
|
41
74
|
|
75
|
+
# Wraps the given socket with a SSLSocket and performs a TLS handshake.
|
76
|
+
#
|
77
|
+
# @param socket [Socket] plain socket
|
78
|
+
# @param context [SSLContext, nil] SSL context
|
79
|
+
# @param opts [Hash] connection options
|
80
|
+
# @return [SSLSocket] SSL socket
|
42
81
|
def secure_socket(socket, context, opts)
|
43
82
|
context ||= OpenSSL::SSL::SSLContext.new
|
44
83
|
setup_alpn(context, opts[:alpn_protocols]) if opts[:alpn_protocols]
|
@@ -51,6 +90,11 @@ module Polyphony
|
|
51
90
|
end
|
52
91
|
end
|
53
92
|
|
93
|
+
# Wraps the given socket with an SSLSocket.
|
94
|
+
#
|
95
|
+
# @param socket [Socket] plain socket
|
96
|
+
# @param context [SSLContext] SSL context
|
97
|
+
# @return [SSLSocket] SSL socket
|
54
98
|
def secure_socket_wrapper(socket, context)
|
55
99
|
if context
|
56
100
|
OpenSSL::SSL::SSLSocket.new(socket, context)
|
@@ -59,11 +103,26 @@ module Polyphony
|
|
59
103
|
end
|
60
104
|
end
|
61
105
|
|
106
|
+
# Wraps the given socket with an SSLServer, setting up ALPN from the given
|
107
|
+
# options.
|
108
|
+
#
|
109
|
+
# @param socket [Socket] plain socket
|
110
|
+
# @param context [SSLContext] SSL context
|
111
|
+
# @param opts [Hash] options
|
112
|
+
# @return [SSLServer] SSL socket
|
62
113
|
def secure_server(socket, context, opts)
|
63
114
|
setup_alpn(context, opts[:alpn_protocols]) if opts[:alpn_protocols]
|
64
115
|
OpenSSL::SSL::SSLServer.new(socket, context)
|
65
116
|
end
|
66
117
|
|
118
|
+
# Sets up ALPN negotiation for the given context. The ALPN handler for the
|
119
|
+
# context will select the first protocol from the list given by the client
|
120
|
+
# that appears in the list of given protocols, according to the specified
|
121
|
+
# order.
|
122
|
+
#
|
123
|
+
# @param context [SSLContext] SSL context
|
124
|
+
# @param protocols [Array] array of supported protocols
|
125
|
+
# @return [void]
|
67
126
|
def setup_alpn(context, protocols)
|
68
127
|
context.alpn_protocols = protocols
|
69
128
|
context.alpn_select_cb = lambda do |peer_protocols|
|
data/lib/polyphony/version.rb
CHANGED
data/lib/polyphony.rb
CHANGED
@@ -9,7 +9,6 @@ Thread.current.backend = Polyphony::Backend.new
|
|
9
9
|
|
10
10
|
require_relative './polyphony/extensions'
|
11
11
|
require_relative './polyphony/core/exceptions'
|
12
|
-
require_relative './polyphony/core/global_api'
|
13
12
|
require_relative './polyphony/core/resource_pool'
|
14
13
|
require_relative './polyphony/core/sync'
|
15
14
|
require_relative './polyphony/core/timer'
|
@@ -53,7 +52,6 @@ module Polyphony
|
|
53
52
|
|
54
53
|
def run_forked_block(&block)
|
55
54
|
Thread.current.setup
|
56
|
-
Fiber.current.setup_main_fiber
|
57
55
|
Thread.current.backend.post_fork
|
58
56
|
|
59
57
|
install_terminating_signal_handlers
|
data/test/test_backend.rb
CHANGED
@@ -191,7 +191,9 @@ class BackendTest < MiniTest::Test
|
|
191
191
|
Net = Polyphony::Net
|
192
192
|
|
193
193
|
def test_accept
|
194
|
-
server = Net.
|
194
|
+
server = Net.send(
|
195
|
+
:listening_socket_from_options, '127.0.0.1', 1234, reuse_addr: true
|
196
|
+
)
|
195
197
|
|
196
198
|
clients = []
|
197
199
|
server_fiber = spin_loop do
|
@@ -218,7 +220,9 @@ class BackendTest < MiniTest::Test
|
|
218
220
|
end
|
219
221
|
|
220
222
|
def test_accept_loop
|
221
|
-
server = Net.
|
223
|
+
server = Net.send(
|
224
|
+
:listening_socket_from_options, '127.0.0.1', 1235, reuse_addr: true
|
225
|
+
)
|
222
226
|
|
223
227
|
clients = []
|
224
228
|
server_fiber = spin do
|
data/test/test_global_api.rb
CHANGED
@@ -140,17 +140,6 @@ class MoveOnAfterTest < MiniTest::Test
|
|
140
140
|
assert_in_range 0.014..0.02, t1 - t0 if IS_LINUX
|
141
141
|
end
|
142
142
|
|
143
|
-
def test_move_on_after_without_block
|
144
|
-
t0 = Time.now
|
145
|
-
f = move_on_after(0.01, with_value: 'foo')
|
146
|
-
assert_kind_of Fiber, f
|
147
|
-
assert_equal Fiber.current, f.parent
|
148
|
-
v = sleep 1
|
149
|
-
t1 = Time.now
|
150
|
-
assert t1 - t0 < 0.1
|
151
|
-
assert_equal 'foo', v
|
152
|
-
end
|
153
|
-
|
154
143
|
def test_nested_move_on_after
|
155
144
|
skip unless IS_LINUX
|
156
145
|
|
@@ -190,18 +179,6 @@ class CancelAfterTest < MiniTest::Test
|
|
190
179
|
assert t1 - t0 < 0.1
|
191
180
|
end
|
192
181
|
|
193
|
-
def test_cancel_after_without_block
|
194
|
-
t0 = Time.now
|
195
|
-
f = cancel_after(0.01)
|
196
|
-
assert_kind_of Fiber, f
|
197
|
-
assert_equal Fiber.current, f.parent
|
198
|
-
assert_raises Polyphony::Cancel do
|
199
|
-
sleep 1
|
200
|
-
end
|
201
|
-
t1 = Time.now
|
202
|
-
assert t1 - t0 < 0.1
|
203
|
-
end
|
204
|
-
|
205
182
|
def test_cancel_after_with_reset
|
206
183
|
t0 = Time.now
|
207
184
|
cancel_after(0.01) do |f|
|
data/test/test_resource_pool.rb
CHANGED
data/test/test_throttler.rb
CHANGED
@@ -11,8 +11,6 @@ class ThrottlerTest < MiniTest::Test
|
|
11
11
|
sleep 0.2
|
12
12
|
f.stop
|
13
13
|
assert_in_range 1..4, buffer.size if IS_LINUX
|
14
|
-
ensure
|
15
|
-
t.stop
|
16
14
|
end
|
17
15
|
|
18
16
|
def test_throttler_with_hash_of_rate
|
@@ -24,8 +22,6 @@ class ThrottlerTest < MiniTest::Test
|
|
24
22
|
sleep 0.25
|
25
23
|
f.stop
|
26
24
|
assert_in_range 4..6, buffer.size if IS_LINUX
|
27
|
-
ensure
|
28
|
-
t.stop
|
29
25
|
end
|
30
26
|
|
31
27
|
def test_throttler_with_hash_of_interval
|
@@ -35,8 +31,6 @@ class ThrottlerTest < MiniTest::Test
|
|
35
31
|
sleep 0.02
|
36
32
|
f.stop
|
37
33
|
assert_in_range 2..4, buffer.size if IS_LINUX
|
38
|
-
ensure
|
39
|
-
t.stop
|
40
34
|
end
|
41
35
|
|
42
36
|
def test_throttler_with_invalid_argument
|
data/test/test_trace.rb
CHANGED
@@ -130,4 +130,91 @@ class TraceTest < MiniTest::Test
|
|
130
130
|
ensure
|
131
131
|
Thread.backend.trace_proc = nil
|
132
132
|
end
|
133
|
+
|
134
|
+
def test_event_firehose_with_threaded_receiver
|
135
|
+
buffer = []
|
136
|
+
this = Fiber.current
|
137
|
+
receiver = Thread.new {
|
138
|
+
this << :ok
|
139
|
+
loop {
|
140
|
+
e = receive
|
141
|
+
break if e == :stop
|
142
|
+
buffer << e
|
143
|
+
}
|
144
|
+
}
|
145
|
+
receive
|
146
|
+
|
147
|
+
Polyphony::Trace.start_event_firehose { |e| receiver << e }
|
148
|
+
|
149
|
+
f1 = spin(:f1) do
|
150
|
+
receive
|
151
|
+
end
|
152
|
+
|
153
|
+
f1 << :foo
|
154
|
+
f1.await
|
155
|
+
|
156
|
+
Thread.backend.trace_proc = nil
|
157
|
+
receiver << :stop
|
158
|
+
receiver.await
|
159
|
+
|
160
|
+
buffer.each { |e| e.delete(:stamp); e.delete(:caller) }
|
161
|
+
|
162
|
+
main = Fiber.current
|
163
|
+
assert_equal(
|
164
|
+
[
|
165
|
+
{ event: :spin, fiber: f1, source_fiber: main },
|
166
|
+
{ event: :schedule, fiber: f1, value: nil, source_fiber: main },
|
167
|
+
{ event: :block, fiber: main },
|
168
|
+
{ event: :unblock, fiber: f1, value: nil },
|
169
|
+
{ event: :schedule, fiber: f1, value: nil, source_fiber: f1 },
|
170
|
+
{ event: :block, fiber: f1, },
|
171
|
+
{ event: :enter_poll },
|
172
|
+
{ event: :leave_poll },
|
173
|
+
{ event: :unblock, fiber: f1, value: nil },
|
174
|
+
{ event: :terminate, fiber: f1, value: :foo },
|
175
|
+
{ event: :schedule, fiber: main, value: nil, source_fiber: f1 },
|
176
|
+
{ event: :block, fiber: f1 },
|
177
|
+
{ event: :unblock, fiber: main, value: nil }
|
178
|
+
], buffer
|
179
|
+
)
|
180
|
+
ensure
|
181
|
+
Thread.backend.trace_proc = nil
|
182
|
+
end
|
183
|
+
|
184
|
+
# def test_event_firehose_with_reentrancy
|
185
|
+
# buffer = []
|
186
|
+
# Polyphony::Trace.start_event_firehose { |e| buffer << e }
|
187
|
+
|
188
|
+
# f1 = spin(:f1) do
|
189
|
+
# receive
|
190
|
+
# end
|
191
|
+
|
192
|
+
# f1 << :foo
|
193
|
+
# f1.await
|
194
|
+
|
195
|
+
# Thread.backend.trace_proc = nil
|
196
|
+
# buffer.each { |e| e.delete(:stamp); e.delete(:caller) }
|
197
|
+
|
198
|
+
# main = Fiber.current
|
199
|
+
# assert_equal(
|
200
|
+
# [
|
201
|
+
# { event: :spin, fiber: f1, source_fiber: main },
|
202
|
+
# { event: :schedule, fiber: f1, value: nil, source_fiber: main },
|
203
|
+
# { event: :block, fiber: main },
|
204
|
+
# { event: :unblock, fiber: f1, value: nil },
|
205
|
+
# { event: :schedule, fiber: f1, value: nil, source_fiber: f1 },
|
206
|
+
# { event: :block, fiber: f1, },
|
207
|
+
# { event: :enter_poll },
|
208
|
+
# { event: :leave_poll },
|
209
|
+
# { event: :unblock, fiber: f1, value: nil },
|
210
|
+
# { event: :terminate, fiber: f1, value: :foo },
|
211
|
+
# { event: :schedule, fiber: main, value: nil, source_fiber: f1 },
|
212
|
+
# { event: :block, fiber: f1 },
|
213
|
+
# { event: :unblock, fiber: main, value: nil }
|
214
|
+
# ], buffer
|
215
|
+
# )
|
216
|
+
# ensure
|
217
|
+
# Thread.backend.trace_proc = nil
|
218
|
+
# end
|
219
|
+
|
133
220
|
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.
|
4
|
+
version: '0.80'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-02-
|
11
|
+
date: 2022-02-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -136,7 +136,7 @@ dependencies:
|
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: 1.1.4
|
139
|
-
description:
|
139
|
+
description:
|
140
140
|
email: sharon@noteflakes.com
|
141
141
|
executables: []
|
142
142
|
extensions:
|
@@ -249,6 +249,7 @@ files:
|
|
249
249
|
- examples/core/trap2.rb
|
250
250
|
- examples/core/using-a-mutex.rb
|
251
251
|
- examples/core/worker-thread.rb
|
252
|
+
- examples/core/zlib_stream.rb
|
252
253
|
- examples/io/backticks.rb
|
253
254
|
- examples/io/echo_client.rb
|
254
255
|
- examples/io/echo_client_from_stdin.rb
|
@@ -358,7 +359,6 @@ files:
|
|
358
359
|
- lib/polyphony/adapters/readline.rb
|
359
360
|
- lib/polyphony/adapters/redis.rb
|
360
361
|
- lib/polyphony/adapters/sequel.rb
|
361
|
-
- lib/polyphony/core/channel.rb
|
362
362
|
- lib/polyphony/core/debug.rb
|
363
363
|
- lib/polyphony/core/exceptions.rb
|
364
364
|
- lib/polyphony/core/global_api.rb
|
@@ -373,6 +373,7 @@ files:
|
|
373
373
|
- lib/polyphony/extensions/fiber.rb
|
374
374
|
- lib/polyphony/extensions/io.rb
|
375
375
|
- lib/polyphony/extensions/kernel.rb
|
376
|
+
- lib/polyphony/extensions/object.rb
|
376
377
|
- lib/polyphony/extensions/openssl.rb
|
377
378
|
- lib/polyphony/extensions/process.rb
|
378
379
|
- lib/polyphony/extensions/socket.rb
|
@@ -415,7 +416,7 @@ metadata:
|
|
415
416
|
documentation_uri: https://digital-fabric.github.io/polyphony/
|
416
417
|
homepage_uri: https://digital-fabric.github.io/polyphony/
|
417
418
|
changelog_uri: https://github.com/digital-fabric/polyphony/blob/master/CHANGELOG.md
|
418
|
-
post_install_message:
|
419
|
+
post_install_message:
|
419
420
|
rdoc_options:
|
420
421
|
- "--title"
|
421
422
|
- polyphony
|
@@ -434,8 +435,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
434
435
|
- !ruby/object:Gem::Version
|
435
436
|
version: '0'
|
436
437
|
requirements: []
|
437
|
-
rubygems_version: 3.
|
438
|
-
signing_key:
|
438
|
+
rubygems_version: 3.1.6
|
439
|
+
signing_key:
|
439
440
|
specification_version: 4
|
440
441
|
summary: Fine grained concurrency for Ruby
|
441
442
|
test_files: []
|
@@ -1,15 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative './exceptions'
|
4
|
-
|
5
|
-
module Polyphony
|
6
|
-
# Implements a unidirectional communication channel along the lines of Go
|
7
|
-
# (buffered) channels.
|
8
|
-
class Channel < Polyphony::Queue
|
9
|
-
alias_method :receive, :shift
|
10
|
-
|
11
|
-
def close
|
12
|
-
flush_waiters(Polyphony::MoveOn.new)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|