polyphony 0.99 → 0.99.1

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 (94) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +1 -1
  3. data/.rubocop.yml +3 -3
  4. data/.yardopts +30 -0
  5. data/CHANGELOG.md +4 -0
  6. data/LICENSE +1 -1
  7. data/README.md +63 -29
  8. data/Rakefile +1 -5
  9. data/TODO.md +0 -4
  10. data/docs/{main-concepts/concurrency.md → concurrency.md} +2 -9
  11. data/docs/{main-concepts/design-principles.md → design-principles.md} +3 -9
  12. data/docs/{main-concepts/exception-handling.md → exception-handling.md} +2 -9
  13. data/docs/{main-concepts/extending.md → extending.md} +2 -9
  14. data/docs/faq.md +3 -16
  15. data/docs/{main-concepts/fiber-scheduling.md → fiber-scheduling.md} +1 -9
  16. data/docs/link_rewriter.rb +16 -0
  17. data/docs/{getting-started/overview.md → overview.md} +1 -30
  18. data/docs/{getting-started/tutorial.md → tutorial.md} +3 -28
  19. data/docs/{_posts/2020-07-26-polyphony-0.44.md → whats-new.md} +3 -1
  20. data/examples/adapters/redis_client.rb +3 -2
  21. data/examples/io/echo_server.rb +1 -1
  22. data/examples/io/echo_server_plain_ruby.rb +26 -0
  23. data/ext/polyphony/backend_io_uring.c +154 -9
  24. data/ext/polyphony/backend_io_uring_context.c +21 -12
  25. data/ext/polyphony/backend_io_uring_context.h +12 -7
  26. data/ext/polyphony/backend_libev.c +1 -1
  27. data/ext/polyphony/extconf.rb +24 -8
  28. data/ext/polyphony/fiber.c +79 -2
  29. data/ext/polyphony/io_extensions.c +53 -0
  30. data/ext/polyphony/pipe.c +42 -2
  31. data/ext/polyphony/polyphony.c +345 -31
  32. data/ext/polyphony/polyphony.h +9 -2
  33. data/ext/polyphony/queue.c +181 -0
  34. data/ext/polyphony/ring_buffer.c +0 -1
  35. data/ext/polyphony/runqueue.c +8 -1
  36. data/ext/polyphony/runqueue_ring_buffer.c +13 -0
  37. data/ext/polyphony/runqueue_ring_buffer.h +2 -1
  38. data/ext/polyphony/socket_extensions.c +6 -0
  39. data/ext/polyphony/thread.c +34 -2
  40. data/lib/polyphony/adapters/process.rb +11 -1
  41. data/lib/polyphony/adapters/sequel.rb +1 -1
  42. data/lib/polyphony/core/channel.rb +2 -0
  43. data/lib/polyphony/core/debug.rb +1 -1
  44. data/lib/polyphony/core/global_api.rb +25 -24
  45. data/lib/polyphony/core/resource_pool.rb +7 -6
  46. data/lib/polyphony/core/sync.rb +2 -2
  47. data/lib/polyphony/core/thread_pool.rb +3 -3
  48. data/lib/polyphony/core/timer.rb +8 -8
  49. data/lib/polyphony/extensions/exception.rb +2 -0
  50. data/lib/polyphony/extensions/fiber.rb +15 -13
  51. data/lib/polyphony/extensions/io.rb +127 -5
  52. data/lib/polyphony/extensions/kernel.rb +20 -2
  53. data/lib/polyphony/extensions/openssl.rb +100 -11
  54. data/lib/polyphony/extensions/pipe.rb +103 -7
  55. data/lib/polyphony/extensions/process.rb +13 -1
  56. data/lib/polyphony/extensions/socket.rb +93 -27
  57. data/lib/polyphony/extensions/thread.rb +9 -1
  58. data/lib/polyphony/extensions/timeout.rb +1 -1
  59. data/lib/polyphony/version.rb +2 -1
  60. data/lib/polyphony.rb +27 -7
  61. data/polyphony.gemspec +1 -8
  62. data/test/stress.rb +1 -1
  63. data/test/test_global_api.rb +45 -7
  64. data/test/test_socket.rb +96 -0
  65. data/test/test_timer.rb +5 -5
  66. metadata +17 -40
  67. data/docs/_config.yml +0 -64
  68. data/docs/_includes/head.html +0 -40
  69. data/docs/_includes/title.html +0 -1
  70. data/docs/_sass/custom/custom.scss +0 -10
  71. data/docs/_sass/overrides.scss +0 -0
  72. data/docs/api-reference/exception.md +0 -31
  73. data/docs/api-reference/fiber.md +0 -425
  74. data/docs/api-reference/index.md +0 -9
  75. data/docs/api-reference/io.md +0 -36
  76. data/docs/api-reference/object.md +0 -99
  77. data/docs/api-reference/polyphony-baseexception.md +0 -33
  78. data/docs/api-reference/polyphony-cancel.md +0 -26
  79. data/docs/api-reference/polyphony-moveon.md +0 -24
  80. data/docs/api-reference/polyphony-net.md +0 -20
  81. data/docs/api-reference/polyphony-process.md +0 -28
  82. data/docs/api-reference/polyphony-resourcepool.md +0 -59
  83. data/docs/api-reference/polyphony-restart.md +0 -18
  84. data/docs/api-reference/polyphony-terminate.md +0 -18
  85. data/docs/api-reference/polyphony-threadpool.md +0 -67
  86. data/docs/api-reference/polyphony-throttler.md +0 -77
  87. data/docs/api-reference/polyphony.md +0 -36
  88. data/docs/api-reference/thread.md +0 -88
  89. data/docs/favicon.ico +0 -0
  90. data/docs/getting-started/index.md +0 -10
  91. data/docs/getting-started/installing.md +0 -34
  92. /data/{docs/assets/img → assets}/echo-fibers.svg +0 -0
  93. /data/{docs → assets}/polyphony-logo.png +0 -0
  94. /data/{docs/assets/img → assets}/sleeping-fiber.svg +0 -0
