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.
- checksums.yaml +4 -4
- data/.github/FUNDING.yml +1 -1
- data/.rubocop.yml +3 -3
- data/.yardopts +30 -0
- data/CHANGELOG.md +4 -0
- data/LICENSE +1 -1
- data/README.md +63 -29
- data/Rakefile +1 -5
- data/TODO.md +0 -4
- data/docs/{main-concepts/concurrency.md → concurrency.md} +2 -9
- data/docs/{main-concepts/design-principles.md → design-principles.md} +3 -9
- data/docs/{main-concepts/exception-handling.md → exception-handling.md} +2 -9
- data/docs/{main-concepts/extending.md → extending.md} +2 -9
- data/docs/faq.md +3 -16
- data/docs/{main-concepts/fiber-scheduling.md → fiber-scheduling.md} +1 -9
- data/docs/link_rewriter.rb +16 -0
- data/docs/{getting-started/overview.md → overview.md} +1 -30
- data/docs/{getting-started/tutorial.md → tutorial.md} +3 -28
- data/docs/{_posts/2020-07-26-polyphony-0.44.md → whats-new.md} +3 -1
- data/examples/adapters/redis_client.rb +3 -2
- data/examples/io/echo_server.rb +1 -1
- data/examples/io/echo_server_plain_ruby.rb +26 -0
- data/ext/polyphony/backend_io_uring.c +154 -9
- data/ext/polyphony/backend_io_uring_context.c +21 -12
- data/ext/polyphony/backend_io_uring_context.h +12 -7
- data/ext/polyphony/backend_libev.c +1 -1
- data/ext/polyphony/extconf.rb +24 -8
- data/ext/polyphony/fiber.c +79 -2
- data/ext/polyphony/io_extensions.c +53 -0
- data/ext/polyphony/pipe.c +42 -2
- data/ext/polyphony/polyphony.c +345 -31
- data/ext/polyphony/polyphony.h +9 -2
- data/ext/polyphony/queue.c +181 -0
- data/ext/polyphony/ring_buffer.c +0 -1
- data/ext/polyphony/runqueue.c +8 -1
- data/ext/polyphony/runqueue_ring_buffer.c +13 -0
- data/ext/polyphony/runqueue_ring_buffer.h +2 -1
- data/ext/polyphony/socket_extensions.c +6 -0
- data/ext/polyphony/thread.c +34 -2
- data/lib/polyphony/adapters/process.rb +11 -1
- data/lib/polyphony/adapters/sequel.rb +1 -1
- data/lib/polyphony/core/channel.rb +2 -0
- data/lib/polyphony/core/debug.rb +1 -1
- data/lib/polyphony/core/global_api.rb +25 -24
- data/lib/polyphony/core/resource_pool.rb +7 -6
- data/lib/polyphony/core/sync.rb +2 -2
- data/lib/polyphony/core/thread_pool.rb +3 -3
- data/lib/polyphony/core/timer.rb +8 -8
- data/lib/polyphony/extensions/exception.rb +2 -0
- data/lib/polyphony/extensions/fiber.rb +15 -13
- data/lib/polyphony/extensions/io.rb +127 -5
- data/lib/polyphony/extensions/kernel.rb +20 -2
- data/lib/polyphony/extensions/openssl.rb +100 -11
- data/lib/polyphony/extensions/pipe.rb +103 -7
- data/lib/polyphony/extensions/process.rb +13 -1
- data/lib/polyphony/extensions/socket.rb +93 -27
- data/lib/polyphony/extensions/thread.rb +9 -1
- data/lib/polyphony/extensions/timeout.rb +1 -1
- data/lib/polyphony/version.rb +2 -1
- data/lib/polyphony.rb +27 -7
- data/polyphony.gemspec +1 -8
- data/test/stress.rb +1 -1
- data/test/test_global_api.rb +45 -7
- data/test/test_socket.rb +96 -0
- data/test/test_timer.rb +5 -5
- metadata +17 -40
- data/docs/_config.yml +0 -64
- data/docs/_includes/head.html +0 -40
- data/docs/_includes/title.html +0 -1
- data/docs/_sass/custom/custom.scss +0 -10
- data/docs/_sass/overrides.scss +0 -0
- data/docs/api-reference/exception.md +0 -31
- data/docs/api-reference/fiber.md +0 -425
- data/docs/api-reference/index.md +0 -9
- data/docs/api-reference/io.md +0 -36
- data/docs/api-reference/object.md +0 -99
- data/docs/api-reference/polyphony-baseexception.md +0 -33
- data/docs/api-reference/polyphony-cancel.md +0 -26
- data/docs/api-reference/polyphony-moveon.md +0 -24
- data/docs/api-reference/polyphony-net.md +0 -20
- data/docs/api-reference/polyphony-process.md +0 -28
- data/docs/api-reference/polyphony-resourcepool.md +0 -59
- data/docs/api-reference/polyphony-restart.md +0 -18
- data/docs/api-reference/polyphony-terminate.md +0 -18
- data/docs/api-reference/polyphony-threadpool.md +0 -67
- data/docs/api-reference/polyphony-throttler.md +0 -77
- data/docs/api-reference/polyphony.md +0 -36
- data/docs/api-reference/thread.md +0 -88
- data/docs/favicon.ico +0 -0
- data/docs/getting-started/index.md +0 -10
- data/docs/getting-started/installing.md +0 -34
- /data/{docs/assets/img → assets}/echo-fibers.svg +0 -0
- /data/{docs → assets}/polyphony-logo.png +0 -0
- /data/{docs/assets/img → assets}/sleeping-fiber.svg +0 -0
data/ext/polyphony/queue.c
CHANGED
|
@@ -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
|
|
data/ext/polyphony/ring_buffer.c
CHANGED
data/ext/polyphony/runqueue.c
CHANGED
|
@@ -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)
|
|
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;
|
data/ext/polyphony/thread.c
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
# @
|
|
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)
|
data/lib/polyphony/core/debug.rb
CHANGED
|
@@ -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
|
-
# @
|
|
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
|
|
14
|
-
# @
|
|
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
|
|
60
|
-
# @
|
|
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
|
-
# @
|
|
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
|
|
85
|
-
# @param interval
|
|
86
|
-
# @
|
|
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
|
-
# @
|
|
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
|
-
# @
|
|
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
|
|
164
|
-
# @
|
|
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
|
|
193
|
-
# @param
|
|
194
|
-
# @
|
|
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
|
-
# @
|
|
224
|
-
# @
|
|
225
|
-
# @
|
|
226
|
-
# @
|
|
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
|
-
# @
|
|
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
|
-
|
|
252
|
+
Polyphony.backend_sleep(interval)
|
|
252
253
|
exception = cancel_exception(exception)
|
|
253
254
|
exception.raising_fiber = Fiber.current
|
|
254
|
-
fiber.cancel(exception)
|
|
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
|
-
# @
|
|
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)
|
|
299
|
+
fiber.move_on(value)
|
|
299
300
|
end
|
|
300
301
|
block.call(canceller)
|
|
301
302
|
rescue Polyphony::MoveOn => e
|