polyphony 0.77 → 0.78
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +1 -1
- data/CHANGELOG.md +4 -0
- data/Gemfile.lock +1 -1
- data/ext/polyphony/fiber.c +1 -1
- data/ext/polyphony/polyphony.h +1 -1
- data/ext/polyphony/queue.c +82 -6
- data/lib/polyphony/core/debug.rb +2 -0
- data/lib/polyphony/version.rb +1 -1
- data/test/test_queue.rb +103 -1
- data/test/test_supervise.rb +27 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 51eecc20956cb4f1a35a7f6510dea2730652700e99d29c7d42ade201a119ea2e
|
4
|
+
data.tar.gz: bc2b57dc2cc5a8918bba1d8bf526cdbe23f44d134f9bdca5018b9e9e66930f91
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 21c446f9a6fa032577b245e6de5155832c8e6932d6c17e58824a55923c82be014453b64b29ccbb66fe5d01cde8622d3275664acda403637954f1e7e6851e93c7
|
7
|
+
data.tar.gz: a57831fe861ac51fa43692b66175291a457077822cdb5f795a093fca1e44bf95fb2b6a312cfe8a6c2b3c3e873319ffd03436e6236874a6acdd45843a21bc4981
|
data/.github/workflows/test.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
data/ext/polyphony/fiber.c
CHANGED
data/ext/polyphony/polyphony.h
CHANGED
@@ -74,7 +74,7 @@ void Fiber_make_runnable(VALUE fiber, VALUE value);
|
|
74
74
|
|
75
75
|
VALUE Queue_push(VALUE self, VALUE value);
|
76
76
|
VALUE Queue_unshift(VALUE self, VALUE value);
|
77
|
-
VALUE Queue_shift(VALUE self);
|
77
|
+
VALUE Queue_shift(int argc,VALUE *argv, VALUE self);
|
78
78
|
VALUE Queue_shift_all(VALUE self);
|
79
79
|
|
80
80
|
void Runqueue_push(VALUE self, VALUE fiber, VALUE value, int reschedule);
|
data/ext/polyphony/queue.c
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
#include "ring_buffer.h"
|
3
3
|
|
4
4
|
typedef struct queue {
|
5
|
+
unsigned int closed;
|
5
6
|
ring_buffer values;
|
6
7
|
ring_buffer shift_queue;
|
7
8
|
ring_buffer push_queue;
|
@@ -9,6 +10,8 @@ typedef struct queue {
|
|
9
10
|
} Queue_t;
|
10
11
|
|
11
12
|
VALUE cQueue = Qnil;
|
13
|
+
VALUE cClosedQueueError = Qnil;
|
14
|
+
VALUE cThreadError = Qnil;
|
12
15
|
|
13
16
|
static void Queue_mark(void *ptr) {
|
14
17
|
Queue_t *queue = ptr;
|
@@ -49,6 +52,7 @@ static VALUE Queue_initialize(int argc, VALUE *argv, VALUE self) {
|
|
49
52
|
Queue_t *queue;
|
50
53
|
GetQueue(self, queue);
|
51
54
|
|
55
|
+
queue->closed = 0;
|
52
56
|
ring_buffer_init(&queue->values);
|
53
57
|
ring_buffer_init(&queue->shift_queue);
|
54
58
|
ring_buffer_init(&queue->push_queue);
|
@@ -99,6 +103,9 @@ VALUE Queue_push(VALUE self, VALUE value) {
|
|
99
103
|
Queue_t *queue;
|
100
104
|
GetQueue(self, queue);
|
101
105
|
|
106
|
+
if (queue->closed)
|
107
|
+
rb_raise(cClosedQueueError, "queue closed");
|
108
|
+
|
102
109
|
if (queue->capacity) capped_queue_block_push(queue);
|
103
110
|
|
104
111
|
queue_schedule_first_blocked_fiber(&queue->shift_queue);
|
@@ -111,6 +118,9 @@ VALUE Queue_unshift(VALUE self, VALUE value) {
|
|
111
118
|
Queue_t *queue;
|
112
119
|
GetQueue(self, queue);
|
113
120
|
|
121
|
+
if (queue->closed)
|
122
|
+
rb_raise(cClosedQueueError, "queue closed");
|
123
|
+
|
114
124
|
if (queue->capacity) capped_queue_block_push(queue);
|
115
125
|
|
116
126
|
queue_schedule_first_blocked_fiber(&queue->shift_queue);
|
@@ -119,14 +129,25 @@ VALUE Queue_unshift(VALUE self, VALUE value) {
|
|
119
129
|
return self;
|
120
130
|
}
|
121
131
|
|
122
|
-
VALUE
|
123
|
-
|
132
|
+
VALUE Queue_shift_nonblock(Queue_t *queue) {
|
133
|
+
if (queue->values.count) {
|
134
|
+
VALUE value = ring_buffer_shift(&queue->values);
|
135
|
+
if ((queue->capacity) && (queue->capacity > queue->values.count))
|
136
|
+
queue_schedule_first_blocked_fiber(&queue->push_queue);
|
137
|
+
RB_GC_GUARD(value);
|
138
|
+
return value;
|
139
|
+
}
|
140
|
+
rb_raise(cThreadError, "queue empty");
|
141
|
+
}
|
142
|
+
|
143
|
+
VALUE Queue_shift_block(Queue_t *queue) {
|
124
144
|
VALUE fiber = rb_fiber_current();
|
125
145
|
VALUE thread = rb_thread_current();
|
126
146
|
VALUE backend = rb_ivar_get(thread, ID_ivar_backend);
|
127
147
|
VALUE value;
|
128
148
|
|
129
|
-
|
149
|
+
if (queue->closed && !queue->values.count)
|
150
|
+
rb_raise(cClosedQueueError, "queue closed");
|
130
151
|
|
131
152
|
while (1) {
|
132
153
|
VALUE switchpoint_result;
|
@@ -140,6 +161,7 @@ VALUE Queue_shift(VALUE self) {
|
|
140
161
|
RAISE_IF_EXCEPTION(switchpoint_result);
|
141
162
|
RB_GC_GUARD(switchpoint_result);
|
142
163
|
if (queue->values.count) break;
|
164
|
+
if (queue->closed) return Qnil;
|
143
165
|
}
|
144
166
|
value = ring_buffer_shift(&queue->values);
|
145
167
|
if ((queue->capacity) && (queue->capacity > queue->values.count))
|
@@ -148,6 +170,16 @@ VALUE Queue_shift(VALUE self) {
|
|
148
170
|
return value;
|
149
171
|
}
|
150
172
|
|
173
|
+
VALUE Queue_shift(int argc,VALUE *argv, VALUE self) {
|
174
|
+
int nonblock = argc && RTEST(argv[0]);
|
175
|
+
Queue_t *queue;
|
176
|
+
GetQueue(self, queue);
|
177
|
+
|
178
|
+
return nonblock ?
|
179
|
+
Queue_shift_nonblock(queue) :
|
180
|
+
Queue_shift_block(queue);
|
181
|
+
}
|
182
|
+
|
151
183
|
VALUE Queue_delete(VALUE self, VALUE value) {
|
152
184
|
Queue_t *queue;
|
153
185
|
GetQueue(self, queue);
|
@@ -244,6 +276,13 @@ VALUE Queue_pending_p(VALUE self) {
|
|
244
276
|
return (queue->shift_queue.count) ? Qtrue : Qfalse;
|
245
277
|
}
|
246
278
|
|
279
|
+
VALUE Queue_num_waiting(VALUE self) {
|
280
|
+
Queue_t *queue;
|
281
|
+
GetQueue(self, queue);
|
282
|
+
|
283
|
+
return INT2NUM(queue->shift_queue.count);
|
284
|
+
}
|
285
|
+
|
247
286
|
VALUE Queue_size_m(VALUE self) {
|
248
287
|
Queue_t *queue;
|
249
288
|
GetQueue(self, queue);
|
@@ -251,20 +290,54 @@ VALUE Queue_size_m(VALUE self) {
|
|
251
290
|
return INT2NUM(queue->values.count);
|
252
291
|
}
|
253
292
|
|
293
|
+
VALUE Queue_closed_p(VALUE self) {
|
294
|
+
Queue_t *queue;
|
295
|
+
GetQueue(self, queue);
|
296
|
+
|
297
|
+
return (queue->closed) ? Qtrue : Qfalse;
|
298
|
+
}
|
299
|
+
|
300
|
+
VALUE Queue_close(VALUE self) {
|
301
|
+
Queue_t *queue;
|
302
|
+
GetQueue(self, queue);
|
303
|
+
|
304
|
+
if (queue->closed) goto end;
|
305
|
+
queue->closed = 1;
|
306
|
+
|
307
|
+
// release all fibers waiting on `#shift`
|
308
|
+
while (queue->shift_queue.count) {
|
309
|
+
VALUE fiber = ring_buffer_shift(&queue->shift_queue);
|
310
|
+
if (fiber == Qnil) break;
|
311
|
+
Fiber_make_runnable(fiber, Qnil);
|
312
|
+
}
|
313
|
+
|
314
|
+
end:
|
315
|
+
return self;
|
316
|
+
}
|
317
|
+
|
254
318
|
void Init_Queue() {
|
319
|
+
cClosedQueueError = rb_const_get(rb_cObject, rb_intern("ClosedQueueError"));
|
320
|
+
cThreadError = rb_const_get(rb_cObject, rb_intern("ThreadError"));
|
321
|
+
|
255
322
|
cQueue = rb_define_class_under(mPolyphony, "Queue", rb_cObject);
|
256
323
|
rb_define_alloc_func(cQueue, Queue_allocate);
|
257
324
|
|
258
325
|
rb_define_method(cQueue, "initialize", Queue_initialize, -1);
|
259
326
|
rb_define_method(cQueue, "push", Queue_push, 1);
|
260
327
|
rb_define_method(cQueue, "<<", Queue_push, 1);
|
328
|
+
rb_define_method(cQueue, "enq", Queue_push, 1);
|
261
329
|
rb_define_method(cQueue, "unshift", Queue_unshift, 1);
|
262
330
|
|
263
|
-
rb_define_method(cQueue, "shift", Queue_shift,
|
264
|
-
rb_define_method(cQueue, "pop", Queue_shift,
|
331
|
+
rb_define_method(cQueue, "shift", Queue_shift, -1);
|
332
|
+
rb_define_method(cQueue, "pop", Queue_shift, -1);
|
333
|
+
rb_define_method(cQueue, "deq", Queue_shift, -1);
|
334
|
+
|
265
335
|
rb_define_method(cQueue, "delete", Queue_delete, 1);
|
266
336
|
rb_define_method(cQueue, "clear", Queue_clear, 0);
|
267
337
|
|
338
|
+
rb_define_method(cQueue, "size", Queue_size_m, 0);
|
339
|
+
rb_define_method(cQueue, "length", Queue_size_m, 0);
|
340
|
+
|
268
341
|
rb_define_method(cQueue, "cap", Queue_cap, 1);
|
269
342
|
rb_define_method(cQueue, "capped?", Queue_capped_p, 0);
|
270
343
|
|
@@ -273,5 +346,8 @@ void Init_Queue() {
|
|
273
346
|
rb_define_method(cQueue, "flush_waiters", Queue_flush_waiters, 1);
|
274
347
|
rb_define_method(cQueue, "empty?", Queue_empty_p, 0);
|
275
348
|
rb_define_method(cQueue, "pending?", Queue_pending_p, 0);
|
276
|
-
rb_define_method(cQueue, "
|
349
|
+
rb_define_method(cQueue, "num_waiting", Queue_num_waiting, 0);
|
350
|
+
|
351
|
+
rb_define_method(cQueue, "closed?", Queue_closed_p, 0);
|
352
|
+
rb_define_method(cQueue, "close", Queue_close, 0);
|
277
353
|
}
|
data/lib/polyphony/core/debug.rb
CHANGED
@@ -6,6 +6,8 @@ module ::Kernel
|
|
6
6
|
def format_trace(args)
|
7
7
|
if args.size > 1 && args.first.is_a?(String)
|
8
8
|
format("%s: %p\n", args.shift, args.size == 1 ? args.first : args)
|
9
|
+
elsif args.size == 1 && args.first.is_a?(String)
|
10
|
+
"#{args.first}\n"
|
9
11
|
else
|
10
12
|
format("%p\n", args.size == 1 ? args.first : args)
|
11
13
|
end
|
data/lib/polyphony/version.rb
CHANGED
data/test/test_queue.rb
CHANGED
@@ -21,6 +21,44 @@ class QueueTest < MiniTest::Test
|
|
21
21
|
assert_equal [1, 2, 3, 4], buf
|
22
22
|
end
|
23
23
|
|
24
|
+
def test_chained_push
|
25
|
+
@queue << 5 << 6 << 7
|
26
|
+
|
27
|
+
buf = []
|
28
|
+
3.times { buf << @queue.shift }
|
29
|
+
assert_equal [5, 6, 7], buf
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_push_aliases
|
33
|
+
@queue.push 1
|
34
|
+
@queue << 2
|
35
|
+
@queue.enq 3
|
36
|
+
|
37
|
+
buf = []
|
38
|
+
3.times { buf << @queue.shift }
|
39
|
+
assert_equal [1, 2, 3], buf
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_pop_aliases
|
43
|
+
@queue << 1 << 2 << 3
|
44
|
+
|
45
|
+
assert_equal 1, @queue.pop
|
46
|
+
assert_equal 2, @queue.deq
|
47
|
+
assert_equal 3, @queue.shift
|
48
|
+
|
49
|
+
@queue << 1 << 2 << 3
|
50
|
+
|
51
|
+
assert_equal 1, @queue.pop(false)
|
52
|
+
assert_equal 2, @queue.deq(false)
|
53
|
+
assert_equal 3, @queue.shift(false)
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_nonblocking_pop
|
57
|
+
assert_raises(ThreadError) { @queue.pop(true) }
|
58
|
+
assert_raises(ThreadError) { @queue.deq(true) }
|
59
|
+
assert_raises(ThreadError) { @queue.shift(true) }
|
60
|
+
end
|
61
|
+
|
24
62
|
def test_unshift
|
25
63
|
@queue.push 1
|
26
64
|
@queue.push 2
|
@@ -112,22 +150,86 @@ class QueueTest < MiniTest::Test
|
|
112
150
|
|
113
151
|
def test_queue_size
|
114
152
|
assert_equal 0, @queue.size
|
153
|
+
assert_equal 0, @queue.length
|
115
154
|
|
116
155
|
@queue.push 1
|
117
156
|
|
118
157
|
assert_equal 1, @queue.size
|
158
|
+
assert_equal 1, @queue.length
|
119
159
|
|
120
160
|
@queue.push 2
|
121
161
|
|
122
162
|
assert_equal 2, @queue.size
|
163
|
+
assert_equal 2, @queue.length
|
123
164
|
|
124
165
|
@queue.shift
|
125
166
|
|
126
167
|
assert_equal 1, @queue.size
|
168
|
+
assert_equal 1, @queue.length
|
127
169
|
|
128
170
|
@queue.shift
|
129
171
|
|
130
172
|
assert_equal 0, @queue.size
|
173
|
+
assert_equal 0, @queue.length
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_pending?
|
177
|
+
assert_equal false, @queue.pending?
|
178
|
+
|
179
|
+
buf = []
|
180
|
+
f = spin { buf << @queue.shift }
|
181
|
+
snooze
|
182
|
+
assert_equal true, @queue.pending?
|
183
|
+
|
184
|
+
@queue << 42
|
185
|
+
f.await
|
186
|
+
assert_equal [42], buf
|
187
|
+
assert_equal false, @queue.pending?
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_num_waiting
|
191
|
+
assert_equal 0, @queue.num_waiting
|
192
|
+
|
193
|
+
f1 = spin { @queue.shift }
|
194
|
+
snooze # allow fiber to start
|
195
|
+
assert_equal 1, @queue.num_waiting
|
196
|
+
|
197
|
+
f2 = spin { @queue.shift }
|
198
|
+
snooze # allow fiber to start
|
199
|
+
assert_equal 2, @queue.num_waiting
|
200
|
+
|
201
|
+
@queue << 1
|
202
|
+
f1.await
|
203
|
+
assert_equal 1, @queue.num_waiting
|
204
|
+
|
205
|
+
@queue << 2
|
206
|
+
f2.await
|
207
|
+
assert_equal 0, @queue.num_waiting
|
208
|
+
end
|
209
|
+
|
210
|
+
def test_closed_queue
|
211
|
+
assert_equal false, @queue.closed?
|
212
|
+
|
213
|
+
buf = []
|
214
|
+
f = spin { buf << @queue.shift }
|
215
|
+
snooze # allow fiber to start
|
216
|
+
|
217
|
+
@queue.close
|
218
|
+
assert_equal true, @queue.closed?
|
219
|
+
cancel_after(1) { f.await }
|
220
|
+
assert_equal [nil], buf
|
221
|
+
|
222
|
+
assert_raises(ClosedQueueError) { @queue << 1 }
|
223
|
+
assert_raises(ClosedQueueError) { @queue.deq }
|
224
|
+
assert_raises(ThreadError) { @queue.pop(true) }
|
225
|
+
|
226
|
+
# test deq on closed non-empty queue
|
227
|
+
@queue = Polyphony::Queue.new
|
228
|
+
@queue << 42 << 43
|
229
|
+
@queue.close
|
230
|
+
|
231
|
+
assert_equal 42, @queue.deq(false)
|
232
|
+
assert_equal 43, @queue.deq(true)
|
131
233
|
end
|
132
234
|
end
|
133
235
|
|
@@ -246,4 +348,4 @@ class CappedQueueTest < MiniTest::Test
|
|
246
348
|
a.join
|
247
349
|
assert_equal [1, 2, 3, :d5, 4, :d8, 5], buffer
|
248
350
|
end
|
249
|
-
end
|
351
|
+
end
|
data/test/test_supervise.rb
CHANGED
@@ -269,4 +269,31 @@ class SuperviseTest < MiniTest::Test
|
|
269
269
|
snooze
|
270
270
|
assert_equal [[f1, :foo], [f2, :bar]], buffer
|
271
271
|
end
|
272
|
+
|
273
|
+
def test_detached_supervisor
|
274
|
+
buffer = []
|
275
|
+
|
276
|
+
s = nil
|
277
|
+
f = spin {
|
278
|
+
foo = spin do
|
279
|
+
sleep 0.1
|
280
|
+
ensure
|
281
|
+
buffer << :foo
|
282
|
+
end
|
283
|
+
bar = spin do
|
284
|
+
sleep 0.2
|
285
|
+
ensure
|
286
|
+
buffer << :bar
|
287
|
+
end
|
288
|
+
|
289
|
+
s = spin { supervise }.detach
|
290
|
+
Fiber.current.attach_all_children_to(s)
|
291
|
+
|
292
|
+
s.terminate(true)
|
293
|
+
}
|
294
|
+
|
295
|
+
f.await
|
296
|
+
s.await
|
297
|
+
assert_equal [:foo, :bar], buffer
|
298
|
+
end
|
272
299
|
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.78'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-02-
|
11
|
+
date: 2022-02-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|