polyphony 0.99 → 0.99.1

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