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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 10f049946dc02d9cdd984cc8658687d2319e0fd85f6f2cce74aa0a887bc714cb
4
- data.tar.gz: 5118859d4640aebeddb9186c43d58617e9b455a63ea97c1dc8283432db954fd1
3
+ metadata.gz: 51eecc20956cb4f1a35a7f6510dea2730652700e99d29c7d42ade201a119ea2e
4
+ data.tar.gz: bc2b57dc2cc5a8918bba1d8bf526cdbe23f44d134f9bdca5018b9e9e66930f91
5
5
  SHA512:
6
- metadata.gz: e107e21d6c42f9cd9e91521e288dfee37a6f0da4b7d8a8d311924bf88ccf732d2cc94de834dbbaa3c7a974e5bb84ce1d8d20efd68870c9f2dac9b73155d28558
7
- data.tar.gz: 8e4f7005c9cbc46cd084bbe66a4e8f7145f6a4a3062ce027a70eee07c0e648f79289515591ef4b48010580b7125c403ab09e45417781346ebf6da4b2d528ec45
6
+ metadata.gz: 21c446f9a6fa032577b245e6de5155832c8e6932d6c17e58824a55923c82be014453b64b29ccbb66fe5d01cde8622d3275664acda403637954f1e7e6851e93c7
7
+ data.tar.gz: a57831fe861ac51fa43692b66175291a457077822cdb5f795a093fca1e44bf95fb2b6a312cfe8a6c2b3c3e873319ffd03436e6236874a6acdd45843a21bc4981
@@ -19,7 +19,7 @@ jobs:
19
19
  POLYPHONY_USE_LIBEV: "1"
20
20
 
21
21
  steps:
22
- - name: Setup OS
22
+ - name: Setup machine
23
23
  uses: actions/checkout@v1
24
24
  - name: Setup Ruby
25
25
  uses: ruby/setup-ruby@v1
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 0.78 2022-02-16
2
+
3
+ - Fix Polyphony::Queue API compatibility (#72)
4
+
1
5
  ## 0.77 2022-02-07
2
6
 
3
7
  - Fix behaviour of signal traps (#71)
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- polyphony (0.77)
4
+ polyphony (0.78)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -97,7 +97,7 @@ VALUE Fiber_receive(VALUE self) {
97
97
  mailbox = rb_funcall(cQueue, ID_new, 0);
98
98
  rb_ivar_set(self, ID_ivar_mailbox, mailbox);
99
99
  }
100
- return Queue_shift(mailbox);
100
+ return Queue_shift(0, 0, mailbox);
101
101
  }
102
102
 
103
103
  VALUE Fiber_mailbox(VALUE self) {
@@ -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);
@@ -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 Queue_shift(VALUE self) {
123
- Queue_t *queue;
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
- GetQueue(self, queue);
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, 0);
264
- rb_define_method(cQueue, "pop", Queue_shift, 0);
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, "size", Queue_size_m, 0);
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
  }
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polyphony
4
- VERSION = '0.77'
4
+ VERSION = '0.78'
5
5
  end
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
@@ -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.77'
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-07 00:00:00.000000000 Z
11
+ date: 2022-02-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler