polyphony 0.30 → 0.31
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 +36 -55
- data/Gemfile.lock +5 -3
- data/Rakefile +0 -4
- data/TODO.md +61 -9
- data/examples/{interfaces → adapters}/pg_client.rb +1 -1
- data/examples/{interfaces → adapters}/pg_notify.rb +1 -1
- data/examples/{interfaces → adapters}/pg_pool.rb +1 -1
- data/examples/{interfaces → adapters}/pg_transaction.rb +1 -1
- data/examples/{interfaces → adapters}/redis_channels.rb +1 -2
- data/examples/{interfaces → adapters}/redis_client.rb +1 -1
- data/examples/{interfaces → adapters}/redis_pubsub.rb +1 -2
- data/examples/{interfaces → adapters}/redis_pubsub_perf.rb +1 -2
- data/ext/gyro/thread.c +36 -1
- data/ext/gyro/timer.c +2 -1
- data/lib/polyphony.rb +2 -2
- data/lib/polyphony/{fs.rb → adapters/fs.rb} +0 -0
- data/lib/polyphony/adapters/irb.rb +51 -0
- data/lib/polyphony/{postgres.rb → adapters/postgres.rb} +1 -1
- data/lib/polyphony/{redis.rb → adapters/redis.rb} +1 -1
- data/lib/polyphony/{trace.rb → adapters/trace.rb} +0 -0
- data/lib/polyphony/core/global_api.rb +2 -2
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +1 -1
- data/test/test_fiber.rb +1 -1
- data/test/test_global_api.rb +13 -0
- data/test/test_signal.rb +73 -0
- metadata +17 -17
- data/lib/polyphony/irb.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 24126ff67fd9fd240299e1af8567da58f072c6c60df3f77b40f87ac108010f80
|
4
|
+
data.tar.gz: 95bcac53f361d65718aea1b55b557a7f68624d9815c38ee7c0cb79e11cb7bc96
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8849c26d4c2eccba56e786ac7ad76c2e2129244b619b988d649dca636491dd6158c0bed8feac191df9a7958f946592a8987a1e6709f27ef1383403b279f5595d
|
7
|
+
data.tar.gz: e8797e0b6e3852a208488213634b1360fc297e3ee9efa5c5e05d538a2684a02dfdf5efb00aca82b72064fc996a50c91de5c477a55ef5fd9dbf85275fd10e1f42
|
data/CHANGELOG.md
CHANGED
@@ -1,9 +1,16 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
* Fix adapter requires (redis and postgres).
|
2
|
+
|
3
|
+
## 0.31 2020-02-20
|
4
|
+
|
5
|
+
* Fix signal handling race condition (#13)
|
6
|
+
* Move adapter code into polyphony/adapters
|
7
|
+
* Fix spin_loop caller, add tag parameter
|
8
|
+
|
9
|
+
## 0.30 2020-02-04
|
3
10
|
|
4
11
|
* Add support for awaiting a fiber from multiple monitor fibers at once
|
5
12
|
* Implemented child fibers
|
6
|
-
* Fix TERM and INT signal handling (
|
13
|
+
* Fix TERM and INT signal handling (#11)
|
7
14
|
* Fix compiling on Linux
|
8
15
|
* Do not reset runnable value in Gyro_suspend (prevents interrupting timers)
|
9
16
|
* Don't snooze when stopping a fiber
|
@@ -12,8 +19,7 @@
|
|
12
19
|
* Prevent signalling of inactive async watcher
|
13
20
|
* Better fiber messaging
|
14
21
|
|
15
|
-
0.29 2020-02-02
|
16
|
-
---------------
|
22
|
+
## 0.29 2020-02-02
|
17
23
|
|
18
24
|
* Pass SignalException to main fiber
|
19
25
|
* Add (restore) default thread pool
|
@@ -24,8 +30,7 @@
|
|
24
30
|
* Improve tracing
|
25
31
|
* Fix IRB adapter
|
26
32
|
|
27
|
-
0.28 2020-01-27
|
28
|
-
---------------
|
33
|
+
## 0.28 2020-01-27
|
29
34
|
|
30
35
|
* Accept block in Supervisor#initialize
|
31
36
|
* Refactor `ThreadPool`
|
@@ -37,37 +42,32 @@
|
|
37
42
|
* Use `:waiting`, `:runnable`, `:running`, `:dead` for fiber states
|
38
43
|
* Move docs to https://digital-fabric.github.io/polyphony/
|
39
44
|
|
40
|
-
0.27 2020-01-19
|
41
|
-
---------------
|
45
|
+
## 0.27 2020-01-19
|
42
46
|
|
43
47
|
* Reimplement `Throttler` using recurring timer
|
44
48
|
* Add `Gyro::Selector` for wrapping libev
|
45
49
|
* Add `Gyro::Queue`, a fiber-aware thread-safe queue
|
46
50
|
* Implement multithreaded fiber scheduling
|
47
51
|
|
48
|
-
0.26 2020-01-12
|
49
|
-
---------------
|
52
|
+
## 0.26 2020-01-12
|
50
53
|
|
51
54
|
* Optimize `IO#read_watcher`, `IO#write_watcher`
|
52
55
|
* Implement `Fiber#raise`
|
53
56
|
* Fix `Kernel#gets` with `ARGV`
|
54
57
|
* Return `[pid, exit_status]` from `Gyro::Child#await`
|
55
58
|
|
56
|
-
0.25 2020-01-10
|
57
|
-
---------------
|
59
|
+
## 0.25 2020-01-10
|
58
60
|
|
59
61
|
* Fold `Coprocess` functionality into `Fiber`
|
60
62
|
* Add support for indefinite `#sleep`
|
61
63
|
|
62
|
-
0.24 2020-01-08
|
63
|
-
---------------
|
64
|
+
## 0.24 2020-01-08
|
64
65
|
|
65
66
|
* Extract HTTP code into separate polyphony-http gem
|
66
67
|
* Cull core, io examples
|
67
68
|
* Remove `SIGINT` handler
|
68
69
|
|
69
|
-
0.23 2020-01-07
|
70
|
-
---------------
|
70
|
+
## 0.23 2020-01-07
|
71
71
|
|
72
72
|
* Remove `API#pulse`
|
73
73
|
* Better repeat timer, reimplement `API#every`
|
@@ -91,8 +91,7 @@
|
|
91
91
|
* Add Gyro.run
|
92
92
|
* Move away from callback-based API for `Gyro::Timer`, `Gyro::Signal`
|
93
93
|
|
94
|
-
0.22 2020-01-02
|
95
|
-
---------------
|
94
|
+
## 0.22 2020-01-02
|
96
95
|
|
97
96
|
* Redesign Gyro scheduling subsystem, go scheduler-less
|
98
97
|
* More docs
|
@@ -102,8 +101,7 @@
|
|
102
101
|
* Fix socket extensions
|
103
102
|
* Fix ALPN setup in Net.secure_socket
|
104
103
|
|
105
|
-
0.21 2019-12-12
|
106
|
-
---------------
|
104
|
+
## 0.21 2019-12-12
|
107
105
|
|
108
106
|
* Add Coprocess.await (for waiting for multiple coprocesses)
|
109
107
|
* Add Coprocess#caller, Coprocess#location methods
|
@@ -112,8 +110,7 @@
|
|
112
110
|
* Improve error handling in HTTP/2 adapter
|
113
111
|
* More documentation
|
114
112
|
|
115
|
-
0.20 2019-11-27
|
116
|
-
---------------
|
113
|
+
## 0.20 2019-11-27
|
117
114
|
|
118
115
|
* Refactor and improve CancelScope, ResourcePool
|
119
116
|
* Reimplement cancel_after, move_on_after using plain timers
|
@@ -147,8 +144,7 @@
|
|
147
144
|
* Fix HTTP1 adapter
|
148
145
|
* Better support for debugging with ruby-debug-ide (WIP)
|
149
146
|
|
150
|
-
0.19 2019-06-12
|
151
|
-
---------------
|
147
|
+
## 0.19 2019-06-12
|
152
148
|
|
153
149
|
* Rewrite HTTP server for better concurrency, sequential API
|
154
150
|
* Support 204 no-content response in HTTP 1
|
@@ -156,14 +152,12 @@
|
|
156
152
|
* Implement Fiber#safe_transfer in C
|
157
153
|
* Optimize Kernel#next_tick implementation using ev_idle instead of ev_timer
|
158
154
|
|
159
|
-
0.18 2019-06-08
|
160
|
-
---------------
|
155
|
+
## 0.18 2019-06-08
|
161
156
|
|
162
157
|
* Rename Kernel#coproc to Kernel#spin
|
163
158
|
* Rewrite Supervisor#spin
|
164
159
|
|
165
|
-
0.17 2019-05-24
|
166
|
-
---------------
|
160
|
+
## 0.17 2019-05-24
|
167
161
|
|
168
162
|
* Implement IO#read_watcher, IO#write_watcher in C for better performance
|
169
163
|
* Implement nonblocking (yielding) versions of Kernel#system, IO.popen,
|
@@ -173,14 +167,12 @@
|
|
173
167
|
* Fix encoding of strings read with IO#read, IO#readpartial
|
174
168
|
* Fix non-blocking behaviour of IO#read, IO#readpartial, IO#write
|
175
169
|
|
176
|
-
0.16 2019-05-22
|
177
|
-
---------------
|
170
|
+
## 0.16 2019-05-22
|
178
171
|
|
179
172
|
* Reorganize and refactor code
|
180
173
|
* Allow opening secure socket without OpenSSL context
|
181
174
|
|
182
|
-
0.15 2019-05-20
|
183
|
-
---------------
|
175
|
+
## 0.15 2019-05-20
|
184
176
|
|
185
177
|
* Optimize `#next_tick` callback (about 6% faster than before)
|
186
178
|
* Fix IO#<< to return self
|
@@ -188,8 +180,7 @@
|
|
188
180
|
* Fix race condition in `Supervisor#stop!`
|
189
181
|
* Add `Kernel#snooze` method (`EV.snooze` will be deprecated eventually)
|
190
182
|
|
191
|
-
0.14 2019-05-17
|
192
|
-
---------------
|
183
|
+
## 0.14 2019-05-17
|
193
184
|
|
194
185
|
* Use chunked encoding in HTTP 1 response
|
195
186
|
* Rewrite `IO#read`, `#readpartial`, `#write` in C (about 30% performance improvement)
|
@@ -199,13 +190,11 @@
|
|
199
190
|
* Preliminary support for websocket (see `examples/io/http_ws_server.rb`)
|
200
191
|
* Rename `Coroutine` to `Coprocess`
|
201
192
|
|
202
|
-
0.13 2019-01-05
|
203
|
-
---------------
|
193
|
+
## 0.13 2019-01-05
|
204
194
|
|
205
195
|
* Rename Rubato to Polyphony (I know, this is getting silly...)
|
206
196
|
|
207
|
-
0.12 2019-01-01
|
208
|
-
---------------
|
197
|
+
## 0.12 2019-01-01
|
209
198
|
|
210
199
|
* Add Coroutine#resume
|
211
200
|
* Improve startup time
|
@@ -214,8 +203,7 @@
|
|
214
203
|
* Improve handling of uncaught raised errors
|
215
204
|
* Implement HTTP 1.1/2 client agent with connection management
|
216
205
|
|
217
|
-
0.11 2018-12-27
|
218
|
-
---------------
|
206
|
+
## 0.11 2018-12-27
|
219
207
|
|
220
208
|
* Move reactor loop to secondary fiber, allow blocking operations on main
|
221
209
|
fiber.
|
@@ -225,8 +213,7 @@
|
|
225
213
|
for message passing
|
226
214
|
* Add Coroutine.current for getting current coroutine
|
227
215
|
|
228
|
-
0.10 2018-11-20
|
229
|
-
---------------
|
216
|
+
## 0.10 2018-11-20
|
230
217
|
|
231
218
|
* Rewrite Rubato core for simpler code and better performance
|
232
219
|
* Implement EV.snooze (sleep until next tick)
|
@@ -236,20 +223,17 @@
|
|
236
223
|
* Rate throttling
|
237
224
|
* Implement async SSL server
|
238
225
|
|
239
|
-
0.9 2018-11-14
|
240
|
-
--------------
|
226
|
+
## 0.9 2018-11-14
|
241
227
|
|
242
228
|
* Rename Nuclear to Rubato
|
243
229
|
|
244
|
-
0.8 2018-10-04
|
245
|
-
--------------
|
230
|
+
## 0.8 2018-10-04
|
246
231
|
|
247
232
|
* Replace nio4r with in-house extension based on libev, with better API,
|
248
233
|
better performance, support for IO, timer, signal and async watchers
|
249
234
|
* Fix mem leak coming from nio4r (probably related to code in Selector#select)
|
250
235
|
|
251
|
-
0.7 2018-09-13
|
252
|
-
--------------
|
236
|
+
## 0.7 2018-09-13
|
253
237
|
|
254
238
|
* Implement resource pool
|
255
239
|
* transaction method for pg cient
|
@@ -258,22 +242,19 @@
|
|
258
242
|
* Improve HTTP server performance
|
259
243
|
* Proper promise chaining
|
260
244
|
|
261
|
-
0.6 2018-09-11
|
262
|
-
--------------
|
245
|
+
## 0.6 2018-09-11
|
263
246
|
|
264
247
|
* Add http, redis, pg dependencies
|
265
248
|
* Move ALPN code inside net module
|
266
249
|
|
267
|
-
0.4 2018-09-10
|
268
|
-
--------------
|
250
|
+
## 0.4 2018-09-10
|
269
251
|
|
270
252
|
* Code refactored and reogranized
|
271
253
|
* Fix recursion in next_tick
|
272
254
|
* HTTP 2 server with support for ALPN protocol negotiation and HTTP upgrade
|
273
255
|
* OpenSSL server
|
274
256
|
|
275
|
-
0.3 2018-09-06
|
276
|
-
--------------
|
257
|
+
## 0.3 2018-09-06
|
277
258
|
|
278
259
|
* Event reactor
|
279
260
|
* Timers
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
polyphony (0.
|
4
|
+
polyphony (0.31)
|
5
5
|
modulation (~> 1.0)
|
6
6
|
|
7
7
|
GEM
|
@@ -90,12 +90,14 @@ GEM
|
|
90
90
|
rb-inotify (0.10.1)
|
91
91
|
ffi (~> 1.0)
|
92
92
|
redis (4.1.0)
|
93
|
+
rexml (3.2.4)
|
93
94
|
rouge (3.15.0)
|
94
|
-
rubocop (0.
|
95
|
+
rubocop (0.80.0)
|
95
96
|
jaro_winkler (~> 1.5.1)
|
96
97
|
parallel (~> 1.10)
|
97
98
|
parser (>= 2.7.0.1)
|
98
99
|
rainbow (>= 2.2.2, < 4.0)
|
100
|
+
rexml
|
99
101
|
ruby-progressbar (~> 1.7)
|
100
102
|
unicode-display_width (>= 1.4.0, < 1.7)
|
101
103
|
ruby-progressbar (1.10.1)
|
@@ -131,7 +133,7 @@ DEPENDENCIES
|
|
131
133
|
polyphony!
|
132
134
|
rake-compiler (= 1.0.5)
|
133
135
|
redis (= 4.1.0)
|
134
|
-
rubocop (= 0.
|
136
|
+
rubocop (= 0.80.0)
|
135
137
|
simplecov (= 0.17.1)
|
136
138
|
|
137
139
|
BUNDLED WITH
|
data/Rakefile
CHANGED
@@ -3,8 +3,6 @@
|
|
3
3
|
require "bundler/gem_tasks"
|
4
4
|
require "rake/clean"
|
5
5
|
|
6
|
-
# frozen_string_literal: true
|
7
|
-
|
8
6
|
require "rake/extensiontask"
|
9
7
|
Rake::ExtensionTask.new("gyro_ext") do |ext|
|
10
8
|
ext.ext_dir = "ext/gyro"
|
@@ -21,6 +19,4 @@ task :docs do
|
|
21
19
|
exec 'RUBYOPT=-W0 jekyll serve -s docs'
|
22
20
|
end
|
23
21
|
|
24
|
-
task default: %w[compile]
|
25
|
-
|
26
22
|
CLEAN.include "**/*.o", "**/*.so", "**/*.bundle", "**/*.jar", "pkg", "tmp"
|
data/TODO.md
CHANGED
@@ -1,4 +1,47 @@
|
|
1
|
-
## 0.
|
1
|
+
## 0.32 Working Sinatra application
|
2
|
+
|
3
|
+
- Introduce mailbox limiting:
|
4
|
+
- add API for limiting mailbox size:
|
5
|
+
|
6
|
+
```ruby
|
7
|
+
Fiber.current.mailbox_limit = 1000
|
8
|
+
```
|
9
|
+
|
10
|
+
- Add the limit for `Gyro::Queue`
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
Gyro::Queue.new(1000)
|
14
|
+
```
|
15
|
+
|
16
|
+
- Pushing to a limited queue will block if limit is reached
|
17
|
+
|
18
|
+
- Introduce selective receive:
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
# returns (or waits for) the first message for which the block returns true
|
22
|
+
(_, item) = receive { |msg| msg.first == ref }
|
23
|
+
```
|
24
|
+
|
25
|
+
Possible implementation:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
def receive
|
29
|
+
return @mailbox.shift unless block_given?
|
30
|
+
|
31
|
+
loop
|
32
|
+
msg = @mailbox.shift
|
33
|
+
return msg if yield(msg)
|
34
|
+
|
35
|
+
# message didn't match condition, put it back in queue
|
36
|
+
@mailbox.push msg
|
37
|
+
end
|
38
|
+
end
|
39
|
+
```
|
40
|
+
|
41
|
+
- Test hypothetical situation 1:
|
42
|
+
- fiber A sends a request to fiber B
|
43
|
+
- fiber B terminates on a raised exception
|
44
|
+
- What happens to fiber A? (it should get the exception)
|
2
45
|
|
3
46
|
- Accept rate/interval in `spin_loop` and `spin_worker_loop`:
|
4
47
|
|
@@ -8,13 +51,22 @@
|
|
8
51
|
spin_loop(interval: 10) { ... } # once every ten seconds
|
9
52
|
```
|
10
53
|
|
11
|
-
- Docs
|
54
|
+
- Docs
|
55
|
+
- landing page:
|
56
|
+
- links to the interesting stuff
|
57
|
+
- concurrency overview
|
58
|
+
- faq
|
59
|
+
- benchmarks
|
60
|
+
- explain difference between `sleep` and `suspend`
|
61
|
+
- concurrency overview: add explanation about async vs sync
|
62
|
+
|
63
|
+
- move all adapters into polyphony/adapters
|
64
|
+
|
12
65
|
- Check why first call to `#sleep` returns too early in tests. Check the
|
13
66
|
sleep behaviour in a spawned thread.
|
14
|
-
- app with database access (postgresql)
|
15
|
-
- benchmarks!
|
67
|
+
- sintra app with database access (postgresql)
|
16
68
|
|
17
|
-
## 0.
|
69
|
+
## 0.33 Sidekick
|
18
70
|
|
19
71
|
Plan of action:
|
20
72
|
|
@@ -22,13 +74,13 @@ Plan of action:
|
|
22
74
|
- test performance
|
23
75
|
- proceed from there
|
24
76
|
|
25
|
-
## 0.
|
77
|
+
## 0.34 Testing && Docs
|
26
78
|
|
27
79
|
- Pull out redis/postgres code, put into new `polyphony-xxx` gems
|
28
80
|
|
29
|
-
## 0.
|
81
|
+
## 0.35 Integration
|
30
82
|
|
31
|
-
## 0.
|
83
|
+
## 0.36 Real IO#gets and IO#read
|
32
84
|
|
33
85
|
- More tests
|
34
86
|
- Implement some basic stuff missing:
|
@@ -38,7 +90,7 @@ Plan of action:
|
|
38
90
|
- `IO.foreach`
|
39
91
|
- `Process.waitpid`
|
40
92
|
|
41
|
-
## 0.
|
93
|
+
## 0.37 Rails
|
42
94
|
|
43
95
|
- Rails?
|
44
96
|
|
data/ext/gyro/thread.c
CHANGED
@@ -129,6 +129,39 @@ VALUE Thread_schedule_fiber(VALUE self, VALUE fiber, VALUE value) {
|
|
129
129
|
return self;
|
130
130
|
}
|
131
131
|
|
132
|
+
VALUE Thread_schedule_fiber_with_priority(VALUE self, VALUE fiber, VALUE value) {
|
133
|
+
if (rb_fiber_alive_p(fiber) != Qtrue) {
|
134
|
+
return self;
|
135
|
+
}
|
136
|
+
FIBER_TRACE(3, SYM_fiber_schedule, fiber, value);
|
137
|
+
rb_ivar_set(fiber, ID_runnable_value, value);
|
138
|
+
|
139
|
+
VALUE queue = rb_ivar_get(self, ID_run_queue);
|
140
|
+
|
141
|
+
// if fiber is already scheduled, remove it from the run queue
|
142
|
+
if (rb_ivar_get(fiber, ID_runnable) != Qnil) {
|
143
|
+
rb_ary_delete(queue, fiber);
|
144
|
+
} else {
|
145
|
+
rb_ivar_set(fiber, ID_runnable, Qtrue);
|
146
|
+
}
|
147
|
+
|
148
|
+
// the fiber is given priority by putting it at the front of the run queue
|
149
|
+
rb_ary_unshift(queue, fiber);
|
150
|
+
|
151
|
+
if (rb_thread_current() != self) {
|
152
|
+
// if the fiber scheduling is done across threads, we need to make sure the
|
153
|
+
// target thread is woken up in case it is in the middle of running its
|
154
|
+
// event selector. Otherwise it's gonna be stuck waiting for an event to
|
155
|
+
// happen, not knowing that it there's already a fiber ready to run in its
|
156
|
+
// run queue.
|
157
|
+
VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
|
158
|
+
if (selector != Qnil) {
|
159
|
+
Gyro_Selector_break_out_of_ev_loop(selector);
|
160
|
+
}
|
161
|
+
}
|
162
|
+
return self;
|
163
|
+
}
|
164
|
+
|
132
165
|
VALUE Thread_switch_fiber(VALUE self) {
|
133
166
|
VALUE current_fiber = rb_fiber_current();
|
134
167
|
if (__tracing_enabled__) {
|
@@ -202,7 +235,7 @@ VALUE Thread_current_event_selector() {
|
|
202
235
|
|
203
236
|
VALUE Thread_fiber_break_out_of_ev_loop(VALUE self, VALUE resume_obj) {
|
204
237
|
VALUE selector = rb_ivar_get(self, ID_ivar_event_selector);
|
205
|
-
|
238
|
+
Thread_schedule_fiber_with_priority(self, rb_fiber_current(), resume_obj);
|
206
239
|
|
207
240
|
if (Gyro_Selector_break_out_of_ev_loop(selector) == Qnil) {
|
208
241
|
// we're not inside the ev_loop, so we just do a switchpoint
|
@@ -243,6 +276,8 @@ void Init_Thread() {
|
|
243
276
|
rb_define_method(rb_cThread, "break_out_of_ev_loop", Thread_fiber_break_out_of_ev_loop, 1);
|
244
277
|
|
245
278
|
rb_define_method(rb_cThread, "schedule_fiber", Thread_schedule_fiber, 2);
|
279
|
+
rb_define_method(rb_cThread, "schedule_fiber_with_priority",
|
280
|
+
Thread_schedule_fiber_with_priority, 2);
|
246
281
|
rb_define_method(rb_cThread, "switch_fiber", Thread_switch_fiber, 0);
|
247
282
|
|
248
283
|
rb_define_method(rb_cThread, "join_perform", Thread_join_perform, 0);
|
data/ext/gyro/timer.c
CHANGED
@@ -131,11 +131,12 @@ VALUE Gyro_Timer_await(VALUE self) {
|
|
131
131
|
ev_timer_stop(timer->ev_loop, &timer->ev_timer);
|
132
132
|
timer->ev_loop = 0;
|
133
133
|
}
|
134
|
-
RB_GC_GUARD(self);
|
135
134
|
|
136
135
|
// fiber is resumed, check if resumed value is an exception
|
137
136
|
timer->fiber = Qnil;
|
138
137
|
timer->selector = Qnil;
|
138
|
+
|
139
|
+
RB_GC_GUARD(self);
|
139
140
|
if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) {
|
140
141
|
return rb_funcall(rb_mKernel, ID_raise, 1, ret);
|
141
142
|
}
|
data/lib/polyphony.rb
CHANGED
@@ -30,12 +30,12 @@ module Polyphony
|
|
30
30
|
auto_import(
|
31
31
|
CancelScope: './polyphony/core/cancel_scope',
|
32
32
|
Channel: './polyphony/core/channel',
|
33
|
-
FS: './polyphony/fs',
|
33
|
+
FS: './polyphony/adapters/fs',
|
34
34
|
ResourcePool: './polyphony/core/resource_pool',
|
35
35
|
Sync: './polyphony/core/sync',
|
36
36
|
ThreadPool: './polyphony/core/thread_pool',
|
37
37
|
Throttler: './polyphony/core/throttler',
|
38
|
-
Trace: './polyphony/trace',
|
38
|
+
Trace: './polyphony/adapters/trace',
|
39
39
|
Websocket: './polyphony/websocket'
|
40
40
|
)
|
41
41
|
|
File without changes
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'polyphony'
|
4
|
+
|
5
|
+
if Object.constants.include?(:Reline)
|
6
|
+
class Reline::ANSI
|
7
|
+
def self.select(read_ios = [], write_ios = [], error_ios = [], timeout = nil)
|
8
|
+
p [:select, read_ios]
|
9
|
+
raise if read_ios.size > 1
|
10
|
+
raise if write_ios.size > 0
|
11
|
+
raise if error_ios.size > 0
|
12
|
+
|
13
|
+
fiber = Fiber.current
|
14
|
+
timer = spin do
|
15
|
+
sleep timeout
|
16
|
+
fiber.cancel!
|
17
|
+
end
|
18
|
+
read_ios.each do |io|
|
19
|
+
io.read_watcher.await
|
20
|
+
return [io]
|
21
|
+
end
|
22
|
+
rescue Polyphony::Cancel
|
23
|
+
return nil
|
24
|
+
ensure
|
25
|
+
timer.stop
|
26
|
+
end
|
27
|
+
end
|
28
|
+
else
|
29
|
+
# readline blocks the current thread, so we offload it to the blocking-ops
|
30
|
+
# thread pool. That way, the reactor loop can keep running while waiting for
|
31
|
+
# readline to return
|
32
|
+
module ::Readline
|
33
|
+
alias_method :orig_readline, :readline
|
34
|
+
|
35
|
+
Workers = Polyphony::ThreadPool.new
|
36
|
+
|
37
|
+
def readline(*args)
|
38
|
+
p :readline
|
39
|
+
# caller.each do |l|
|
40
|
+
# STDOUT.orig_puts l
|
41
|
+
# end
|
42
|
+
Workers.process { orig_readline(*args) }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class ::RubyLex
|
47
|
+
class TerminateLineInput2 < RuntimeError
|
48
|
+
end
|
49
|
+
const_set(:TerminateLineInput, TerminateLineInput2)
|
50
|
+
end
|
51
|
+
end
|
File without changes
|
data/lib/polyphony/version.rb
CHANGED
data/polyphony.gemspec
CHANGED
@@ -28,7 +28,7 @@ Gem::Specification.new do |s|
|
|
28
28
|
s.add_development_dependency 'minitest', '5.13.0'
|
29
29
|
s.add_development_dependency 'minitest-reporters', '1.4.2'
|
30
30
|
s.add_development_dependency 'simplecov', '0.17.1'
|
31
|
-
s.add_development_dependency 'rubocop', '0.
|
31
|
+
s.add_development_dependency 'rubocop', '0.80.0'
|
32
32
|
s.add_development_dependency 'pg', '1.1.3'
|
33
33
|
s.add_development_dependency 'rake-compiler', '1.0.5'
|
34
34
|
s.add_development_dependency 'redis', '4.1.0'
|
data/test/test_fiber.rb
CHANGED
data/test/test_global_api.rb
CHANGED
@@ -230,6 +230,19 @@ class MoveOnAfterTest < MiniTest::Test
|
|
230
230
|
assert_equal [1, 2, 3], buffer
|
231
231
|
end
|
232
232
|
|
233
|
+
def test_spin_loop_location
|
234
|
+
location = /^#{__FILE__}:#{__LINE__ + 1}/
|
235
|
+
f = spin_loop {}
|
236
|
+
|
237
|
+
assert_match location, f.location
|
238
|
+
end
|
239
|
+
|
240
|
+
def test_spin_loop_tag
|
241
|
+
f = spin_loop(:my_loop) {}
|
242
|
+
|
243
|
+
assert_equal :my_loop, f.tag
|
244
|
+
end
|
245
|
+
|
233
246
|
def test_throttled_loop
|
234
247
|
buffer = []
|
235
248
|
counter = 0
|
data/test/test_signal.rb
CHANGED
@@ -36,3 +36,76 @@ class SignalTest < MiniTest::Test
|
|
36
36
|
assert_equal 1, count
|
37
37
|
end
|
38
38
|
end
|
39
|
+
|
40
|
+
class SignalTrapTest < Minitest::Test
|
41
|
+
def test_signal_exception_propagation
|
42
|
+
i, o = IO.pipe
|
43
|
+
pid = Polyphony.fork do
|
44
|
+
i.close
|
45
|
+
spin do
|
46
|
+
spin do
|
47
|
+
sleep 1
|
48
|
+
rescue ::Interrupt => e
|
49
|
+
o.puts "1-interrupt"
|
50
|
+
raise e
|
51
|
+
end.await
|
52
|
+
rescue ::Interrupt => e
|
53
|
+
o.puts "2-interrupt"
|
54
|
+
raise e
|
55
|
+
end.await
|
56
|
+
rescue ::Interrupt => e
|
57
|
+
o.puts "3-interrupt"
|
58
|
+
ensure
|
59
|
+
o.close
|
60
|
+
end
|
61
|
+
sleep 0.01
|
62
|
+
o.close
|
63
|
+
watcher = Gyro::Child.new(pid)
|
64
|
+
Process.kill('INT', pid)
|
65
|
+
watcher.await
|
66
|
+
buffer = i.read
|
67
|
+
assert_equal "1-interrupt\n2-interrupt\n3-interrupt\n", buffer
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_signal_exception_possible_race_condition
|
71
|
+
i, o = IO.pipe
|
72
|
+
pid = Polyphony.fork do
|
73
|
+
i.close
|
74
|
+
f1 = nil
|
75
|
+
f2 = spin do
|
76
|
+
# this fiber will try to create a race condition by
|
77
|
+
# - being scheduled before f1 is scheduled with the Interrupt exception
|
78
|
+
# - scheduling f1 without an exception
|
79
|
+
suspend
|
80
|
+
f1.schedule
|
81
|
+
rescue ::Interrupt => e
|
82
|
+
o.puts '2-interrupt'
|
83
|
+
raise e
|
84
|
+
end
|
85
|
+
f1 = spin do
|
86
|
+
# this fiber is the one that will be current when the
|
87
|
+
# signal is trapped
|
88
|
+
sleep 1
|
89
|
+
o << 'boom'
|
90
|
+
rescue ::Interrupt => e
|
91
|
+
o.puts '1-interrupt'
|
92
|
+
raise e
|
93
|
+
end
|
94
|
+
old_trap = trap('INT') do
|
95
|
+
f2.schedule
|
96
|
+
old_trap.()
|
97
|
+
end
|
98
|
+
Fiber.current.await_all_children
|
99
|
+
rescue ::Interrupt => e
|
100
|
+
o.puts '3-interrupt'
|
101
|
+
ensure
|
102
|
+
o.close
|
103
|
+
end
|
104
|
+
o.close
|
105
|
+
sleep 0.1
|
106
|
+
Process.kill('INT', pid)
|
107
|
+
Gyro::Child.new(pid).await
|
108
|
+
buffer = i.read
|
109
|
+
assert_equal "1-interrupt\n3-interrupt\n", buffer
|
110
|
+
end
|
111
|
+
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.31'
|
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-02-
|
11
|
+
date: 2020-02-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: modulation
|
@@ -100,14 +100,14 @@ dependencies:
|
|
100
100
|
requirements:
|
101
101
|
- - '='
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: 0.
|
103
|
+
version: 0.80.0
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - '='
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: 0.
|
110
|
+
version: 0.80.0
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: pg
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -275,6 +275,14 @@ files:
|
|
275
275
|
- docs/user-guide.md
|
276
276
|
- docs/user-guide/all-about-timers.md
|
277
277
|
- docs/user-guide/web-server.md
|
278
|
+
- examples/adapters/pg_client.rb
|
279
|
+
- examples/adapters/pg_notify.rb
|
280
|
+
- examples/adapters/pg_pool.rb
|
281
|
+
- examples/adapters/pg_transaction.rb
|
282
|
+
- examples/adapters/redis_channels.rb
|
283
|
+
- examples/adapters/redis_client.rb
|
284
|
+
- examples/adapters/redis_pubsub.rb
|
285
|
+
- examples/adapters/redis_pubsub_perf.rb
|
278
286
|
- examples/core/01-spinning-up-fibers.rb
|
279
287
|
- examples/core/02-awaiting-fibers.rb
|
280
288
|
- examples/core/03-interrupting.rb
|
@@ -310,14 +318,6 @@ files:
|
|
310
318
|
- examples/core/xx-trace.rb
|
311
319
|
- examples/core/xx-using-a-mutex.rb
|
312
320
|
- examples/core/xx-worker-thread.rb
|
313
|
-
- examples/interfaces/pg_client.rb
|
314
|
-
- examples/interfaces/pg_notify.rb
|
315
|
-
- examples/interfaces/pg_pool.rb
|
316
|
-
- examples/interfaces/pg_transaction.rb
|
317
|
-
- examples/interfaces/redis_channels.rb
|
318
|
-
- examples/interfaces/redis_client.rb
|
319
|
-
- examples/interfaces/redis_pubsub.rb
|
320
|
-
- examples/interfaces/redis_pubsub_perf.rb
|
321
321
|
- examples/io/xx-backticks.rb
|
322
322
|
- examples/io/xx-echo_client.rb
|
323
323
|
- examples/io/xx-echo_client_from_stdin.rb
|
@@ -378,6 +378,11 @@ files:
|
|
378
378
|
- ext/libev/ev_wrap.h
|
379
379
|
- ext/libev/test_libev_win32.c
|
380
380
|
- lib/polyphony.rb
|
381
|
+
- lib/polyphony/adapters/fs.rb
|
382
|
+
- lib/polyphony/adapters/irb.rb
|
383
|
+
- lib/polyphony/adapters/postgres.rb
|
384
|
+
- lib/polyphony/adapters/redis.rb
|
385
|
+
- lib/polyphony/adapters/trace.rb
|
381
386
|
- lib/polyphony/core/cancel_scope.rb
|
382
387
|
- lib/polyphony/core/channel.rb
|
383
388
|
- lib/polyphony/core/exceptions.rb
|
@@ -392,12 +397,7 @@ files:
|
|
392
397
|
- lib/polyphony/extensions/openssl.rb
|
393
398
|
- lib/polyphony/extensions/socket.rb
|
394
399
|
- lib/polyphony/extensions/thread.rb
|
395
|
-
- lib/polyphony/fs.rb
|
396
|
-
- lib/polyphony/irb.rb
|
397
400
|
- lib/polyphony/net.rb
|
398
|
-
- lib/polyphony/postgres.rb
|
399
|
-
- lib/polyphony/redis.rb
|
400
|
-
- lib/polyphony/trace.rb
|
401
401
|
- lib/polyphony/version.rb
|
402
402
|
- polyphony.gemspec
|
403
403
|
- test/coverage.rb
|
data/lib/polyphony/irb.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'polyphony'
|
4
|
-
|
5
|
-
# readline blocks the current thread, so we offload it to the blocking-ops
|
6
|
-
# thread pool. That way, the reactor loop can keep running while waiting for
|
7
|
-
# readline to return
|
8
|
-
module ::Readline
|
9
|
-
alias_method :orig_readline, :readline
|
10
|
-
|
11
|
-
def readline(*args)
|
12
|
-
async = Gyro::Async.new
|
13
|
-
Thread.new do
|
14
|
-
result = orig_readline(*args)
|
15
|
-
async.signal!(result)
|
16
|
-
end
|
17
|
-
async.await
|
18
|
-
end
|
19
|
-
end
|