polyphony 0.43.4 → 0.43.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +1 -1
  3. data/CHANGELOG.md +45 -0
  4. data/Gemfile.lock +1 -1
  5. data/README.md +21 -4
  6. data/TODO.md +1 -6
  7. data/bin/stress.rb +28 -0
  8. data/docs/_includes/head.html +40 -0
  9. data/docs/_includes/title.html +1 -0
  10. data/docs/_user-guide/web-server.md +11 -11
  11. data/docs/getting-started/overview.md +2 -2
  12. data/docs/index.md +4 -3
  13. data/docs/main-concepts/design-principles.md +23 -34
  14. data/docs/main-concepts/fiber-scheduling.md +1 -1
  15. data/docs/polyphony-logo.png +0 -0
  16. data/examples/core/xx-channels.rb +4 -2
  17. data/examples/core/xx-using-a-mutex.rb +2 -1
  18. data/examples/io/xx-happy-eyeballs.rb +21 -22
  19. data/examples/io/xx-zip.rb +19 -0
  20. data/examples/performance/fiber_transfer.rb +47 -0
  21. data/examples/performance/messaging.rb +29 -0
  22. data/examples/performance/multi_snooze.rb +11 -9
  23. data/examples/xx-spin.rb +32 -0
  24. data/ext/polyphony/agent.h +39 -0
  25. data/ext/polyphony/event.c +86 -0
  26. data/ext/polyphony/fiber.c +0 -5
  27. data/ext/polyphony/libev_agent.c +231 -79
  28. data/ext/polyphony/polyphony.c +2 -2
  29. data/ext/polyphony/polyphony.h +19 -16
  30. data/ext/polyphony/polyphony_ext.c +4 -2
  31. data/ext/polyphony/queue.c +194 -0
  32. data/ext/polyphony/ring_buffer.c +96 -0
  33. data/ext/polyphony/ring_buffer.h +28 -0
  34. data/ext/polyphony/thread.c +48 -31
  35. data/lib/polyphony.rb +5 -6
  36. data/lib/polyphony/core/channel.rb +3 -34
  37. data/lib/polyphony/core/resource_pool.rb +13 -75
  38. data/lib/polyphony/core/sync.rb +12 -9
  39. data/lib/polyphony/core/thread_pool.rb +1 -1
  40. data/lib/polyphony/extensions/core.rb +9 -0
  41. data/lib/polyphony/extensions/fiber.rb +9 -2
  42. data/lib/polyphony/extensions/io.rb +16 -15
  43. data/lib/polyphony/extensions/openssl.rb +8 -0
  44. data/lib/polyphony/extensions/socket.rb +13 -9
  45. data/lib/polyphony/extensions/thread.rb +1 -1
  46. data/lib/polyphony/version.rb +1 -1
  47. data/test/helper.rb +2 -2
  48. data/test/q.rb +24 -0
  49. data/test/test_agent.rb +2 -2
  50. data/test/test_event.rb +12 -0
  51. data/test/test_global_api.rb +2 -2
  52. data/test/test_io.rb +24 -2
  53. data/test/test_queue.rb +59 -1
  54. data/test/test_resource_pool.rb +0 -43
  55. data/test/test_trace.rb +18 -17
  56. metadata +16 -5
  57. data/ext/polyphony/libev_queue.c +0 -217
  58. data/lib/polyphony/event.rb +0 -27
@@ -6,7 +6,7 @@ class AgentTest < MiniTest::Test
6
6
  def setup
7
7
  super
8
8
  @prev_agent = Thread.current.agent
9
- @agent = Polyphony::LibevAgent.new
9
+ @agent = Polyphony::Agent.new
10
10
  Thread.current.agent = @agent
11
11
  end
12
12
 
@@ -97,7 +97,7 @@ class AgentTest < MiniTest::Test
97
97
  o.close
98
98
 
99
99
  # read_loop will snooze after every read
100
- 4.times { snooze }
100
+ 6.times { snooze }
101
101
 
102
102
  assert_equal [:ready, 'foo', 'bar', :done], buf
103
103
  end
@@ -34,6 +34,7 @@ class EventTest < MiniTest::Test
34
34
  }
35
35
  }
36
36
  snooze
37
+
37
38
  t = Thread.new do
38
39
  orig_sleep 0.001
39
40
  3.times { a.signal }
@@ -45,4 +46,15 @@ class EventTest < MiniTest::Test
45
46
  t&.kill
46
47
  t&.join
47
48
  end
49
+
50
+ def test_exception_while_waiting_for_event
51
+ e = Polyphony::Event.new
52
+
53
+ f = spin { e.await }
54
+ g = spin { f.raise 'foo' }
55
+
56
+ assert_raises(RuntimeError) do
57
+ f.await
58
+ end
59
+ end
48
60
  end
@@ -211,13 +211,13 @@ class SpinLoopTest < MiniTest::Test
211
211
 
212
212
  def test_spin_loop_location
213
213
  location = /^#{__FILE__}:#{__LINE__ + 1}/
214
- f = spin_loop {}
214
+ f = spin_loop { snooze }
215
215
 
216
216
  assert_match location, f.location
217
217
  end
218
218
 
219
219
  def test_spin_loop_tag
220
- f = spin_loop(:my_loop) {}
220
+ f = spin_loop(:my_loop) { snooze }
221
221
 
222
222
  assert_equal :my_loop, f.tag
223
223
  end
@@ -30,6 +30,14 @@ class IOTest < MiniTest::Test
30
30
  assert_equal 'hello', msg
31
31
  end
32
32
 
33
+ def test_write_multiple_arguments
34
+ i, o = IO.pipe
35
+ count = o.write('a', 'b', "\n", 'c')
36
+ assert_equal 4, count
37
+ o.close
38
+ assert_equal "ab\nc", i.read
39
+ end
40
+
33
41
  def test_that_double_chevron_method_returns_io
34
42
  assert_equal @o, @o << 'foo'
35
43
 
@@ -83,6 +91,20 @@ class IOTest < MiniTest::Test
83
91
 
84
92
  assert_raises(EOFError) { i.readpartial(1) }
85
93
  end
94
+
95
+ # see https://github.com/digital-fabric/polyphony/issues/30
96
+ def test_reopened_tempfile
97
+ file = Tempfile.new
98
+ file << 'hello: world'
99
+ file.close
100
+
101
+ buf = nil
102
+ File.open(file, 'r:bom|utf-8') do |f|
103
+ buf = f.read(16384)
104
+ end
105
+
106
+ assert_equal 'hello: world', buf
107
+ end
86
108
  end
87
109
 
88
110
  class IOClassMethodsTest < MiniTest::Test
@@ -121,7 +143,7 @@ class IOClassMethodsTest < MiniTest::Test
121
143
  assert_equal "end\n", lines[-1]
122
144
  end
123
145
 
124
- def test_read
146
+ def test_read_class_method
125
147
  s = IO.read(__FILE__)
126
148
  assert_kind_of String, s
127
149
  assert(!s.empty?)
@@ -144,7 +166,7 @@ class IOClassMethodsTest < MiniTest::Test
144
166
 
145
167
  WRITE_DATA = "foo\nbar קוקו"
146
168
 
147
- def test_write
169
+ def test_write_class_method
148
170
  fn = '/tmp/test_write'
149
171
  FileUtils.rm(fn) rescue nil
150
172
 
@@ -8,7 +8,7 @@ class QueueTest < MiniTest::Test
8
8
  @queue = Polyphony::Queue.new
9
9
  end
10
10
 
11
- def test_pop
11
+ def test_push_shift
12
12
  spin {
13
13
  @queue << 42
14
14
  }
@@ -21,6 +21,18 @@ class QueueTest < MiniTest::Test
21
21
  assert_equal [1, 2, 3, 4], buf
22
22
  end
23
23
 
24
+ def test_unshift
25
+ @queue.push 1
26
+ @queue.push 2
27
+ @queue.push 3
28
+ @queue.unshift 4
29
+
30
+ buf = []
31
+ buf << @queue.shift while !@queue.empty?
32
+
33
+ assert_equal [4, 1, 2, 3], buf
34
+ end
35
+
24
36
  def test_multiple_waiters
25
37
  a = spin { @queue.shift }
26
38
  b = spin { @queue.shift }
@@ -41,6 +53,19 @@ class QueueTest < MiniTest::Test
41
53
  buf = []
42
54
  @queue.shift_each { |i| buf << i }
43
55
  assert_equal [1, 2, 3, 4], buf
56
+
57
+ buf = []
58
+ @queue.shift_each { |i| buf << i }
59
+ assert_equal [], buf
60
+ end
61
+
62
+ def test_shift_all
63
+ (1..4).each { |i| @queue << i }
64
+ buf = @queue.shift_all
65
+ assert_equal [1, 2, 3, 4], buf
66
+
67
+ buf = @queue.shift_all
68
+ assert_equal [], buf
44
69
  end
45
70
 
46
71
  def test_empty?
@@ -71,4 +96,37 @@ class QueueTest < MiniTest::Test
71
96
  assert_nil f2.await
72
97
  assert_equal :bar, f3.await
73
98
  end
99
+
100
+ def test_fiber_removal_from_queue_simple
101
+ f1 = spin { @queue.shift }
102
+
103
+ # let fibers run
104
+ snooze
105
+
106
+ f1.stop
107
+ snooze
108
+
109
+ @queue << :foo
110
+ assert_nil f1.await
111
+ end
112
+
113
+ def test_queue_size
114
+ assert_equal 0, @queue.size
115
+
116
+ @queue.push 1
117
+
118
+ assert_equal 1, @queue.size
119
+
120
+ @queue.push 2
121
+
122
+ assert_equal 2, @queue.size
123
+
124
+ @queue.shift
125
+
126
+ assert_equal 1, @queue.size
127
+
128
+ @queue.shift
129
+
130
+ assert_equal 0, @queue.size
131
+ end
74
132
  end
@@ -37,49 +37,6 @@ class ResourcePoolTest < MiniTest::Test
37
37
  assert_equal 2, pool.size
38
38
  end
39
39
 
40
- def test_discard
41
- resources = [+'a', +'b']
42
- pool = Polyphony::ResourcePool.new(limit: 2) { resources.shift }
43
-
44
- results = []
45
- 4.times {
46
- spin {
47
- snooze
48
- pool.acquire { |resource|
49
- results << resource
50
- resource.__discard__ if resource == 'b'
51
- snooze
52
- }
53
- }
54
- }
55
- 6.times { snooze }
56
-
57
- assert_equal ['a', 'b', 'a', 'a'], results
58
- assert_equal 1, pool.size
59
- end
60
-
61
- def test_add
62
- resources = [+'a', +'b']
63
- pool = Polyphony::ResourcePool.new(limit: 2) { resources.shift }
64
-
65
- pool << +'c'
66
-
67
- results = []
68
- 4.times {
69
- spin {
70
- snooze
71
- pool.acquire { |resource|
72
- results << resource
73
- resource.__discard__ if resource == 'b'
74
- snooze
75
- }
76
- }
77
- }
78
- 6.times { snooze }
79
-
80
- assert_equal ['c', 'a', 'c', 'a'], results
81
- end
82
-
83
40
  def test_single_resource_limit
84
41
  resources = [+'a', +'b']
85
42
  pool = Polyphony::ResourcePool.new(limit: 1) { resources.shift }
@@ -34,7 +34,8 @@ class TraceTest < MiniTest::Test
34
34
 
35
35
  def test_2_fiber_trace
36
36
  records = []
37
- t = Polyphony::Trace.new(:fiber_all) { |r| records << r if r[:event] =~ /^fiber_/ }
37
+ thread = Thread.current
38
+ t = Polyphony::Trace.new(:fiber_all) { |r| records << r if Thread.current == thread && r[:event] =~ /^fiber_/ }
38
39
  t.enable
39
40
  Polyphony.trace(true)
40
41
 
@@ -42,23 +43,23 @@ class TraceTest < MiniTest::Test
42
43
  suspend
43
44
  sleep 0
44
45
 
45
- events = records.map { |r| [r[:fiber], r[:event]] }
46
+ events = records.map { |r| [r[:fiber] == f ? :f : :current, r[:event]] }
46
47
  assert_equal [
47
- [f, :fiber_create],
48
- [f, :fiber_schedule],
49
- [Fiber.current, :fiber_switchpoint],
50
- [f, :fiber_run],
51
- [f, :fiber_switchpoint],
52
- [f, :fiber_ev_loop_enter],
53
- [f, :fiber_schedule],
54
- [f, :fiber_ev_loop_leave],
55
- [f, :fiber_run],
56
- [f, :fiber_terminate],
57
- [Fiber.current, :fiber_switchpoint],
58
- [Fiber.current, :fiber_ev_loop_enter],
59
- [Fiber.current, :fiber_schedule],
60
- [Fiber.current, :fiber_ev_loop_leave],
61
- [Fiber.current, :fiber_run]
48
+ [:f, :fiber_create],
49
+ [:f, :fiber_schedule],
50
+ [:current, :fiber_switchpoint],
51
+ [:f, :fiber_run],
52
+ [:f, :fiber_switchpoint],
53
+ [:f, :fiber_ev_loop_enter],
54
+ [:f, :fiber_schedule],
55
+ [:f, :fiber_ev_loop_leave],
56
+ [:f, :fiber_run],
57
+ [:f, :fiber_terminate],
58
+ [:current, :fiber_switchpoint],
59
+ [:current, :fiber_ev_loop_enter],
60
+ [:current, :fiber_schedule],
61
+ [:current, :fiber_ev_loop_leave],
62
+ [:current, :fiber_run]
62
63
  ], events
