polyphony 0.77 → 0.78
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/.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
|