polyphony 0.43.4 → 0.43.10

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.
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
-