polyphony 0.77 → 0.78

Sign up to get free protection for your applications and to get access to all the features.
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