polyphony 0.43.8

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 (221) hide show
  1. checksums.yaml +7 -0
  2. data/.gitbook.yaml +4 -0
  3. data/.github/workflows/test.yml +29 -0
  4. data/.gitignore +59 -0
  5. data/.rubocop.yml +175 -0
  6. data/CHANGELOG.md +393 -0
  7. data/Gemfile +3 -0
  8. data/Gemfile.lock +141 -0
  9. data/LICENSE +21 -0
  10. data/README.md +51 -0
  11. data/Rakefile +26 -0
  12. data/TODO.md +201 -0
  13. data/bin/polyphony-debug +87 -0
  14. data/docs/_config.yml +64 -0
  15. data/docs/_includes/head.html +40 -0
  16. data/docs/_includes/title.html +1 -0
  17. data/docs/_sass/custom/custom.scss +10 -0
  18. data/docs/_sass/overrides.scss +0 -0
  19. data/docs/_user-guide/all-about-timers.md +126 -0
  20. data/docs/_user-guide/index.md +9 -0
  21. data/docs/_user-guide/web-server.md +136 -0
  22. data/docs/api-reference/exception.md +27 -0
  23. data/docs/api-reference/fiber.md +425 -0
  24. data/docs/api-reference/index.md +9 -0
  25. data/docs/api-reference/io.md +36 -0
  26. data/docs/api-reference/object.md +99 -0
  27. data/docs/api-reference/polyphony-baseexception.md +33 -0
  28. data/docs/api-reference/polyphony-cancel.md +26 -0
  29. data/docs/api-reference/polyphony-moveon.md +24 -0
  30. data/docs/api-reference/polyphony-net.md +20 -0
  31. data/docs/api-reference/polyphony-process.md +28 -0
  32. data/docs/api-reference/polyphony-resourcepool.md +59 -0
  33. data/docs/api-reference/polyphony-restart.md +18 -0
  34. data/docs/api-reference/polyphony-terminate.md +18 -0
  35. data/docs/api-reference/polyphony-threadpool.md +67 -0
  36. data/docs/api-reference/polyphony-throttler.md +77 -0
  37. data/docs/api-reference/polyphony.md +36 -0
  38. data/docs/api-reference/thread.md +88 -0
  39. data/docs/assets/img/echo-fibers.svg +1 -0
  40. data/docs/assets/img/sleeping-fiber.svg +1 -0
  41. data/docs/faq.md +195 -0
  42. data/docs/favicon.ico +0 -0
  43. data/docs/getting-started/index.md +10 -0
  44. data/docs/getting-started/installing.md +34 -0
  45. data/docs/getting-started/overview.md +486 -0
  46. data/docs/getting-started/tutorial.md +359 -0
  47. data/docs/index.md +94 -0
  48. data/docs/main-concepts/concurrency.md +151 -0
  49. data/docs/main-concepts/design-principles.md +161 -0
  50. data/docs/main-concepts/exception-handling.md +291 -0
  51. data/docs/main-concepts/extending.md +89 -0
  52. data/docs/main-concepts/fiber-scheduling.md +197 -0
  53. data/docs/main-concepts/index.md +9 -0
  54. data/docs/polyphony-logo.png +0 -0
  55. data/examples/adapters/concurrent-ruby.rb +9 -0
  56. data/examples/adapters/pg_client.rb +36 -0
  57. data/examples/adapters/pg_notify.rb +35 -0
  58. data/examples/adapters/pg_pool.rb +43 -0
  59. data/examples/adapters/pg_transaction.rb +31 -0
  60. data/examples/adapters/redis_blpop.rb +12 -0
  61. data/examples/adapters/redis_channels.rb +122 -0
  62. data/examples/adapters/redis_client.rb +19 -0
  63. data/examples/adapters/redis_pubsub.rb +26 -0
  64. data/examples/adapters/redis_pubsub_perf.rb +68 -0
  65. data/examples/core/01-spinning-up-fibers.rb +18 -0
  66. data/examples/core/02-awaiting-fibers.rb +20 -0
  67. data/examples/core/03-interrupting.rb +39 -0
  68. data/examples/core/04-handling-signals.rb +19 -0
  69. data/examples/core/xx-agent.rb +102 -0
  70. data/examples/core/xx-at_exit.rb +29 -0
  71. data/examples/core/xx-caller.rb +12 -0
  72. data/examples/core/xx-channels.rb +45 -0
  73. data/examples/core/xx-daemon.rb +14 -0
  74. data/examples/core/xx-deadlock.rb +8 -0
  75. data/examples/core/xx-deferring-an-operation.rb +14 -0
  76. data/examples/core/xx-erlang-style-genserver.rb +81 -0
  77. data/examples/core/xx-exception-backtrace.rb +40 -0
  78. data/examples/core/xx-fork-cleanup.rb +22 -0
  79. data/examples/core/xx-fork-spin.rb +42 -0
  80. data/examples/core/xx-fork-terminate.rb +27 -0
  81. data/examples/core/xx-forking.rb +24 -0
  82. data/examples/core/xx-move_on.rb +23 -0
  83. data/examples/core/xx-pingpong.rb +18 -0
  84. data/examples/core/xx-queue-async.rb +120 -0
  85. data/examples/core/xx-readpartial.rb +18 -0
  86. data/examples/core/xx-recurrent-timer.rb +12 -0
  87. data/examples/core/xx-resource_delegate.rb +31 -0
  88. data/examples/core/xx-signals.rb +16 -0
  89. data/examples/core/xx-sleep-forever.rb +9 -0
  90. data/examples/core/xx-sleeping.rb +25 -0
  91. data/examples/core/xx-snooze-starve.rb +16 -0
  92. data/examples/core/xx-spin-fork.rb +49 -0
  93. data/examples/core/xx-spin_error_backtrace.rb +33 -0
  94. data/examples/core/xx-state-machine.rb +51 -0
  95. data/examples/core/xx-stop.rb +20 -0
  96. data/examples/core/xx-supervise-process.rb +30 -0
  97. data/examples/core/xx-supervisors.rb +21 -0
  98. data/examples/core/xx-thread-selector-sleep.rb +51 -0
  99. data/examples/core/xx-thread-selector-snooze.rb +46 -0
  100. data/examples/core/xx-thread-sleep.rb +17 -0
  101. data/examples/core/xx-thread-snooze.rb +34 -0
  102. data/examples/core/xx-thread_pool.rb +17 -0
  103. data/examples/core/xx-throttling.rb +18 -0
  104. data/examples/core/xx-timeout.rb +10 -0
  105. data/examples/core/xx-timer-gc.rb +17 -0
  106. data/examples/core/xx-trace.rb +79 -0
  107. data/examples/core/xx-using-a-mutex.rb +21 -0
  108. data/examples/core/xx-worker-thread.rb +30 -0
  109. data/examples/io/tunnel.rb +48 -0
  110. data/examples/io/xx-backticks.rb +11 -0
  111. data/examples/io/xx-echo_client.rb +25 -0
  112. data/examples/io/xx-echo_client_from_stdin.rb +21 -0
  113. data/examples/io/xx-echo_pipe.rb +16 -0
  114. data/examples/io/xx-echo_server.rb +17 -0
  115. data/examples/io/xx-echo_server_with_timeout.rb +34 -0
  116. data/examples/io/xx-echo_stdin.rb +14 -0
  117. data/examples/io/xx-happy-eyeballs.rb +36 -0
  118. data/examples/io/xx-httparty.rb +38 -0
  119. data/examples/io/xx-irb.rb +17 -0
  120. data/examples/io/xx-net-http.rb +15 -0
  121. data/examples/io/xx-open.rb +16 -0
  122. data/examples/io/xx-switch.rb +15 -0
  123. data/examples/io/xx-system.rb +11 -0
  124. data/examples/io/xx-tcpserver.rb +15 -0
  125. data/examples/io/xx-tcpsocket.rb +18 -0
  126. data/examples/io/xx-zip.rb +19 -0
  127. data/examples/performance/fiber_transfer.rb +47 -0
  128. data/examples/performance/fs_read.rb +38 -0
  129. data/examples/performance/mem-usage.rb +56 -0
  130. data/examples/performance/messaging.rb +29 -0
  131. data/examples/performance/multi_snooze.rb +33 -0
  132. data/examples/performance/snooze.rb +39 -0
  133. data/examples/performance/snooze_raw.rb +39 -0
  134. data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +74 -0
  135. data/examples/performance/thread-vs-fiber/polyphony_server.rb +45 -0
  136. data/examples/performance/thread-vs-fiber/polyphony_server_read_loop.rb +58 -0
  137. data/examples/performance/thread-vs-fiber/threaded_server.rb +27 -0
  138. data/examples/performance/thread-vs-fiber/xx-httparty_multi.rb +36 -0
  139. data/examples/performance/thread-vs-fiber/xx-httparty_threaded.rb +29 -0
  140. data/examples/performance/thread_pool_perf.rb +63 -0
  141. data/examples/performance/xx-array.rb +11 -0
  142. data/examples/performance/xx-fiber-switch.rb +9 -0
  143. data/examples/performance/xx-snooze.rb +15 -0
  144. data/examples/xx-spin.rb +32 -0
  145. data/ext/libev/Changes +548 -0
  146. data/ext/libev/LICENSE +37 -0
  147. data/ext/libev/README +59 -0
  148. data/ext/libev/README.embed +3 -0
  149. data/ext/libev/ev.c +5279 -0
  150. data/ext/libev/ev.h +856 -0
  151. data/ext/libev/ev_epoll.c +296 -0
  152. data/ext/libev/ev_kqueue.c +224 -0
  153. data/ext/libev/ev_linuxaio.c +642 -0
  154. data/ext/libev/ev_poll.c +156 -0
  155. data/ext/libev/ev_port.c +192 -0
  156. data/ext/libev/ev_select.c +316 -0
  157. data/ext/libev/ev_vars.h +215 -0
  158. data/ext/libev/ev_win32.c +162 -0
  159. data/ext/libev/ev_wrap.h +216 -0
  160. data/ext/libev/test_libev_win32.c +123 -0
  161. data/ext/polyphony/extconf.rb +20 -0
  162. data/ext/polyphony/fiber.c +109 -0
  163. data/ext/polyphony/libev.c +2 -0
  164. data/ext/polyphony/libev.h +9 -0
  165. data/ext/polyphony/libev_agent.c +882 -0
  166. data/ext/polyphony/polyphony.c +71 -0
  167. data/ext/polyphony/polyphony.h +97 -0
  168. data/ext/polyphony/polyphony_ext.c +21 -0
  169. data/ext/polyphony/queue.c +168 -0
  170. data/ext/polyphony/ring_buffer.c +96 -0
  171. data/ext/polyphony/ring_buffer.h +28 -0
  172. data/ext/polyphony/thread.c +208 -0
  173. data/ext/polyphony/tracing.c +11 -0
  174. data/lib/polyphony.rb +136 -0
  175. data/lib/polyphony/adapters/fs.rb +19 -0
  176. data/lib/polyphony/adapters/irb.rb +52 -0
  177. data/lib/polyphony/adapters/postgres.rb +110 -0
  178. data/lib/polyphony/adapters/process.rb +33 -0
  179. data/lib/polyphony/adapters/redis.rb +67 -0
  180. data/lib/polyphony/adapters/trace.rb +138 -0
  181. data/lib/polyphony/core/channel.rb +46 -0
  182. data/lib/polyphony/core/exceptions.rb +36 -0
  183. data/lib/polyphony/core/global_api.rb +124 -0
  184. data/lib/polyphony/core/resource_pool.rb +117 -0
  185. data/lib/polyphony/core/sync.rb +21 -0
  186. data/lib/polyphony/core/thread_pool.rb +64 -0
  187. data/lib/polyphony/core/throttler.rb +41 -0
  188. data/lib/polyphony/event.rb +17 -0
  189. data/lib/polyphony/extensions/core.rb +174 -0
  190. data/lib/polyphony/extensions/fiber.rb +379 -0
  191. data/lib/polyphony/extensions/io.rb +221 -0
  192. data/lib/polyphony/extensions/openssl.rb +81 -0
  193. data/lib/polyphony/extensions/socket.rb +150 -0
  194. data/lib/polyphony/extensions/thread.rb +108 -0
  195. data/lib/polyphony/net.rb +77 -0
  196. data/lib/polyphony/version.rb +5 -0
  197. data/polyphony.gemspec +40 -0
  198. data/test/coverage.rb +54 -0
  199. data/test/eg.rb +27 -0
  200. data/test/helper.rb +56 -0
  201. data/test/q.rb +24 -0
  202. data/test/run.rb +5 -0
  203. data/test/stress.rb +25 -0
  204. data/test/test_agent.rb +130 -0
  205. data/test/test_event.rb +59 -0
  206. data/test/test_ext.rb +196 -0
  207. data/test/test_fiber.rb +988 -0
  208. data/test/test_global_api.rb +352 -0
  209. data/test/test_io.rb +249 -0
  210. data/test/test_kernel.rb +57 -0
  211. data/test/test_process_supervision.rb +46 -0
  212. data/test/test_queue.rb +112 -0
  213. data/test/test_resource_pool.rb +138 -0
  214. data/test/test_signal.rb +100 -0
  215. data/test/test_socket.rb +34 -0
  216. data/test/test_supervise.rb +103 -0
  217. data/test/test_thread.rb +170 -0
  218. data/test/test_thread_pool.rb +101 -0
  219. data/test/test_throttler.rb +50 -0
  220. data/test/test_trace.rb +68 -0
  221. metadata +482 -0