@@ -1,6 +1,19 @@
1
1
  #include "polyphony.h"
2
2
  #include "ring_buffer.h"
3
3
 
4
+ /*
5
+ * Document-class: Polyphony::Queue
6
+ *
7
+ * This class implements a FIFO queue that can be used to exchange data between
8
+ * different fibers or threads. The queue can simultaneously service multiple
9
+ * producers and multiple consumers. A consumers trying to remove an item from
10
+ * an empty queue will block at least one item is added to the queue.
11
+ *
12
+ * A queue can also be capped in order to limit its depth. A producer trying to
13
+ * add an item to a full capped queue will block until at least one item is
14
+ * removed from it.
15
+ */
16
+
4
17
  typedef struct queue {
5
18
  unsigned int closed;
6
19
  ring_buffer values;
@@ -48,6 +61,18 @@ static VALUE Queue_allocate(VALUE klass) {
48
61
  #define GetQueue(obj, queue) \
49
62
  TypedData_Get_Struct((obj), Queue_t, &Queue_type, (queue))
50
63
 
64
+ /* call-seq:
65
+ * Queue.new -> queue
66
+ * Queue.new(capacity) -> queue
67
+ *
68
+ * Initializes a queue instance. If the capacity is given, the queue becomes
69
+ * capped, i.e. it cannot contain more elements than its capacity. When trying
70
+ * to add items to a capped queue that is full, the current fiber will block
71
+ * until at least one item is removed from the queue.
72
+ *
73
+ * @return [void]
74
+ */
75
+
51
76
  static VALUE Queue_initialize(int argc, VALUE *argv, VALUE self) {
52
77
  Queue_t *queue;
53
78
  GetQueue(self, queue);
@@ -99,6 +124,18 @@ static inline void capped_queue_block_push(Queue_t *queue) {
99
124
  }
100
125
  }
101
126
 
127
+ /* call-seq:
128
+ * queue.push(value) -> queue
129
+ * queue.enq(value) -> queue
130
+ * queue << value -> queue
131
+ *
132
+ * Adds the given value to the queue's end. If the queue is capped and full, the
133
+ * call will block until a value is removed from the queue.
134
+ *
135
+ * @param value [any] value to be added to the queue
136
+ * @return [Queue] self
137
+ */
138
+
102
139
  VALUE Queue_push(VALUE self, VALUE value) {
103
140
  Queue_t *queue;
104
141
  GetQueue(self, queue);
@@ -114,6 +151,16 @@ VALUE Queue_push(VALUE self, VALUE value) {
114
151
  return self;
115
152
  }
116
153
 
154
+ /* call-seq:
155
+ * queue.unshift(value) -> queue
156
+ *
157
+ * Adds the given value to the queue's beginning. If the queue is capped and
158
+ * full, the call will block until a value is removed from the queue.
159
+ *
160
+ * @param value [any] value to be added to the queue
161
+ * @return [Queue] self
162
+ */
163
+
117
164
  VALUE Queue_unshift(VALUE self, VALUE value) {
118
165
  Queue_t *queue;
119
166
  GetQueue(self, queue);
@@ -170,6 +217,22 @@ VALUE Queue_shift_block(Queue_t *queue) {
170
217
  return value;
171
218
  }
172
219
 
220
+ /* call-seq:
221
+ * queue.shift -> value
222
+ * queue.shift(true) -> value
223
+ * queue.pop -> value
224
+ * queue.pop(true) -> value
225
+ * queue.deq -> value
226
+ * queue.deq(true) -> value
227
+ *
228
+ * Removes the first value in the queue and returns it. If the optional nonblock
229
+ * parameter is true, the operation is non-blocking. In non-blocking mode, if
230
+ * the queue is empty, a ThreadError exception is raised. In blocking mode, if
231
+ * the queue is empty, the call will block until an item is added to the queue.
232
+ *
233
+ * @return [any] first value in queue
234
+ */
235
+
173
236
  VALUE Queue_shift(int argc,VALUE *argv, VALUE self) {
174
237
  int nonblock = argc && RTEST(argv[0]);
175
238
  Queue_t *queue;
@@ -180,6 +243,14 @@ VALUE Queue_shift(int argc,VALUE *argv, VALUE self) {
180
243
  Queue_shift_block(queue);
181
244
  }
182
245
 
246
+ /* call-seq:
247
+ * queue.delete(value) -> queue
248
+ *
249
+ * Removes the given value from the queue.
250
+ *
251
+ * @return [Queue] self
252
+ */
253
+
183
254
  VALUE Queue_delete(VALUE self, VALUE value) {
184
255
  Queue_t *queue;
185
256
  GetQueue(self, queue);
@@ -192,6 +263,16 @@ VALUE Queue_delete(VALUE self, VALUE value) {
192
263
  return self;
193
264
  }
194
265
 
266
+ /* call-seq:
267
+ * queue.cap(capacity) -> queue
268
+ *
269
+ * Sets the capacity for the queue to the given value. If 0 or nil is given, the
270
+ * queue becomes uncapped.
271
+ *
272
+ * @param cap [Integer, nil] new capacity
273
+ * @return [Queue] self
274
+ */
275
+
195
276
  VALUE Queue_cap(VALUE self, VALUE cap) {
196
277
  unsigned int new_capacity = NUM2UINT(cap);
197
278
  Queue_t *queue;
@@ -206,6 +287,14 @@ VALUE Queue_cap(VALUE self, VALUE cap) {
206
287
  return self;
207
288
  }
208
289
 
290
+ /* call-seq:
291
+ * queue.capped? -> bool
292
+ *
293
+ * Returns true if the queue is capped.
294
+ *
295
+ * @return [boolean] is the queue capped
296
+ */
297
+
209
298
  VALUE Queue_capped_p(VALUE self) {
210
299
  Queue_t *queue;
211
300
  GetQueue(self, queue);
@@ -213,6 +302,14 @@ VALUE Queue_capped_p(VALUE self) {
213
302
  return queue->capacity ? INT2FIX(queue->capacity) : Qnil;
214
303
  }
215
304
 
305
+ /* call-seq:
306
+ * queue.clear -> queue
307
+ *
308
+ * Removes all values from the queue.
309
+ *
310
+ * @return [Queue] self
311
+ */
312
+
216
313
  VALUE Queue_clear(VALUE self) {
217
314
  Queue_t *queue;
218
315
  GetQueue(self, queue);
@@ -230,6 +327,16 @@ long Queue_len(VALUE self) {
230
327
  return queue->values.count;
231
328
  }
232
329
 
330
+ /* call-seq:
331
+ * queue.shift_each { |value| do_something(value) } -> queue
332
+ *
333
+ * Iterates over all values in the queue, removing each item and passing it to
334
+ * the given block.
335
+ *
336
+ * @yield [any] value passed to the given block
337
+ * @return [Queue] self
338
+ */
339
+
233
340
  VALUE Queue_shift_each(VALUE self) {
234
341
  Queue_t *queue;
235
342
  GetQueue(self, queue);
@@ -239,6 +346,14 @@ VALUE Queue_shift_each(VALUE self) {
239
346
  return self;
240
347
  }
241
348
 
349
+ /* call-seq:
350
+ * queue.shift_all -> array
351
+ *
352
+ * Returns all values currently in the queue, clearing the queue.
353
+ *
354
+ * @return [Array] all values
355
+ */
356
+
242
357
  VALUE Queue_shift_all(VALUE self) {
243
358
  Queue_t *queue;
244
359
  VALUE result;
@@ -250,6 +365,16 @@ VALUE Queue_shift_all(VALUE self) {
250
365
  return result;
251
366
  }
252
367
 
368
+ /* call-seq:
369
+ * queue.flush_waiters -> queue
370
+ *
371
+ * Flushes all fibers currently blocked waiting to remove items from the queue,
372
+ * resuming them with the given value.
373
+ *
374
+ * @param value [any] value to resome all waiting fibers with
375
+ * @return [Queue] self
376
+ */
377
+
253
378
  VALUE Queue_flush_waiters(VALUE self, VALUE value) {
254
379
  Queue_t *queue;
255
380
  GetQueue(self, queue);
@@ -260,8 +385,18 @@ VALUE Queue_flush_waiters(VALUE self, VALUE value) {
260
385
 
261
386
  Fiber_make_runnable(fiber, value);
262
387
  }
388
+
389
+ return self;
263
390
  }
264
391
 
392
+ /* call-seq:
393
+ * queue.empty? -> bool
394
+ *
395
+ * Returns true if the queue is empty.
396
+ *
397
+ * @return [boolean]
398
+ */
399
+
265
400
  VALUE Queue_empty_p(VALUE self) {
266
401
  Queue_t *queue;
267
402
  GetQueue(self, queue);
@@ -269,6 +404,15 @@ VALUE Queue_empty_p(VALUE self) {
269
404
  return (!queue->values.count) ? Qtrue : Qfalse;
270
405
  }
271
406
 
407
+ /* call-seq:
408
+ * queue.pending? -> bool
409
+ *
410
+ * Returns true if any fibers are currently waiting to remove items from the
411
+ * queue.
412
+ *
413
+ * @return [boolean]
414
+ */
415
+
272
416
  VALUE Queue_pending_p(VALUE self) {
273
417
  Queue_t *queue;
274
418
  GetQueue(self, queue);
@@ -276,6 +420,15 @@ VALUE Queue_pending_p(VALUE self) {
276
420
  return (queue->shift_queue.count) ? Qtrue : Qfalse;
277
421
  }
278
422
 
423
+ /* call-seq:
424
+ * queue.num_waiting -> integer
425
+ *
426
+ * Returns the number of fibers currently waiting to remove items from the
427
+ * queue.
428
+ *
429
+ * @return [Integer]
430
+ */
431
+
279
432
  VALUE Queue_num_waiting(VALUE self) {
280
433
  Queue_t *queue;
281
434
  GetQueue(self, queue);
@@ -283,6 +436,15 @@ VALUE Queue_num_waiting(VALUE self) {
283
436
  return INT2FIX(queue->shift_queue.count);
284
437
  }
285
438
 
439
+ /* call-seq:
440
+ * queue.size -> integer
441
+ * queue.length -> integer
442
+ *
443
+ * Returns the number of values currently in the queue.
444
+ *
445
+ * @return [Integer] number of values in the queue
446
+ */
447
+
286
448
  VALUE Queue_size_m(VALUE self) {
287
449
  Queue_t *queue;
288
450
  GetQueue(self, queue);
@@ -290,6 +452,14 @@ VALUE Queue_size_m(VALUE self) {
290
452
  return INT2FIX(queue->values.count);
291
453
  }
292
454
 
455
+ /* call-seq:
456
+ * queue.closed? -> bool
457
+ *
458
+ * Returns true if the queue has been closed.
459
+ *
460
+ * @return [boolean]
461
+ */
462
+
293
463
  VALUE Queue_closed_p(VALUE self) {
294
464
  Queue_t *queue;
295
465
  GetQueue(self, queue);
@@ -297,6 +467,16 @@ VALUE Queue_closed_p(VALUE self) {
297
467
  return (queue->closed) ? Qtrue : Qfalse;
298
468
  }
299
469
 
470
+ /* call-seq:
471
+ * queue.close -> queue
472
+ *
473
+ * Marks the queue as closed. Any fibers currently waiting on the queue are
474
+ * resumed with a `nil` value. After the queue is closed, trying to remove items
475
+ * from the queue will cause a `ClosedQueueError` to be raised.
476
+ *
477
+ * @return [Queue] self
478
+ */
479
+
300
480
  VALUE Queue_close(VALUE self) {
301
481
  Queue_t *queue;
302
482
  GetQueue(self, queue);
@@ -319,6 +499,7 @@ void Init_Queue(void) {
319
499
  cClosedQueueError = rb_const_get(rb_cObject, rb_intern("ClosedQueueError"));
320
500
  cThreadError = rb_const_get(rb_cObject, rb_intern("ThreadError"));
321
501
 
502
+ /* Queue implements a FIFO queue. */
322
503
  cQueue = rb_define_class_under(mPolyphony, "Queue", rb_cObject);
323
504
  rb_define_alloc_func(cQueue, Queue_allocate);
324
505
 
@@ -10,7 +10,6 @@ void ring_buffer_init(ring_buffer *buffer) {
10
10
  }
11
11
 
12
12
  void ring_buffer_free(ring_buffer *buffer) {
13
- // printf("ring_buffer_free ring_buffer: %p entries: %p\n", buffer, buffer->entries);
14
13
  free(buffer->entries);
15
14
  }
16
15
 
@@ -15,7 +15,14 @@ inline void runqueue_mark(runqueue_t *runqueue) {
15
15
  }
16
16
 
17
17
  inline void runqueue_push(runqueue_t *runqueue, VALUE fiber, VALUE value, int reschedule) {
18
- if (reschedule) runqueue_ring_buffer_delete(&runqueue->entries, fiber);
18
+ if (reschedule) {
19
+ if (IS_EXCEPTION(value))
20
+ runqueue_ring_buffer_delete(&runqueue->entries, fiber);
21
+ else {
22
+ int exception_scheduled = runqueue_ring_buffer_delete_if_not_exception(&runqueue->entries, fiber);
23
+ if (exception_scheduled) return;
24
+ }
25
+ }
19
26
  runqueue_ring_buffer_push(&runqueue->entries, fiber, value);
20
27
  if (runqueue->entries.count > runqueue->high_watermark)
21
28
  runqueue->high_watermark = runqueue->entries.count;
@@ -87,6 +87,19 @@ inline void runqueue_ring_buffer_delete(runqueue_ring_buffer *buffer, VALUE fibe
87
87
  }
88
88
  }
89
89
 
90
+ inline int runqueue_ring_buffer_delete_if_not_exception(runqueue_ring_buffer *buffer, VALUE fiber) {
91
+ for (unsigned int i = 0; i < buffer->count; i++) {
92
+ unsigned int idx = (buffer->head + i) % buffer->size;
93
+ if (buffer->entries[idx].fiber == fiber) {
94
+ if (IS_EXCEPTION(buffer->entries[idx].value)) return 1;
95
+
96
+ runqueue_ring_buffer_delete_at(buffer, idx);
97
+ return 0;
98
+ }
99
+ }
100
+ return 0;
101
+ }
102
+
90
103
  inline int runqueue_ring_buffer_index_of(runqueue_ring_buffer *buffer, VALUE fiber) {
91
104
  for (unsigned int i = 0; i < buffer->count; i++) {
92
105
  unsigned int idx = (buffer->head + i) % buffer->size;
@@ -27,8 +27,9 @@ void runqueue_ring_buffer_unshift(runqueue_ring_buffer *buffer, VALUE fiber, VAL
27
27
  void runqueue_ring_buffer_push(runqueue_ring_buffer *buffer, VALUE fiber, VALUE value);
28
28
 
29
29
  void runqueue_ring_buffer_delete(runqueue_ring_buffer *buffer, VALUE fiber);
30
+ int runqueue_ring_buffer_delete_if_not_exception(runqueue_ring_buffer *buffer, VALUE fiber);
30
31
  int runqueue_ring_buffer_index_of(runqueue_ring_buffer *buffer, VALUE fiber);
31
32
 
32
33
  void runqueue_ring_buffer_migrate(runqueue_ring_buffer *src, runqueue_ring_buffer *dest, VALUE fiber);
33
34
 
34
- #endif /* RUNQUEUE_RING_BUFFER_H */
35
+ #endif /* RUNQUEUE_RING_BUFFER_H */
@@ -1,9 +1,13 @@
1
1
  #include "polyphony.h"
2
2
 
3
+ /* :nop-doc: */
4
+
3
5
  VALUE Socket_send(VALUE self, VALUE msg, VALUE flags) {
4
6
  return Backend_send(BACKEND(), self, msg, flags);
5
7
  }
6
8
 
9
+ /* :nop-doc: */
10
+
7
11
  VALUE Socket_write(int argc, VALUE *argv, VALUE self) {
8
12
  VALUE ary = rb_ary_new_from_values(argc, argv);
9
13
  VALUE result = Backend_sendv(BACKEND(), self, ary, INT2FIX(0));
@@ -11,6 +15,8 @@ VALUE Socket_write(int argc, VALUE *argv, VALUE self) {
11
15
  return result;
12
16
  }
13
17
 
18
+ /* :nop-doc: */
19
+
14
20
  VALUE Socket_double_chevron(VALUE self, VALUE msg) {
15
21
  Backend_send(BACKEND(), self, msg, INT2FIX(0));
16
22
  return self;
@@ -8,6 +8,8 @@ ID ID_ivar_main_fiber;
8
8
  ID ID_ivar_terminated;
9
9
  ID ID_stop;
10
10
 
11
+ /* :nop-doc: */
12
+
11
13
  static VALUE Thread_setup_fiber_scheduling(VALUE self) {
12
14
  rb_ivar_set(self, ID_ivar_main_fiber, rb_fiber_current());
13
15
  return self;
@@ -17,6 +19,15 @@ inline void schedule_fiber(VALUE self, VALUE fiber, VALUE value, int prioritize)
17
19
  Backend_schedule_fiber(self, rb_ivar_get(self, ID_ivar_backend), fiber, value, prioritize);
18
20
  }
19
21
 
22
+ /* call-seq:
23
+ * thread.unschedule_fiber(fiber)
24
+ *
25
+ * Removes the given fiber from the thread's runqueue.
26
+ *
27
+ * @param fiber [Fiber] fiber to unschedule
28
+ * @return [Thread] self
29
+ */
30
+
20
31
  VALUE Thread_fiber_unschedule(VALUE self, VALUE fiber) {
21
32
  Backend_unschedule_fiber(rb_ivar_get(self, ID_ivar_backend), fiber);
22
33
  return self;
@@ -34,28 +45,49 @@ inline void Thread_schedule_fiber_with_priority(VALUE self, VALUE fiber, VALUE v
34
45
  // schedule_fiber(self, fiber, value, 1);
35
46
  }
36
47
 
48
+ /* call-seq:
49
+ * thread.switch_fiber()
50
+ *
51
+ * Switches to the next fiber in the thread's runqueue.
52
+ *
53
+ * @return [void]
54
+ */
55
+
37
56
  VALUE Thread_switch_fiber(VALUE self) {
38
57
  return Backend_switch_fiber(rb_ivar_get(self, ID_ivar_backend));
39
58
  }
40
59
 
60
+ /* @!visibility private */
61
+
41
62
  VALUE Thread_fiber_schedule_and_wakeup(VALUE self, VALUE fiber, VALUE resume_obj) {
42
63
  if (fiber != Qnil) {
43
64
  Thread_schedule_fiber_with_priority(self, fiber, resume_obj);
44
65
  }
45
66
 
46
- if (Backend_wakeup(rb_ivar_get(self, ID_ivar_backend)) == Qnil) {
67
+ VALUE backend = rb_ivar_get(self, ID_ivar_backend);
68
+ if (Backend_wakeup(backend) == Qnil) {
47
69
  // we're not inside Backend_poll, so we just do a switchpoint
48
- Thread_switch_fiber(self);
70
+ Backend_switch_fiber(backend);
49
71
  }
50
72
 
51
73
  return self;
52
74
  }
53
75
 
76
+ /* @!visibility private */
77
+
54
78
  VALUE Thread_debug(VALUE self) {
55
79
  rb_ivar_set(self, rb_intern("@__debug__"), Qtrue);
56
80
  return self;
57
81
  }
58
82
 
83
+ /* call-seq:
84
+ * Thread.backend
85
+ *
86
+ * Returns the backend for the current thread.
87
+ *
88
+ * @return [Polyphony::Backend] backend for the current thread
89
+ */
90
+
59
91
  VALUE Thread_class_backend(VALUE _self) {
60
92
  return rb_ivar_get(rb_thread_current(), ID_ivar_backend);
61
93
  }
@@ -13,7 +13,7 @@ module Polyphony
13
13
  # process is killed.
14
14
  #
15
15
  # @param cmd [String, nil] command to spawn
16
- # @param &block [Proc] block to fork
16
+ # @yield [] block to fork
17
17
  # @return [void]
18
18
  def watch(cmd = nil, &block)
19
19
  terminated = nil
@@ -24,6 +24,11 @@ module Polyphony
24
24
  kill_process(pid) unless terminated || pid.nil?
25
25
  end
26
26
 
27
+ # Kills the given pid, waiting for it to terminate, with a timeout of 5
28
+ # seconds.
29
+ #
30
+ # @param pid [Integer] pid
31
+ # @return [void]
27
32
  def kill_process(pid)
28
33
  cancel_after(5) do
29
34
  kill_and_await('TERM', pid)
@@ -34,6 +39,11 @@ module Polyphony
34
39
 
35
40
  private
36
41
 
42
+ # Kills the given process with given signal, waiting for it to terminate.
43
+ #
44
+ # @param sig [String, Symbol, Integer] signal to use
45
+ # @param pid [Integer] pid
46
+ # @return [void]
37
47
  def kill_and_await(sig, pid)
38
48
  ::Process.kill(sig, pid)
39
49
  Polyphony.backend_waitpid(pid)
@@ -11,7 +11,7 @@ module Polyphony
11
11
  # Initializes the connection pool.
12
12
  #
13
13
  # @param db [any] db to connect to
14
- # @opts [Hash] connection pool options
14
+ # @paral opts [Hash] connection pool options
15
15
  def initialize(db, opts = OPTS)
16
16
  super
17
17
  max_size = Integer(opts[:max_connections] || 4)
@@ -8,6 +8,8 @@ module Polyphony
8
8
  class Channel < Polyphony::Queue
9
9
  alias_method :receive, :shift
10
10
 
11
+ # Closes the channel, resuming any fibers waiting on the channel with
12
+ # a Polyphony::MoveOn exception
11
13
  def close
12
14
  flush_waiters(Polyphony::MoveOn.new)
13
15
  end
@@ -32,7 +32,7 @@ module Polyphony
32
32
  # If an IO instance is given, events are dumped to it instead.
33
33
  #
34
34
  # @param io [IO, nil] IO instance
35
- # @param &block [Proc] event handler block
35
+ # @yield [Hash] event handler block
36
36
  # @return [void]
37
37
  def start_event_firehose(io = nil, &block)
38
38
  Thread.backend.trace_proc = firehose_proc(io, block)
@@ -10,8 +10,8 @@ module Polyphony
10
10
  # Spins up a fiber that will run the given block after sleeping for the
11
11
  # given delay.
12
12
  #
13
- # @param delay [Number] delay in seconds before running the given block
14
- # @param &block [Proc] block to run
13
+ # @param interval [Number] delay in seconds before running the given block
14
+ # @yield [] block to run
15
15
  # @return [Fiber] spun fiber
16
16
  def after(interval, &block)
17
17
  spin do
@@ -56,8 +56,8 @@ module Polyphony
56
56
  # end
57
57
  #
58
58
  # @param interval [Number] timout in seconds
59
- # @param with_exception: [Class, Exception] exception or exception class
60
- # @param &block [Proc] block to execute
59
+ # @param with_exception [Class, Exception] exception or exception class
60
+ # @yield [Fiber] block to execute
61
61
  # @return [any] block's return value
62
62
  def cancel_after(interval, with_exception: Polyphony::Cancel, &block)
63
63
  if block.arity > 0
@@ -70,7 +70,7 @@ module Polyphony
70
70
  # Spins up a new fiber.
71
71
  #
72
72
  # @param tag [any] optional tag for the new fiber
73
- # @param &block [Proc] fiber block
73
+ # @yield [any] fiber block
74
74
  # @return [Fiber] new fiber
75
75
  def spin(tag = nil, &block)
76
76
  Fiber.current.spin(tag, caller, &block)
@@ -81,9 +81,9 @@ module Polyphony
81
81
  # accordingly.
82
82
  #
83
83
  # @param tag [any] optional tag for the new fiber
84
- # @param rate: [Number, nil] loop rate (times per second)
85
- # @param interval: [Number, nil] interval between consecutive iterations in seconds
86
- # @param &block [Proc] code to run
84
+ # @param rate [Number, nil] loop rate (times per second)
85
+ # @param interval [Number, nil] interval between consecutive iterations in seconds
86
+ # @yield [any] code to run
87
87
  # @return [Fiber] new fiber
88
88
  def spin_loop(tag = nil, rate: nil, interval: nil, &block)
89
89
  if rate || interval
@@ -98,7 +98,7 @@ module Polyphony
98
98
  # Runs the given code, then waits for any child fibers of the current fibers
99
99
  # to terminate.
100
100
  #
101
- # @param &block [Proc] code to run
101
+ # @yield [any] code to run
102
102
  # @return [any] given block's return value
103
103
  def spin_scope(&block)
104
104
  raise unless block
@@ -114,7 +114,7 @@ module Polyphony
114
114
  # consecutive iterations.
115
115
  #
116
116
  # @param interval [Number] interval between consecutive iterations in seconds
117
- # @param &block [Proc] block to run
117
+ # @yield [any] block to run
118
118
  # @return [void]
119
119
  def every(interval, &block)
120
120
  Polyphony.backend_timer_loop(interval, &block)
@@ -160,8 +160,8 @@ module Polyphony
160
160
  # end
161
161
  #
162
162
  # @param interval [Number] timout in seconds
163
- # @param with_value: [any] return value in case of timeout
164
- # @param &block [Proc] block to execute
163
+ # @param with_value [any] return value in case of timeout
164
+ # @yield [Fiber] block to execute
165
165
  # @return [any] block's return value
166
166
  def move_on_after(interval, with_value: nil, &block)
167
167
  if block.arity > 0
@@ -189,9 +189,9 @@ module Polyphony
189
189
  # Supervises the current fiber's children. See `Fiber#supervise` for
190
190
  # options.
191
191
  #
192
- # @param *args [Array] positional parameters
193
- # @param **opts [Hash] named parameters
194
- # @param &block [Proc] given block
192
+ # @param args [Array] positional parameters
193
+ # @param opts [Hash] named parameters
194
+ # @yield [any] given block
195
195
  # @return [void]
196
196
  def supervise(*args, **opts, &block)
197
197
  Fiber.current.supervise(*args, **opts, &block)
@@ -220,10 +220,10 @@ module Polyphony
220
220
  # `interval:` or `rate:` named parameter.
221
221
  #
222
222
  # @param rate [Number, nil] loop rate (times per second)
223
- # @param rate: [Number] loop rate (times per second)
224
- # @param interval: [Number] loop interval in seconds
225
- # @param count: [Number, nil] number of iterations (nil for infinite)
226
- # @param &block [Proc] code to run
223
+ # @option opts [Number] :rate loop rate (times per second)
224
+ # @option opts [Number] :interval loop interval in seconds
225
+ # @option opts [Number] :count number of iterations (nil for infinite)
226
+ # @yield [] code to run
227
227
  # @return [void]
228
228
  def throttled_loop(rate = nil, **opts, &block)
229
229
  throttler = Polyphony::Throttler.new(rate || opts)
@@ -244,14 +244,15 @@ module Polyphony
244
244
  #
245
245
  # @param interval [Number] timeout interval in seconds
246
246
  # @param exception [Exception, Class, Array<class, message>] exception spec
247
- # @param &block [Proc] block to run
247
+ # @yield [Fiber] block to run
248
248
  # @return [any] block's return value
249
249
  def cancel_after_with_optional_reset(interval, exception, &block)
250
+ fiber = Fiber.current
250
251
  canceller = spin do
251
- sleep interval
252
+ Polyphony.backend_sleep(interval)
252
253
  exception = cancel_exception(exception)
253
254
  exception.raising_fiber = Fiber.current
254
- fiber.cancel(exception).await
255
+ fiber.cancel(exception)
255
256
  end
256
257
  block.call(canceller)
257
258
  ensure
@@ -289,13 +290,13 @@ module Polyphony
289
290
  #
290
291
  # @param interval [Number] timeout interval in seconds
291
292
  # @param value [any] return value in case of timeout
292
- # @param &block [Proc] code to run
293
+ # @yield [Fiber] code to run
293
294
  # @return [any] return value of given block or timeout value
294
295
  def move_on_after_with_optional_reset(interval, value, &block)
295
296
  fiber = Fiber.current
296
297
  canceller = spin do
297
298
  sleep interval
298
- fiber.move_on(value).await
299
+ fiber.move_on(value)
299
300
  end
300
301
  block.call(canceller)
301
302
  rescue Polyphony::MoveOn => e