63
64
  ensure
64
65
  t&.disable
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.43.4
4
+ version: 0.43.10
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-07-09 00:00:00.000000000 Z
11
+ date: 2020-07-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -241,7 +241,10 @@ files:
241
241
  - Rakefile
242
242
  - TODO.md
243
243
  - bin/polyphony-debug
244
+ - bin/stress.rb
244
245
  - docs/_config.yml
246
+ - docs/_includes/head.html
247
+ - docs/_includes/title.html
245
248
  - docs/_sass/custom/custom.scss
246
249
  - docs/_sass/overrides.scss
247
250
  - docs/_user-guide/all-about-timers.md
@@ -351,8 +354,11 @@ files:
351
354
  - examples/io/xx-system.rb
352
355
  - examples/io/xx-tcpserver.rb
353
356
  - examples/io/xx-tcpsocket.rb
357
+ - examples/io/xx-zip.rb
358
+ - examples/performance/fiber_transfer.rb
354
359
  - examples/performance/fs_read.rb
355
360
  - examples/performance/mem-usage.rb
361
+ - examples/performance/messaging.rb
356
362
  - examples/performance/multi_snooze.rb
357
363
  - examples/performance/snooze.rb
358
364
  - examples/performance/snooze_raw.rb
@@ -366,6 +372,7 @@ files:
366
372
  - examples/performance/xx-array.rb
367
373
  - examples/performance/xx-fiber-switch.rb
368
374
  - examples/performance/xx-snooze.rb
375
+ - examples/xx-spin.rb
369
376
  - ext/libev/Changes
370
377
  - ext/libev/LICENSE
371
378
  - ext/libev/README
@@ -382,15 +389,19 @@ files:
382
389
  - ext/libev/ev_win32.c
383
390
  - ext/libev/ev_wrap.h
384
391
  - ext/libev/test_libev_win32.c
392
+ - ext/polyphony/agent.h
393
+ - ext/polyphony/event.c
385
394
  - ext/polyphony/extconf.rb
386
395
  - ext/polyphony/fiber.c
387
396
  - ext/polyphony/libev.c
388
397
  - ext/polyphony/libev.h
389
398
  - ext/polyphony/libev_agent.c
390
- - ext/polyphony/libev_queue.c
391
399
  - ext/polyphony/polyphony.c
392
400
  - ext/polyphony/polyphony.h
393
401
  - ext/polyphony/polyphony_ext.c
402
+ - ext/polyphony/queue.c
403
+ - ext/polyphony/ring_buffer.c
404
+ - ext/polyphony/ring_buffer.h
394
405
  - ext/polyphony/thread.c
395
406
  - ext/polyphony/tracing.c
396
407
  - lib/polyphony.rb
@@ -407,7 +418,6 @@ files:
407
418
  - lib/polyphony/core/sync.rb
408
419
  - lib/polyphony/core/thread_pool.rb
409
420
  - lib/polyphony/core/throttler.rb
410
- - lib/polyphony/event.rb
411
421
  - lib/polyphony/extensions/core.rb
412
422
  - lib/polyphony/extensions/fiber.rb
413
423
  - lib/polyphony/extensions/io.rb
@@ -420,6 +430,7 @@ files:
420
430
  - test/coverage.rb
421
431
  - test/eg.rb
422
432
  - test/helper.rb
433
+ - test/q.rb
423
434
  - test/run.rb
424
435
  - test/stress.rb
425
436
  - test/test_agent.rb
@@ -466,7 +477,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
466
477
  - !ruby/object:Gem::Version
467
478
  version: '0'
468
479
  requirements: []