@@ -0,0 +1,71 @@
1
+ #include "polyphony.h"
2
+
3
+ VALUE mPolyphony;
4
+
5
+ ID ID_call;
6
+ ID ID_caller;
7
+ ID ID_clear;
8
+ ID ID_each;
9
+ ID ID_inspect;
10
+ ID ID_new;
11
+ ID ID_raise;
12
+ ID ID_ivar_running;
13
+ ID ID_ivar_thread;
14
+ ID ID_runnable;
15
+ ID ID_runnable_value;
16
+ ID ID_size;
17
+ ID ID_signal;
18
+ ID ID_switch_fiber;
19
+ ID ID_transfer;
20
+ ID ID_R;
21
+ ID ID_W;
22
+ ID ID_RW;
23
+
24
+ VALUE Polyphony_snooze(VALUE self) {
25
+ VALUE ret;
26
+ VALUE fiber = rb_fiber_current();
27
+
28
+ Fiber_make_runnable(fiber, Qnil);
29
+ ret = Thread_switch_fiber(rb_thread_current());
30
+ TEST_RESUME_EXCEPTION(ret);
31
+ RB_GC_GUARD(ret);
32
+ return ret;
33
+ }
34
+
35
+ static VALUE Polyphony_suspend(VALUE self) {
36
+ VALUE ret = Thread_switch_fiber(rb_thread_current());
37
+
38
+ TEST_RESUME_EXCEPTION(ret);
39
+ RB_GC_GUARD(ret);
40
+ return ret;
41
+ }
42
+
43
+ VALUE Polyphony_trace(VALUE self, VALUE enabled) {
44
+ __tracing_enabled__ = RTEST(enabled) ? 1 : 0;
45
+ return Qnil;
46
+ }
47
+
48
+ void Init_Polyphony() {
49
+ mPolyphony = rb_define_module("Polyphony");
50
+
51
+ rb_define_singleton_method(mPolyphony, "trace", Polyphony_trace, 1);
52
+
53
+ rb_define_global_function("snooze", Polyphony_snooze, 0);
54
+ rb_define_global_function("suspend", Polyphony_suspend, 0);
55
+
56
+ ID_call = rb_intern("call");
57
+ ID_caller = rb_intern("caller");
58
+ ID_clear = rb_intern("clear");
59
+ ID_each = rb_intern("each");
60
+ ID_inspect = rb_intern("inspect");
61
+ ID_ivar_running = rb_intern("@running");
62
+ ID_ivar_thread = rb_intern("@thread");
63
+ ID_new = rb_intern("new");
64
+ ID_raise = rb_intern("raise");
65
+ ID_runnable = rb_intern("runnable");
66
+ ID_runnable_value = rb_intern("runnable_value");
67
+ ID_signal = rb_intern("signal");
68
+ ID_size = rb_intern("size");
69
+ ID_switch_fiber = rb_intern("switch_fiber");
70
+ ID_transfer = rb_intern("transfer");
71
+ }
@@ -0,0 +1,97 @@
1
+ #ifndef POLYPHONY_H
2
+ #define POLYPHONY_H
3
+
4
+ #include "ruby.h"
5
+ #include "ruby/io.h"
6
+ #include "libev.h"
7
+
8
+ // debugging
9
+ #define OBJ_ID(obj) (NUM2LONG(rb_funcall(obj, rb_intern("object_id"), 0)))
10
+ #define INSPECT(obj) { VALUE s = rb_funcall(obj, rb_intern("inspect"), 0); printf("%s\n", StringValueCStr(s));}
11
+ #define FIBER_TRACE(...) if (__tracing_enabled__) { \
12
+ rb_funcall(rb_cObject, ID_fiber_trace, __VA_ARGS__); \
13
+ }
14
+
15
+ #define TEST_EXCEPTION(ret) (RTEST(rb_obj_is_kind_of(ret, rb_eException)))
16
+
17
+ #define TEST_RESUME_EXCEPTION(ret) if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) { \
18
+ return rb_funcall(rb_mKernel, ID_raise, 1, ret); \
19
+ }
20
+
21
+ extern VALUE mPolyphony;
22
+ extern VALUE cQueue;
23
+ extern VALUE cEvent;
24
+
25
+ extern ID ID_call;
26
+ extern ID ID_caller;
27
+ extern ID ID_clear;
28
+ extern ID ID_each;
29
+ extern ID ID_fiber_trace;
30
+ extern ID ID_inspect;
31
+ extern ID ID_ivar_agent;
32
+ extern ID ID_ivar_running;
33
+ extern ID ID_ivar_thread;
34
+ extern ID ID_new;
35
+ extern ID ID_raise;
36
+ extern ID ID_runnable;
37
+ extern ID ID_runnable_value;
38
+ extern ID ID_signal;
39
+ extern ID ID_size;
40
+ extern ID ID_switch_fiber;
41
+ extern ID ID_transfer;
42
+
43
+ extern VALUE SYM_fiber_create;
44
+ extern VALUE SYM_fiber_ev_loop_enter;
45
+ extern VALUE SYM_fiber_ev_loop_leave;
46
+ extern VALUE SYM_fiber_run;
47
+ extern VALUE SYM_fiber_schedule;
48
+ extern VALUE SYM_fiber_switchpoint;
49
+ extern VALUE SYM_fiber_terminate;
50
+
51
+ extern int __tracing_enabled__;
52
+
53
+ enum {
54
+ FIBER_STATE_NOT_SCHEDULED = 0,
55
+ FIBER_STATE_WAITING = 1,
56
+ FIBER_STATE_SCHEDULED = 2
57
+ };
58
+
59
+ // watcher flags
60
+ enum {
61
+ // a watcher's active field will be set to this after fork
62
+ GYRO_WATCHER_POST_FORK = 0xFF
63
+ };
64
+
65
+ VALUE Fiber_auto_watcher(VALUE self);
66
+ void Fiber_make_runnable(VALUE fiber, VALUE value);
67
+
68
+ VALUE LibevAgent_poll(VALUE self, VALUE nowait, VALUE current_fiber, VALUE queue);
69
+ VALUE LibevAgent_break(VALUE self);
70
+ VALUE LibevAgent_pending_count(VALUE self);
71
+ VALUE LibevAgent_wait_io(VALUE self, VALUE io, VALUE write);
72
+
73
+ VALUE LibevAgent_ref(VALUE self);
74
+ VALUE LibevAgent_unref(VALUE self);
75
+ int LibevAgent_ref_count(VALUE self);
76
+ void LibevAgent_reset_ref_count(VALUE self);
77
+ VALUE LibevAgent_wait_event(VALUE self, VALUE raise);
78
+
79
+ VALUE Queue_push(VALUE self, VALUE value);
80
+ VALUE Queue_unshift(VALUE self, VALUE value);
81
+ VALUE Queue_shift(VALUE self);
82
+ VALUE Queue_shift_no_wait(VALUE self);
83
+ VALUE Queue_clear(VALUE self);
84
+ VALUE Queue_delete(VALUE self, VALUE value);
85
+ long Queue_len(VALUE self);
86
+ void Queue_trace(VALUE self);
87
+
88
+ VALUE Polyphony_snooze(VALUE self);
89
+
90
+ VALUE Thread_schedule_fiber(VALUE thread, VALUE fiber, VALUE value);
91
+ VALUE Thread_switch_fiber(VALUE thread);
92
+
93
+ int io_setstrbuf(VALUE *str, long len);
94
+ void io_set_read_length(VALUE str, long n, int shrinkable);
95
+ VALUE io_enc_str(VALUE str, rb_io_t *fptr);
96
+
97
+ #endif /* POLYPHONY_H */
@@ -0,0 +1,21 @@
1
+ #include "polyphony.h"
2
+
3
+ void Init_Fiber();
4
+ void Init_Polyphony();
5
+ void Init_LibevAgent();
6
+ void Init_Queue();
7
+ void Init_Thread();
8
+ void Init_Tracing();
9
+
10
+ void Init_polyphony_ext() {
11
+ ev_set_allocator(xrealloc);
12
+
13
+ Init_Polyphony();
14
+ Init_LibevAgent();
15
+ Init_Queue();
16
+
17
+ Init_Fiber();
18
+ Init_Thread();
19
+
20
+ Init_Tracing();
21
+ }
@@ -0,0 +1,168 @@
1
+ #include "polyphony.h"
2
+ #include "ring_buffer.h"
3
+
4
+ typedef struct queue {
5
+ ring_buffer values;
6
+ ring_buffer shift_queue;
7
+ } Queue_t;
8
+
9
+ VALUE cQueue = Qnil;
10
+
11
+ static void Queue_mark(void *ptr) {
12
+ Queue_t *queue = ptr;
13
+ ring_buffer_mark(&queue->values);
14
+ ring_buffer_mark(&queue->shift_queue);
15
+ }
16
+
17
+ static void Queue_free(void *ptr) {
18
+ Queue_t *queue = ptr;
19
+ ring_buffer_free(&queue->values);
20
+ ring_buffer_free(&queue->shift_queue);
21
+ xfree(ptr);
22
+ }
23
+
24
+ static size_t Queue_size(const void *ptr) {
25
+ return sizeof(Queue_t);
26
+ }
27
+
28
+ static const rb_data_type_t Queue_type = {
29
+ "Queue",
30
+ {Queue_mark, Queue_free, Queue_size,},
31
+ 0, 0, 0
32
+ };
33
+
34
+ static VALUE Queue_allocate(VALUE klass) {
35
+ Queue_t *queue;
36
+
37
+ queue = ALLOC(Queue_t);
38
+ return TypedData_Wrap_Struct(klass, &Queue_type, queue);
39
+ }
40
+
41
+ #define GetQueue(obj, queue) \
42
+ TypedData_Get_Struct((obj), Queue_t, &Queue_type, (queue))
43
+
44
+ static VALUE Queue_initialize(VALUE self) {
45
+ Queue_t *queue;
46
+ GetQueue(self, queue);
47
+
48
+ ring_buffer_init(&queue->values);
49
+ ring_buffer_init(&queue->shift_queue);
50
+
51
+ return self;
52
+ }
53
+
54
+ VALUE Queue_push(VALUE self, VALUE value) {
55
+ Queue_t *queue;
56
+ GetQueue(self, queue);
57
+ if (queue->shift_queue.count > 0) {
58
+ VALUE fiber = ring_buffer_shift(&queue->shift_queue);
59
+ if (fiber != Qnil) Fiber_make_runnable(fiber, Qnil);
60
+ }
61
+ ring_buffer_push(&queue->values, value);
62
+ return self;
63
+ }
64
+
65
+ VALUE Queue_unshift(VALUE self, VALUE value) {
66
+ Queue_t *queue;
67
+ GetQueue(self, queue);
68
+ if (queue->shift_queue.count > 0) {
69
+ VALUE fiber = ring_buffer_shift(&queue->shift_queue);
70
+ if (fiber != Qnil) Fiber_make_runnable(fiber, Qnil);
71
+ }
72
+ ring_buffer_unshift(&queue->values, value);
73
+ return self;
74
+ }
75
+
76
+ VALUE Queue_shift(VALUE self) {
77
+ Queue_t *queue;
78
+ GetQueue(self, queue);
79
+
80
+ if (queue->values.count == 0) {
81
+ VALUE agent = rb_ivar_get(rb_thread_current(), ID_ivar_agent);
82
+ VALUE fiber = rb_fiber_current();
83
+ VALUE switchpoint_result = Qnil;
84
+ ring_buffer_push(&queue->shift_queue, fiber);
85
+ switchpoint_result = LibevAgent_wait_event(agent, Qnil);
86
+ if (RTEST(rb_obj_is_kind_of(switchpoint_result, rb_eException))) {
87
+ ring_buffer_delete(&queue->shift_queue, fiber);
88
+ return rb_funcall(rb_mKernel, ID_raise, 1, switchpoint_result);
89
+ }
90
+ RB_GC_GUARD(agent);
91
+ RB_GC_GUARD(switchpoint_result);
92
+ }
93
+
94
+ return ring_buffer_shift(&queue->values);
95
+ }
96
+
97
+ VALUE Queue_shift_no_wait(VALUE self) {
98
+ Queue_t *queue;
99
+ GetQueue(self, queue);
100
+
101
+ return ring_buffer_shift(&queue->values);
102
+ }
103
+
104
+ VALUE Queue_delete(VALUE self, VALUE value) {
105
+ Queue_t *queue;
106
+ GetQueue(self, queue);
107
+
108
+ ring_buffer_delete(&queue->values, value);
109
+ return self;
110
+ }
111
+
112
+ VALUE Queue_clear(VALUE self) {
113
+ Queue_t *queue;
114
+ GetQueue(self, queue);
115
+
116
+ ring_buffer_clear(&queue->values);
117
+ return self;
118
+ }
119
+
120
+ long Queue_len(VALUE self) {
121
+ Queue_t *queue;
122
+ GetQueue(self, queue);
123
+
124
+ return queue->values.count;
125
+ }
126
+
127
+ VALUE Queue_shift_each(VALUE self) {
128
+ Queue_t *queue;
129
+ GetQueue(self, queue);
130
+
131
+ ring_buffer_shift_each(&queue->values);
132
+ return self;
133
+ }
134
+
135
+ VALUE Queue_shift_all(VALUE self) {
136
+ Queue_t *queue;
137
+ GetQueue(self, queue);
138
+
139
+ return ring_buffer_shift_all(&queue->values);
140
+ }
141
+
142
+ VALUE Queue_empty_p(VALUE self) {
143
+ Queue_t *queue;
144
+ GetQueue(self, queue);
145
+
146
+ return (queue->values.count == 0) ? Qtrue : Qfalse;
147
+ }
148
+
149
+ void Init_Queue() {
150
+ cQueue = rb_define_class_under(mPolyphony, "Queue", rb_cData);
151
+ rb_define_alloc_func(cQueue, Queue_allocate);
152
+
153
+ rb_define_method(cQueue, "initialize", Queue_initialize, 0);
154
+ rb_define_method(cQueue, "push", Queue_push, 1);
155
+ rb_define_method(cQueue, "<<", Queue_push, 1);
156
+ rb_define_method(cQueue, "unshift", Queue_unshift, 1);
157
+
158
+ rb_define_method(cQueue, "shift", Queue_shift, 0);
159
+ rb_define_method(cQueue, "pop", Queue_shift, 0);
160
+ rb_define_method(cQueue, "shift_no_wait", Queue_shift_no_wait, 0);
161
+ rb_define_method(cQueue, "delete", Queue_delete, 1);
162
+
163
+ rb_define_method(cQueue, "shift_each", Queue_shift_each, 0);
164
+ rb_define_method(cQueue, "shift_all", Queue_shift_all, 0);
165
+ rb_define_method(cQueue, "empty?", Queue_empty_p, 0);
166
+ }
167
+
168
+
@@ -0,0 +1,96 @@
1
+ #include "polyphony.h"
2
+ #include "ring_buffer.h"
3
+
4
+ void ring_buffer_init(ring_buffer *buffer) {
5
+ buffer->size = 1;
6
+ buffer->count = 0;
7
+ buffer->entries = malloc(buffer->size * sizeof(VALUE));
8
+ buffer->head = 0;
9
+ buffer->tail = 0;
10
+ }
11
+
12
+ void ring_buffer_free(ring_buffer *buffer) {
13
+ free(buffer->entries);
14
+ }
15
+
16
+ int ring_buffer_empty_p(ring_buffer *buffer) {
17
+ return buffer->count == 0;
18
+ }
19
+
20
+ VALUE ring_buffer_shift(ring_buffer *buffer) {
21
+ VALUE value;
22
+ if (buffer->count == 0) return Qnil;
23
+
24
+ value = buffer->entries[buffer->head];
25
+ buffer->head = (buffer->head + 1) % buffer->size;
26
+ buffer->count--;
27
+ // INSPECT(value);
28
+ return value;
29
+ }
30
+
31
+ void ring_buffer_resize(ring_buffer *buffer) {
32
+ unsigned int old_size = buffer->size;
33
+ buffer->size = old_size == 1 ? 4 : old_size * 2;
34
+ buffer->entries = realloc(buffer->entries, buffer->size * sizeof(VALUE));
35
+ for (unsigned int idx = 0; idx < buffer->head && idx < buffer->tail; idx++)
36
+ buffer->entries[old_size + idx] = buffer->entries[idx];
37
+ buffer->tail = buffer->head + buffer->count;
38
+ }
39
+
40
+ void ring_buffer_unshift(ring_buffer *buffer, VALUE value) {
41
+ if (buffer->count == buffer->size) ring_buffer_resize(buffer);
42
+
43
+ buffer->head = (buffer->head - 1) % buffer->size;
44
+ buffer->entries[buffer->head] = value;
45
+ buffer->count++;
46
+ }
47
+
48
+ void ring_buffer_push(ring_buffer *buffer, VALUE value) {
49
+ if (buffer->count == buffer->size) ring_buffer_resize(buffer);
50
+
51
+ buffer->entries[buffer->tail] = value;
52
+ buffer->tail = (buffer->tail + 1) % buffer->size;
53
+ buffer->count++;
54
+ }
55
+
56
+ void ring_buffer_mark(ring_buffer *buffer) {
57
+ for (unsigned int i = 0; i < buffer->count; i++)
58
+ rb_gc_mark(buffer->entries[(buffer->head + i) % buffer->size]);
59
+ }
60
+
61
+ void ring_buffer_shift_each(ring_buffer *buffer) {
62
+ for (unsigned int i = 0; i < buffer->count; i++)
63
+ rb_yield(buffer->entries[(buffer->head + i) % buffer->size]);
64
+
65
+ buffer->count = buffer->head = buffer->tail = 0;
66
+ }
67
+
68
+ VALUE ring_buffer_shift_all(ring_buffer *buffer) {
69
+ VALUE array = rb_ary_new_capa(buffer->count);
70
+ for (unsigned int i = 0; i < buffer->count; i++)
71
+ rb_ary_push(array, buffer->entries[(buffer->head + i) % buffer->size]);
72
+ buffer->count = buffer->head = buffer->tail = 0;
73
+ return array;
74
+ }
75
+
76
+ void ring_buffer_delete_at(ring_buffer *buffer, unsigned int idx) {
77
+ for (unsigned int idx2 = idx; idx2 != buffer->tail; idx2 = (idx2 + 1) % buffer->size) {
78
+ buffer->entries[idx2] = buffer->entries[(idx2 + 1) % buffer->size];
79
+ }
80
+ buffer->count--;
81
+ buffer->tail = (buffer->tail - 1) % buffer->size;
82
+ }
83
+
84
+ void ring_buffer_delete(ring_buffer *buffer, VALUE value) {
85
+ for (unsigned int i = 0; i < buffer->count; i++) {
86
+ unsigned int idx = (buffer->head + i) % buffer->size;
87
+ if (buffer->entries[idx] == value) {
88
+ ring_buffer_delete_at(buffer, idx);
89
+ return;
90
+ }
91
+ }
92
+ }
93
+
94
+ void ring_buffer_clear(ring_buffer *buffer) {
95
+ buffer->count = buffer->head = buffer->tail = 0;
96
+ }