polyphony 0.79 → 0.80
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 +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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cf3658689c8bb7614624ad75492b16fc31401c5c8ee37cd510bb4aab1c9d1449
|
4
|
+
data.tar.gz: 5e2520d758db10e9dfe8022d6a85df61e1702f2e1e6560a95968e37b6f4f6e82
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7bd42d8fed28064941281c0e010f86a7ff7fff56e28c8e8190c8bc5c68eebd26a8d568e03ce20120db64684a036afb8d9b8586668c59f39fadebdaba2624ba75
|
7
|
+
data.tar.gz: cd91d0394a0642fbb43d59cc3ba6a3100377be955f1cabeebc051f8f6159d6fb0e78fa7deedabc6bc4fabc20b12453c963b85ed9ce76002211d3423b05f51542
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
## 0.80 2022-02-28
|
2
|
+
|
3
|
+
- Prevent reentry into `trace_proc`
|
4
|
+
- Rename `__parser_read_method__` to `__read_method__`
|
5
|
+
- Rename `ResourcePool#preheat!` to `#fill`.
|
6
|
+
- Remove ability to use `#cancel_after` or `#move_on` without a block
|
7
|
+
- Add #move_on alias to `Fiber#interrupt`
|
8
|
+
- Allow specifying exception in `Fiber#cancel`
|
9
|
+
- Remove deprecated `Polyphony::Channel` class
|
10
|
+
|
1
11
|
## 0.79 2022-02-19
|
2
12
|
|
3
13
|
- Overhaul trace events system (#73)
|
data/Gemfile.lock
CHANGED
@@ -17,6 +17,7 @@ inline void backend_base_initialize(struct Backend_base *base) {
|
|
17
17
|
base->idle_gc_last_time = 0;
|
18
18
|
base->idle_proc = Qnil;
|
19
19
|
base->trace_proc = Qnil;
|
20
|
+
base->in_trace_proc = 0;
|
20
21
|
}
|
21
22
|
|
22
23
|
inline void backend_base_finalize(struct Backend_base *base) {
|
@@ -137,7 +138,7 @@ inline void backend_base_unpark_fiber(struct Backend_base *base, VALUE fiber) {
|
|
137
138
|
}
|
138
139
|
|
139
140
|
inline void backend_trace(struct Backend_base *base, int argc, VALUE *argv) {
|
140
|
-
if (base->trace_proc == Qnil) return;
|
141
|
+
if (base->trace_proc == Qnil || base->in_trace_proc) return;
|
141
142
|
|
142
143
|
rb_funcallv(base->trace_proc, ID_call, argc, argv);
|
143
144
|
}
|
@@ -32,6 +32,7 @@ struct Backend_base {
|
|
32
32
|
double idle_gc_last_time;
|
33
33
|
VALUE idle_proc;
|
34
34
|
VALUE trace_proc;
|
35
|
+
unsigned int in_trace_proc;
|
35
36
|
};
|
36
37
|
|
37
38
|
void backend_base_initialize(struct Backend_base *base);
|
@@ -46,8 +47,12 @@ void backend_trace(struct Backend_base *base, int argc, VALUE *argv);
|
|
46
47
|
struct backend_stats backend_base_stats(struct Backend_base *base);
|
47
48
|
|
48
49
|
// tracing
|
49
|
-
#define SHOULD_TRACE(base) ((base)->trace_proc != Qnil)
|
50
|
-
#define TRACE(base, ...)
|
50
|
+
#define SHOULD_TRACE(base) ((base)->trace_proc != Qnil && !(base)->in_trace_proc)
|
51
|
+
#define TRACE(base, ...) { \
|
52
|
+
(base)->in_trace_proc = 1; \
|
53
|
+
rb_funcall((base)->trace_proc, ID_call, __VA_ARGS__); \
|
54
|
+
(base)->in_trace_proc = 0; \
|
55
|
+
}
|
51
56
|
#define COND_TRACE(base, ...) if (SHOULD_TRACE(base)) { TRACE(base, __VA_ARGS__); }
|
52
57
|
|
53
58
|
|
@@ -6,6 +6,8 @@ require_relative '../core/thread_pool'
|
|
6
6
|
|
7
7
|
::File.singleton_class.instance_eval do
|
8
8
|
alias_method :orig_stat, :stat
|
9
|
+
|
10
|
+
# Offloads `File.stat` to the default thread pool.
|
9
11
|
def stat(path)
|
10
12
|
ThreadPool.process { orig_stat(path) }
|
11
13
|
end
|
@@ -13,6 +15,8 @@ end
|
|
13
15
|
|
14
16
|
::IO.singleton_class.instance_eval do
|
15
17
|
alias_method :orig_read, :read
|
18
|
+
|
19
|
+
# Offloads `IO.read` to the default thread pool.
|
16
20
|
def read(path)
|
17
21
|
ThreadPool.process { orig_read(path) }
|
18
22
|
end
|
@@ -1,9 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Polyphony
|
4
|
-
# Process
|
4
|
+
# Process extensions
|
5
5
|
module Process
|
6
6
|
class << self
|
7
|
+
|
8
|
+
# Watches a forked or spawned process, waiting for it to terminate. If
|
9
|
+
# `cmd` is given it is spawned, otherwise the process is forked with the
|
10
|
+
# given block.
|
11
|
+
#
|
12
|
+
# If the operation is interrupted for any reason, the spawned or forked
|
13
|
+
# process is killed.
|
14
|
+
#
|
15
|
+
# @param cmd [String, nil] command to spawn
|
16
|
+
# @param &block [Proc] block to fork
|
17
|
+
# @return [void]
|
7
18
|
def watch(cmd = nil, &block)
|
8
19
|
terminated = nil
|
9
20
|
pid = cmd ? Kernel.spawn(cmd) : Polyphony.fork(&block)
|
@@ -13,6 +24,8 @@ module Polyphony
|
|
13
24
|
kill_process(pid) unless terminated || pid.nil?
|
14
25
|
end
|
15
26
|
|
27
|
+
private
|
28
|
+
|
16
29
|
def kill_process(pid)
|
17
30
|
cancel_after(5) do
|
18
31
|
kill_and_await('TERM', pid)
|
@@ -7,6 +7,10 @@ require 'hiredis/reader'
|
|
7
7
|
|
8
8
|
# Polyphony-based Redis driver
|
9
9
|
class Polyphony::RedisDriver
|
10
|
+
|
11
|
+
# Connects to a Redis server using the given config.
|
12
|
+
#
|
13
|
+
# @return [TCPSocket, UNIXSocket, SSLSocket] client connectio
|
10
14
|
def self.connect(config)
|
11
15
|
raise 'unix sockets not supported' if config[:scheme] == 'unix'
|
12
16
|
|
@@ -20,28 +24,49 @@ class Polyphony::RedisDriver
|
|
20
24
|
# connection.connect(config[:host], config[:port], connect_timeout)
|
21
25
|
end
|
22
26
|
|
27
|
+
# Initializes a Redis client connection.
|
28
|
+
#
|
29
|
+
# @param host [String] hostname
|
30
|
+
# @param port [Integer] port number
|
23
31
|
def initialize(host, port)
|
24
32
|
@connection = Polyphony::Net.tcp_connect(host, port)
|
25
33
|
@reader = ::Hiredis::Reader.new
|
26
34
|
end
|
27
35
|
|
36
|
+
# Returns true if connected to server.
|
37
|
+
#
|
38
|
+
# @return [bool] is connected to server
|
28
39
|
def connected?
|
29
40
|
@connection && !@connection.closed?
|
30
41
|
end
|
31
42
|
|
43
|
+
# Sets a timeout for the connection.
|
44
|
+
#
|
45
|
+
# @return [void]
|
32
46
|
def timeout=(timeout)
|
33
47
|
# ignore timeout for now
|
34
48
|
end
|
35
49
|
|
50
|
+
# Disconnects from the server.
|
51
|
+
#
|
52
|
+
# @return [void]
|
36
53
|
def disconnect
|
37
54
|
@connection.close
|
38
55
|
@connection = nil
|
39
56
|
end
|
40
57
|
|
58
|
+
# Sends a command to the server.
|
59
|
+
#
|
60
|
+
# @param command [Array] Redis command
|
61
|
+
# @return [void]
|
41
62
|
def write(command)
|
42
63
|
@connection.write(format_command(command))
|
43
64
|
end
|
44
65
|
|
66
|
+
# Formats a command for sending to server.
|
67
|
+
#
|
68
|
+
# @param args [Array] command
|
69
|
+
# @return [String] formatted command
|
45
70
|
def format_command(args)
|
46
71
|
args = args.flatten
|
47
72
|
(+"*#{args.size}\r\n").tap do |s|
|
@@ -52,6 +77,9 @@ class Polyphony::RedisDriver
|
|
52
77
|
end
|
53
78
|
end
|
54
79
|
|
80
|
+
# Reads from the connection, feeding incoming data to the parser.
|
81
|
+
#
|
82
|
+
# @return [void]
|
55
83
|
def read
|
56
84
|
reply = @reader.gets
|
57
85
|
return reply if reply
|
@@ -4,14 +4,23 @@ require_relative '../../polyphony'
|
|
4
4
|
require 'sequel'
|
5
5
|
|
6
6
|
module Polyphony
|
7
|
+
|
7
8
|
# Sequel ConnectionPool that delegates to Polyphony::ResourcePool.
|
8
9
|
class FiberConnectionPool < Sequel::ConnectionPool
|
10
|
+
|
11
|
+
# Initializes the connection pool.
|
12
|
+
#
|
13
|
+
# @param db [any] db to connect to
|
14
|
+
# @opts [Hash] connection pool options
|
9
15
|
def initialize(db, opts = OPTS)
|
10
16
|
super
|
11
17
|
max_size = Integer(opts[:max_connections] || 4)
|
12
18
|
@pool = Polyphony::ResourcePool.new(limit: max_size) { make_new(:default) }
|
13
19
|
end
|
14
20
|
|
21
|
+
# Holds a connection from the pool, passing it to the given block.
|
22
|
+
#
|
23
|
+
# @return [any] block's return value
|
15
24
|
def hold(_server = nil)
|
16
25
|
@pool.acquire do |conn|
|
17
26
|
yield conn
|
@@ -23,16 +32,25 @@ module Polyphony
|
|
23
32
|
end
|
24
33
|
end
|
25
34
|
|
35
|
+
# Returns the pool's size.
|
36
|
+
#
|
37
|
+
# @return [Integer] size of pool
|
26
38
|
def size
|
27
39
|
@pool.size
|
28
40
|
end
|
29
41
|
|
42
|
+
# Returns the pool's maximal size.
|
43
|
+
#
|
44
|
+
# @return [Integer] maximum pool size
|
30
45
|
def max_size
|
31
46
|
@pool.limit
|
32
47
|
end
|
33
48
|
|
49
|
+
# Fills pool and preconnects all db instances in pool.
|
50
|
+
#
|
51
|
+
# @return [void]
|
34
52
|
def preconnect(_concurrent = false)
|
35
|
-
@pool.
|
53
|
+
@pool.fill!
|
36
54
|
end
|
37
55
|
end
|
38
56
|
|
data/lib/polyphony/core/debug.rb
CHANGED
@@ -1,8 +1,15 @@
|
|
1
|
+
# Kernel extensions
|
1
2
|
module ::Kernel
|
3
|
+
# Prints a trace message to `STDOUT`, bypassing the Polyphony backend.
|
4
|
+
#
|
5
|
+
# @return [void]
|
2
6
|
def trace(*args)
|
3
7
|
STDOUT.orig_write(format_trace(args))
|
4
8
|
end
|
5
9
|
|
10
|
+
# Formats a trace message.
|
11
|
+
#
|
12
|
+
# @return [String] trace message
|
6
13
|
def format_trace(args)
|
7
14
|
if args.size > 1 && args.first.is_a?(String)
|
8
15
|
format("%s: %p\n", args.shift, args.size == 1 ? args.first : args)
|
@@ -15,14 +22,29 @@ module ::Kernel
|
|
15
22
|
end
|
16
23
|
|
17
24
|
module Polyphony
|
25
|
+
|
26
|
+
# Trace provides tools for tracing the activity of the current thread's
|
27
|
+
# backend.
|
18
28
|
module Trace
|
19
29
|
class << self
|
30
|
+
|
31
|
+
# Starts tracing, emitting events converted to hashes to the given block.
|
32
|
+
# If an IO instance is given, events are dumped to it instead.
|
33
|
+
#
|
34
|
+
# @param io [IO, nil] IO instance
|
35
|
+
# @param &block [Proc] event handler block
|
36
|
+
# @return [void]
|
20
37
|
def start_event_firehose(io = nil, &block)
|
21
38
|
Thread.backend.trace_proc = firehose_proc(io, block)
|
22
39
|
end
|
23
40
|
|
24
41
|
private
|
25
42
|
|
43
|
+
# Returns a firehose proc for the given io and block.
|
44
|
+
#
|
45
|
+
# @param io [IO, nil] IO instance
|
46
|
+
# @param block [Proc] event handler block
|
47
|
+
# @return [Proc] firehose proc
|
26
48
|
def firehose_proc(io, block)
|
27
49
|
if io
|
28
50
|
->(*e) { io.orig_write("#{trace_event_info(e).inspect}\n") }
|
@@ -33,53 +55,50 @@ module Polyphony
|
|
33
55
|
end
|
34
56
|
end
|
35
57
|
|
58
|
+
# Converts an event (expressed as an array) to a hash.
|
59
|
+
#
|
60
|
+
# @param e [Array] event as emitted by the backend
|
61
|
+
# @return [Hash] event hash
|
36
62
|
def trace_event_info(e)
|
37
63
|
{
|
38
|
-
stamp:
|
64
|
+
stamp: Time.now,
|
39
65
|
event: e[0]
|
40
66
|
}.merge(
|
41
67
|
send(:"event_props_#{e[0]}", e)
|
42
68
|
)
|
43
69
|
end
|
44
|
-
|
45
|
-
def format_trace_event_message(e)
|
46
|
-
props = send(:"event_props_#{e[0]}", e).merge(
|
47
|
-
timestamp: format_current_time,
|
48
|
-
event: e[0]
|
49
|
-
)
|
50
|
-
# templ = send(:"event_format_#{e[0]}", e)
|
51
|
-
|
52
|
-
# msg = format("%<timestamp>s #{templ}\n", **props)
|
53
|
-
end
|
54
|
-
|
55
|
-
def format_current_time
|
56
|
-
Time.now.strftime('%Y-%m-%d %H:%M:%S')
|
57
|
-
end
|
58
70
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
def
|
64
|
-
|
71
|
+
# Returns an event hash for a `:block` event.
|
72
|
+
#
|
73
|
+
# @param e [Array] event array
|
74
|
+
# @return [Hash] event hash
|
75
|
+
def event_props_block(e)
|
76
|
+
{
|
77
|
+
fiber: e[1],
|
78
|
+
caller: e[2]
|
79
|
+
}
|
65
80
|
end
|
66
81
|
|
82
|
+
# Returns an event hash for a `:enter_poll` event.
|
83
|
+
#
|
84
|
+
# @param e [Array] event array
|
85
|
+
# @return [Hash] event hash
|
67
86
|
def event_props_enter_poll(e)
|
68
87
|
{}
|
69
88
|
end
|
70
89
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
90
|
+
# Returns an event hash for a `:leave_poll` event.
|
91
|
+
#
|
92
|
+
# @param e [Array] event array
|
93
|
+
# @return [Hash] event hash
|
75
94
|
def event_props_leave_poll(e)
|
76
95
|
{}
|
77
96
|
end
|
78
97
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
98
|
+
# Returns an event hash for a `:schedule` event.
|
99
|
+
#
|
100
|
+
# @param e [Array] event array
|
101
|
+
# @return [Hash] event hash
|
83
102
|
def event_props_schedule(e)
|
84
103
|
{
|
85
104
|
fiber: e[1],
|
@@ -89,22 +108,22 @@ module Polyphony
|
|
89
108
|
}
|
90
109
|
end
|
91
110
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
def
|
111
|
+
# Returns an event hash for a `:spin` event.
|
112
|
+
#
|
113
|
+
# @param e [Array] event array
|
114
|
+
# @return [Hash] event hash
|
115
|
+
def event_props_spin(e)
|
97
116
|
{
|
98
117
|
fiber: e[1],
|
99
|
-
|
100
|
-
|
118
|
+
caller: e[2],
|
119
|
+
source_fiber: Fiber.current
|
101
120
|
}
|
102
121
|
end
|
103
122
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
123
|
+
# Returns an event hash for a `:terminate` event.
|
124
|
+
#
|
125
|
+
# @param e [Array] event array
|
126
|
+
# @return [Hash] event hash
|
108
127
|
def event_props_terminate(e)
|
109
128
|
{
|
110
129
|
fiber: e[1],
|
@@ -112,48 +131,86 @@ module Polyphony
|
|
112
131
|
}
|
113
132
|
end
|
114
133
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
def
|
134
|
+
# Returns an event hash for a `:unblock` event.
|
135
|
+
#
|
136
|
+
# @param e [Array] event array
|
137
|
+
# @return [Hash] event hash
|
138
|
+
def event_props_unblock(e)
|
120
139
|
{
|
121
140
|
fiber: e[1],
|
122
|
-
|
141
|
+
value: e[2],
|
142
|
+
caller: e[3],
|
123
143
|
}
|
124
144
|
end
|
125
145
|
|
126
|
-
|
127
|
-
|
128
|
-
|
146
|
+
# TODO: work on text formatting of events
|
147
|
+
# def format_trace_event_message(e)
|
148
|
+
# props = send(:"event_props_#{e[0]}", e).merge(
|
149
|
+
# timestamp: format_current_time,
|
150
|
+
# event: e[0]
|
151
|
+
# )
|
152
|
+
# templ = send(:"event_format_#{e[0]}", e)
|
153
|
+
# msg = format("%<timestamp>s #{templ}\n", **props)
|
154
|
+
# end
|
129
155
|
|
130
|
-
def
|
131
|
-
|
132
|
-
|
133
|
-
caller: e[2],
|
134
|
-
source_fiber: Fiber.current
|
135
|
-
}
|
136
|
-
end
|
156
|
+
# def format_current_time
|
157
|
+
# Time.now.strftime('%Y-%m-%d %H:%M:%S')
|
158
|
+
# end
|
137
159
|
|
138
|
-
def
|
139
|
-
|
140
|
-
end
|
160
|
+
# def generic_event_format
|
161
|
+
# '%<event>-12.12s'
|
162
|
+
# end
|
141
163
|
|
142
|
-
def
|
143
|
-
|
144
|
-
end
|
164
|
+
# def fiber_event_format
|
165
|
+
# "#{generic_event_format} %<fiber>-44.44s"
|
166
|
+
# end
|
145
167
|
|
146
|
-
def
|
147
|
-
|
148
|
-
|
149
|
-
else
|
150
|
-
format("%-6x %-.10s", fiber.object_id, "(#{fiber.state})")
|
151
|
-
end
|
152
|
-
end
|
168
|
+
# def event_format_enter_poll(e)
|
169
|
+
# generic_event_format
|
170
|
+
# end
|
153
171
|
|
154
|
-
def
|
155
|
-
|
156
|
-
end
|
172
|
+
# def event_format_leave_poll(e)
|
173
|
+
# generic_event_format
|
174
|
+
# end
|
175
|
+
|
176
|
+
|
177
|
+
# def event_format_schedule(e)
|
178
|
+
# "#{fiber_event_format} %<value>-24.24p %<caller>-120.120s <= %<origin_fiber>s"
|
179
|
+
# end
|
180
|
+
|
181
|
+
|
182
|
+
# def event_format_unblock(e)
|
183
|
+
# "#{fiber_event_format} %<value>-24.24p %<caller>-120.120s"
|
184
|
+
# end
|
185
|
+
|
186
|
+
# def event_format_terminate(e)
|
187
|
+
# "#{fiber_event_format} %<value>-24.24p"
|
188
|
+
# end
|
189
|
+
|
190
|
+
# def event_format_block(e)
|
191
|
+
# "#{fiber_event_format} #{' ' * 24} %<caller>-120.120s"
|
192
|
+
# end
|
193
|
+
|
194
|
+
|
195
|
+
# def event_format_spin(e)
|
196
|
+
# "#{fiber_event_format} #{' ' * 24} %<caller>-120.120s <= %<origin_fiber>s"
|
197
|
+
# end
|
198
|
+
|
199
|
+
# def fibe_repr(fiber)
|
200
|
+
# format("%-6x %-20.20s %-10.10s", fiber.object_id, fiber.tag, "(#{fiber.state})")
|
201
|
+
# end
|
202
|
+
|
203
|
+
# def fiber_compact_repr(fiber)
|
204
|
+
# if fiber.tag
|
205
|
+
# format("%-6x %-.20s %-.10s", fiber.object_id, fiber.tag, "(#{fiber.state})")
|
206
|
+
# else
|
207
|
+
# format("%-6x %-.10s", fiber.object_id, "(#{fiber.state})")
|
208
|
+
# end
|
209
|
+
# end
|
210
|
+
|
211
|
+
# def caller_repr(c)
|
212
|
+
# c.map { |i| i.gsub('/home/sharon/repo/polyphony/lib/polyphony', '') }.join(' ')
|
213
|
+
# end
|
157
214
|
end
|
158
215
|
end
|
159
216
|
end
|
@@ -1,15 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Polyphony
|
4
|
-
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
# through nested
|
4
|
+
|
5
|
+
# Base exception class for interrupting fibers. These exceptions allow control
|
6
|
+
# of fibers. BaseException exceptions can encapsulate a value and thus provide
|
7
|
+
# a way to interrupt long-running blocking operations while still passing a
|
8
|
+
# value back to the call site. BaseException exceptions can also references a
|
9
|
+
# cancel scope in order to allow correct bubbling of exceptions through nested
|
10
|
+
# cancel scopes.
|
10
11
|
class BaseException < ::Exception
|
12
|
+
|
13
|
+
# Exception value, used mainly for `MoveOn` exceptions.
|
11
14
|
attr_reader :value
|
12
15
|
|
16
|
+
# Initializes the exception, setting the caller and the value.
|
17
|
+
#
|
18
|
+
# @param value [any] Exception value
|
19
|
+
# @return [void]
|
13
20
|
def initialize(value = nil)
|
14
21
|
@caller_backtrace = caller
|
15
22
|
@value = value
|
@@ -33,10 +40,18 @@ module Polyphony
|
|
33
40
|
|
34
41
|
# Interjection is used to run arbitrary code on arbitrary fibers at any point
|
35
42
|
class Interjection < BaseException
|
43
|
+
|
44
|
+
# Initializes an Interjection with the given proc.
|
45
|
+
#
|
46
|
+
# @param proc [Proc] interjection proc
|
47
|
+
# @return [void]
|
36
48
|
def initialize(proc)
|
37
49
|
@proc = proc
|
38
50
|
end
|
39
51
|
|
52
|
+
# Invokes the exception by calling the associated proc.
|
53
|
+
#
|
54
|
+
# @return [void]
|
40
55
|
def invoke
|
41
56
|
@proc.call
|
42
57
|
end
|