469
- rubygems_version: 3.0.6
480
+ rubygems_version: 3.0.8
470
481
  signing_key:
471
482
  specification_version: 4
472
483
  summary: Fine grained concurrency for Ruby
@@ -1,217 +0,0 @@
1
- #include "polyphony.h"
2
-
3
- struct async_watcher {
4
- ev_async async;
5
- struct ev_loop *ev_loop;
6
- VALUE fiber;
7
- };
8
-
9
- struct async_queue {
10
- struct async_watcher **queue;
11
- unsigned int len;
12
- unsigned int count;
13
- unsigned int push_idx;
14
- unsigned int pop_idx;
15
- };
16
-
17
- void async_queue_init(struct async_queue *queue) {
18
- queue->len = 4;
19
- queue->count = 0;
20
- queue->queue = malloc(sizeof(struct async_watcher *) * queue->len);
21
- queue->push_idx = 0;
22
- queue->pop_idx = 0;
23
- }
24
-
25
- void async_queue_free(struct async_queue *queue) {
26
- free(queue->queue);
27
- }
28
-
29
- void async_queue_push(struct async_queue *queue, struct async_watcher *watcher) {
30
- if (queue->push_idx == queue->len) {
31
- queue->len = queue->len * 2;
32
- queue->queue = realloc(queue->queue, sizeof(struct async_watcher *) * queue->len);
33
- }
34
- if (queue->count == 0) {
35
- queue->push_idx = 0;
36
- queue->pop_idx = 0;
37
- }
38
- queue->count++;
39
- queue->queue[queue->push_idx++] = watcher;
40
- }
41
-
42
- struct async_watcher *async_queue_pop(struct async_queue *queue) {
43
- if (queue->count == 0) return 0;
44
-
45
- queue->count--;
46
-
47
- return queue->queue[queue->pop_idx++];
48
- }
49
-
50
- void async_queue_remove_at_idx(struct async_queue *queue, unsigned int remove_idx) {
51
- queue->count--;
52
- queue->push_idx--;
53
- if (remove_idx < queue->push_idx)
54
- memmove(
55
- queue->queue + remove_idx,
56
- queue->queue + remove_idx + 1,
57
- (queue->push_idx - remove_idx) * sizeof(struct async_watcher *)
58
- );
59
- }
60
-
61
- void async_queue_remove_by_fiber(struct async_queue *queue, VALUE fiber) {
62
- if (queue->count == 0) return;
63
-
64
- for (unsigned idx = queue->pop_idx; idx < queue->push_idx; idx++) {
65
- if (queue->queue[idx]->fiber == fiber) {
66
- async_queue_remove_at_idx(queue, idx);
67
- return;
68
- }
69
- }
70
- }
71
-
72
- typedef struct queue {
73
- VALUE items;
74
- struct async_queue shift_queue;
75
- } LibevQueue_t;
76
-
77
-
78
- VALUE cLibevQueue = Qnil;
79
-
80
- static void LibevQueue_mark(void *ptr) {
81
- LibevQueue_t *queue = ptr;
82
- rb_gc_mark(queue->items);
83
- }
84
-
85
- static void LibevQueue_free(void *ptr) {
86
- LibevQueue_t *queue = ptr;
87
- async_queue_free(&queue->shift_queue);
88
- xfree(ptr);
89
- }
90
-
91
- static size_t LibevQueue_size(const void *ptr) {
92
- return sizeof(LibevQueue_t);
93
- }
94
-
95
- static const rb_data_type_t LibevQueue_type = {
96
- "Queue",
97
- {LibevQueue_mark, LibevQueue_free, LibevQueue_size,},
98
- 0, 0, 0
99
- };
100
-
101
- static VALUE LibevQueue_allocate(VALUE klass) {
102
- LibevQueue_t *queue;
103
-
104
- queue = ALLOC(LibevQueue_t);
105
- return TypedData_Wrap_Struct(klass, &LibevQueue_type, queue);
106
- }
107
-
108
- #define GetQueue(obj, queue) \
109
- TypedData_Get_Struct((obj), LibevQueue_t, &LibevQueue_type, (queue))
110
-
111
- static VALUE LibevQueue_initialize(VALUE self) {
112
- LibevQueue_t *queue;
113
- GetQueue(self, queue);
114
-
115
- queue->items = rb_ary_new();
116
- async_queue_init(&queue->shift_queue);
117
-
118
- return self;
119
- }
120
-
121
- VALUE LibevQueue_push(VALUE self, VALUE value) {
122
- LibevQueue_t *queue;
123
- GetQueue(self, queue);
124
- if (queue->shift_queue.count > 0) {
125
- struct async_watcher *watcher = async_queue_pop(&queue->shift_queue);
126
- if (watcher) {
127
- ev_async_send(watcher->ev_loop, &watcher->async);
128
- }
129
- }
130
- rb_ary_push(queue->items, value);
131
- return self;
132
- }
133
-
134
- struct ev_loop *LibevAgent_ev_loop(VALUE self);
135
-
136
- void async_queue_callback(struct ev_loop *ev_loop, struct ev_async *ev_async, int revents) {
137
- struct async_watcher *watcher = (struct async_watcher *)ev_async;
138
- Fiber_make_runnable(watcher->fiber, Qnil);
139
- }
140
-
141
- VALUE libev_agent_await(VALUE self);
142
-
143
- VALUE LibevQueue_shift(VALUE self) {
144
- LibevQueue_t *queue;
145
- GetQueue(self, queue);
146
-
147
- if (RARRAY_LEN(queue->items) == 0) {
148
- struct async_watcher watcher;
149
- VALUE agent = rb_ivar_get(rb_thread_current(), ID_ivar_agent);
150
- VALUE switchpoint_result = Qnil;
151
-
152
- watcher.ev_loop = LibevAgent_ev_loop(agent);
153
- watcher.fiber = rb_fiber_current();
154
- async_queue_push(&queue->shift_queue, &watcher);
155
- ev_async_init(&watcher.async, async_queue_callback);
156
- ev_async_start(watcher.ev_loop, &watcher.async);
157
-
158
- switchpoint_result = libev_agent_await(agent);
159
- ev_async_stop(watcher.ev_loop, &watcher.async);
160
-
161
- if (RTEST(rb_obj_is_kind_of(switchpoint_result, rb_eException))) {
162
- async_queue_remove_by_fiber(&queue->shift_queue, watcher.fiber);
163
- return rb_funcall(rb_mKernel, ID_raise, 1, switchpoint_result);
164
- }
165
- RB_GC_GUARD(watcher.fiber);
166
- RB_GC_GUARD(agent);
167
- RB_GC_GUARD(switchpoint_result);
168
- }
169
-
170
- return rb_ary_shift(queue->items);
171
- }
172
-
173
- VALUE LibevQueue_shift_each(VALUE self) {
174
- LibevQueue_t *queue;
175
- VALUE old_queue;
176
- GetQueue(self, queue);
177
- old_queue = queue->items;
178
- queue->items = rb_ary_new();
179
-
180
- if (rb_block_given_p()) {
181
- long len = RARRAY_LEN(old_queue);
182
- long i;
183
- for (i = 0; i < len; i++) {
184
- rb_yield(RARRAY_AREF(old_queue, i));
185
- }
186
- RB_GC_GUARD(old_queue);
187
- return self;
188
- }
189
- else {
190
- RB_GC_GUARD(old_queue);
191
- return old_queue;
192
- }
193
- }
194
-
195
- VALUE LibevQueue_empty_p(VALUE self) {
196
- LibevQueue_t *queue;
197
- GetQueue(self, queue);
198
-
199
- return (RARRAY_LEN(queue->items) == 0) ? Qtrue : Qfalse;
200
- }
201
-
202
- void Init_LibevQueue() {
203
- cLibevQueue = rb_define_class_under(mPolyphony, "LibevQueue", rb_cData);
204
- rb_define_alloc_func(cLibevQueue, LibevQueue_allocate);
205
-
206
- rb_define_method(cLibevQueue, "initialize", LibevQueue_initialize, 0);
207
- rb_define_method(cLibevQueue, "push", LibevQueue_push, 1);
208
- rb_define_method(cLibevQueue, "<<", LibevQueue_push, 1);
209
-
210
- rb_define_method(cLibevQueue, "pop", LibevQueue_shift, 0);
211
- rb_define_method(cLibevQueue, "shift", LibevQueue_shift, 0);
212
-
213
- rb_define_method(cLibevQueue, "shift_each", LibevQueue_shift_each, 0);
214
- rb_define_method(cLibevQueue, "empty?", LibevQueue_empty_p, 0);
215
- }
216
-
217
-