polyphony 0.93 → 0.94
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/Gemfile.lock +8 -12
- data/examples/pipes/echo_server.rb +1 -1
- data/examples/pipes/http_server.rb +33 -0
- data/ext/polyphony/backend_common.c +50 -5
- data/ext/polyphony/backend_common.h +21 -13
- data/ext/polyphony/backend_io_uring.c +67 -131
- data/ext/polyphony/backend_libev.c +58 -89
- data/ext/polyphony/extconf.rb +2 -2
- data/ext/polyphony/io_extensions.c +67 -67
- data/ext/polyphony/polyphony.c +22 -22
- data/ext/polyphony/polyphony.h +0 -9
- data/lib/polyphony/version.rb +1 -1
- data/test/test_global_api.rb +1 -1
- metadata +8 -7
@@ -284,51 +284,25 @@ static inline int fd_from_io(VALUE io, rb_io_t **fptr, int write_mode, int recti
|
|
284
284
|
}
|
285
285
|
}
|
286
286
|
|
287
|
-
VALUE Backend_read(VALUE self, VALUE io, VALUE
|
287
|
+
VALUE Backend_read(VALUE self, VALUE io, VALUE buffer, VALUE length, VALUE to_eof, VALUE pos) {
|
288
288
|
Backend_t *backend;
|
289
289
|
struct libev_io watcher;
|
290
290
|
int fd;
|
291
291
|
rb_io_t *fptr;
|
292
292
|
|
293
|
-
struct
|
294
|
-
long buf_pos = FIX2INT(pos);
|
295
|
-
int shrinkable_string = 0;
|
296
|
-
int expandable_buffer = 0;
|
293
|
+
struct backend_buffer_spec buffer_spec = backend_get_buffer_spec(buffer, 0);
|
297
294
|
long total = 0;
|
298
295
|
VALUE switchpoint_result = Qnil;
|
299
296
|
int read_to_eof = RTEST(to_eof);
|
300
297
|
|
301
|
-
if (buffer.raw) {
|
302
|
-
if (buf_pos < 0 || buf_pos > buffer.len) buf_pos = buffer.len;
|
303
|
-
buffer.ptr += buf_pos;
|
304
|
-
buffer.len -= buf_pos;
|
305
|
-
}
|
306
|
-
else {
|
307
|
-
expandable_buffer = length == Qnil;
|
308
|
-
long expected_read_length = expandable_buffer ? 4096 : FIX2INT(length);
|
309
|
-
long string_cap = rb_str_capacity(str);
|
310
|
-
if (buf_pos < 0 || buf_pos > buffer.len) buf_pos = buffer.len;
|
311
|
-
|
312
|
-
if (string_cap < expected_read_length + buf_pos) {
|
313
|
-
shrinkable_string = io_setstrbuf(&str, expected_read_length + buf_pos);
|
314
|
-
buffer.ptr = (unsigned char *)RSTRING_PTR(str) + buf_pos;
|
315
|
-
buffer.len = expected_read_length;
|
316
|
-
}
|
317
|
-
else {
|
318
|
-
buffer.ptr += buf_pos;
|
319
|
-
buffer.len = string_cap - buf_pos;
|
320
|
-
if (buffer.len > expected_read_length)
|
321
|
-
buffer.len = expected_read_length;
|
322
|
-
}
|
323
|
-
}
|
324
|
-
|
325
298
|
GetBackend(self, backend);
|
299
|
+
backend_prepare_read_buffer(buffer, length, &buffer_spec, FIX2INT(pos));
|
326
300
|
fd = fd_from_io(io, &fptr, 0, 1);
|
327
301
|
watcher.fiber = Qnil;
|
328
302
|
|
329
303
|
while (1) {
|
330
304
|
backend->base.op_count++;
|
331
|
-
ssize_t result = read(fd,
|
305
|
+
ssize_t result = read(fd, buffer_spec.ptr, buffer_spec.len);
|
332
306
|
if (result < 0) {
|
333
307
|
int e = errno;
|
334
308
|
if (e != EWOULDBLOCK && e != EAGAIN) rb_syserr_fail(e, strerror(e));
|
@@ -346,40 +320,34 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof,
|
|
346
320
|
total += result;
|
347
321
|
if (!read_to_eof) break;
|
348
322
|
|
349
|
-
if (result ==
|
350
|
-
if (
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
rb_str_modify_expand(str, rb_str_capacity(str));
|
355
|
-
shrinkable_string = 0;
|
356
|
-
buffer.ptr = (unsigned char *)RSTRING_PTR(str) + total + buf_pos;
|
357
|
-
buffer.len = rb_str_capacity(str) - total - buf_pos;
|
323
|
+
if (result == buffer_spec.len) {
|
324
|
+
if (buffer_spec.expandable)
|
325
|
+
backend_grow_string_buffer(buffer, &buffer_spec, total);
|
326
|
+
else
|
327
|
+
break;
|
358
328
|
}
|
359
329
|
else {
|
360
|
-
|
361
|
-
|
362
|
-
if (!
|
330
|
+
buffer_spec.ptr += result;
|
331
|
+
buffer_spec.len -= result;
|
332
|
+
if (!buffer_spec.len) break;
|
363
333
|
}
|
364
334
|
}
|
365
335
|
}
|
366
336
|
|
367
|
-
if (!buffer.raw) {
|
368
|
-
io_set_read_length(str, buf_pos + total, shrinkable_string);
|
369
|
-
if (fptr) io_enc_str(str, fptr);
|
370
|
-
}
|
371
337
|
if (!total) return Qnil;
|
338
|
+
|
339
|
+
if (!buffer_spec.raw) backend_finalize_string_buffer(buffer, &buffer_spec, total, fptr);
|
372
340
|
|
373
341
|
RB_GC_GUARD(watcher.fiber);
|
374
342
|
RB_GC_GUARD(switchpoint_result);
|
375
343
|
|
376
|
-
return
|
344
|
+
return buffer_spec.raw ? INT2FIX(total) : buffer;
|
377
345
|
error:
|
378
346
|
return RAISE_EXCEPTION(switchpoint_result);
|
379
347
|
}
|
380
348
|
|
381
|
-
VALUE Backend_recv(VALUE self, VALUE io, VALUE
|
382
|
-
return Backend_read(self, io,
|
349
|
+
VALUE Backend_recv(VALUE self, VALUE io, VALUE buffer, VALUE length, VALUE pos) {
|
350
|
+
return Backend_read(self, io, buffer, length, Qnil, pos);
|
383
351
|
}
|
384
352
|
|
385
353
|
VALUE Backend_read_loop(VALUE self, VALUE io, VALUE maxlen) {
|
@@ -387,11 +355,11 @@ VALUE Backend_read_loop(VALUE self, VALUE io, VALUE maxlen) {
|
|
387
355
|
struct libev_io watcher;
|
388
356
|
int fd;
|
389
357
|
rb_io_t *fptr;
|
390
|
-
VALUE
|
358
|
+
VALUE buffer;
|
391
359
|
long total;
|
360
|
+
char *ptr;
|
392
361
|
long len = FIX2INT(maxlen);
|
393
362
|
int shrinkable;
|
394
|
-
char *buf;
|
395
363
|
VALUE switchpoint_result = Qnil;
|
396
364
|
|
397
365
|
READ_LOOP_PREPARE_STR();
|
@@ -402,7 +370,7 @@ VALUE Backend_read_loop(VALUE self, VALUE io, VALUE maxlen) {
|
|
402
370
|
|
403
371
|
while (1) {
|
404
372
|
backend->base.op_count++;
|
405
|
-
ssize_t n = read(fd,
|
373
|
+
ssize_t n = read(fd, ptr, len);
|
406
374
|
if (n < 0) {
|
407
375
|
int e = errno;
|
408
376
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
@@ -421,7 +389,7 @@ VALUE Backend_read_loop(VALUE self, VALUE io, VALUE maxlen) {
|
|
421
389
|
}
|
422
390
|
}
|
423
391
|
|
424
|
-
RB_GC_GUARD(
|
392
|
+
RB_GC_GUARD(buffer);
|
425
393
|
RB_GC_GUARD(watcher.fiber);
|
426
394
|
RB_GC_GUARD(switchpoint_result);
|
427
395
|
|
@@ -435,11 +403,11 @@ VALUE Backend_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method) {
|
|
435
403
|
struct libev_io watcher;
|
436
404
|
int fd;
|
437
405
|
rb_io_t *fptr;
|
438
|
-
VALUE
|
406
|
+
VALUE buffer;
|
439
407
|
long total;
|
408
|
+
char *ptr;
|
440
409
|
long len = 8192;
|
441
410
|
int shrinkable;
|
442
|
-
char *buf;
|
443
411
|
VALUE switchpoint_result = Qnil;
|
444
412
|
ID method_id = SYM2ID(method);
|
445
413
|
|
@@ -451,7 +419,7 @@ VALUE Backend_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method) {
|
|
451
419
|
|
452
420
|
while (1) {
|
453
421
|
backend->base.op_count++;
|
454
|
-
ssize_t n = read(fd,
|
422
|
+
ssize_t n = read(fd, ptr, len);
|
455
423
|
if (n < 0) {
|
456
424
|
int e = errno;
|
457
425
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
@@ -470,7 +438,7 @@ VALUE Backend_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method) {
|
|
470
438
|
}
|
471
439
|
}
|
472
440
|
|
473
|
-
RB_GC_GUARD(
|
441
|
+
RB_GC_GUARD(buffer);
|
474
442
|
RB_GC_GUARD(watcher.fiber);
|
475
443
|
RB_GC_GUARD(switchpoint_result);
|
476
444
|
|
@@ -479,15 +447,15 @@ error:
|
|
479
447
|
return RAISE_EXCEPTION(switchpoint_result);
|
480
448
|
}
|
481
449
|
|
482
|
-
VALUE Backend_write(VALUE self, VALUE io, VALUE
|
450
|
+
VALUE Backend_write(VALUE self, VALUE io, VALUE buffer) {
|
483
451
|
Backend_t *backend;
|
484
452
|
struct libev_io watcher;
|
485
453
|
int fd;
|
486
454
|
rb_io_t *fptr;
|
487
455
|
VALUE switchpoint_result = Qnil;
|
488
456
|
|
489
|
-
struct
|
490
|
-
long left =
|
457
|
+
struct backend_buffer_spec buffer_spec = backend_get_buffer_spec(buffer, 1);
|
458
|
+
long left = buffer_spec.len;
|
491
459
|
|
492
460
|
GetBackend(self, backend);
|
493
461
|
fd = fd_from_io(io, &fptr, 1, 0);
|
@@ -495,7 +463,7 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
|
495
463
|
|
496
464
|
while (left > 0) {
|
497
465
|
backend->base.op_count++;
|
498
|
-
ssize_t result = write(fd,
|
466
|
+
ssize_t result = write(fd, buffer_spec.ptr, left);
|
499
467
|
if (result < 0) {
|
500
468
|
int e = errno;
|
501
469
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
@@ -505,7 +473,7 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
|
505
473
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
506
474
|
}
|
507
475
|
else {
|
508
|
-
|
476
|
+
buffer_spec.ptr += result;
|
509
477
|
left -= result;
|
510
478
|
}
|
511
479
|
}
|
@@ -519,7 +487,7 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
|
519
487
|
RB_GC_GUARD(watcher.fiber);
|
520
488
|
RB_GC_GUARD(switchpoint_result);
|
521
489
|
|
522
|
-
return INT2FIX(
|
490
|
+
return INT2FIX(buffer_spec.len);
|
523
491
|
error:
|
524
492
|
return RAISE_EXCEPTION(switchpoint_result);
|
525
493
|
}
|
@@ -542,9 +510,9 @@ VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
542
510
|
|
543
511
|
iov = malloc(iov_count * sizeof(struct iovec));
|
544
512
|
for (int i = 0; i < argc; i++) {
|
545
|
-
VALUE
|
546
|
-
iov[i].iov_base = StringValuePtr(
|
547
|
-
iov[i].iov_len = RSTRING_LEN(
|
513
|
+
VALUE buffer = argv[i];
|
514
|
+
iov[i].iov_base = StringValuePtr(buffer);
|
515
|
+
iov[i].iov_len = RSTRING_LEN(buffer);
|
548
516
|
total_length += iov[i].iov_len;
|
549
517
|
}
|
550
518
|
iov_ptr = iov;
|
@@ -754,15 +722,15 @@ error:
|
|
754
722
|
return RAISE_EXCEPTION(switchpoint_result);
|
755
723
|
}
|
756
724
|
|
757
|
-
VALUE Backend_send(VALUE self, VALUE io, VALUE
|
725
|
+
VALUE Backend_send(VALUE self, VALUE io, VALUE buffer, VALUE flags) {
|
758
726
|
Backend_t *backend;
|
759
727
|
struct libev_io watcher;
|
760
728
|
int fd;
|
761
729
|
rb_io_t *fptr;
|
762
730
|
VALUE switchpoint_result = Qnil;
|
763
731
|
|
764
|
-
struct
|
765
|
-
long left =
|
732
|
+
struct backend_buffer_spec buffer_spec = backend_get_buffer_spec(buffer, 1);
|
733
|
+
long left = buffer_spec.len;
|
766
734
|
int flags_int = FIX2INT(flags);
|
767
735
|
|
768
736
|
GetBackend(self, backend);
|
@@ -771,7 +739,7 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
|
|
771
739
|
|
772
740
|
while (left > 0) {
|
773
741
|
backend->base.op_count++;
|
774
|
-
ssize_t result = send(fd,
|
742
|
+
ssize_t result = send(fd, buffer_spec.ptr, left, flags_int);
|
775
743
|
if (result < 0) {
|
776
744
|
int e = errno;
|
777
745
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
@@ -781,7 +749,7 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
|
|
781
749
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
782
750
|
}
|
783
751
|
else {
|
784
|
-
|
752
|
+
buffer_spec.ptr += result;
|
785
753
|
left -= result;
|
786
754
|
}
|
787
755
|
}
|
@@ -795,7 +763,7 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
|
|
795
763
|
RB_GC_GUARD(watcher.fiber);
|
796
764
|
RB_GC_GUARD(switchpoint_result);
|
797
765
|
|
798
|
-
return INT2FIX(
|
766
|
+
return INT2FIX(buffer_spec.len);
|
799
767
|
error:
|
800
768
|
return RAISE_EXCEPTION(switchpoint_result);
|
801
769
|
}
|
@@ -952,11 +920,11 @@ VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
952
920
|
rb_io_t *dest_fptr;
|
953
921
|
int left = 0;
|
954
922
|
int total = 0;
|
923
|
+
char *ptr;
|
955
924
|
int maxlen_i = FIX2INT(maxlen);
|
956
925
|
int splice_to_eof = maxlen_i < 0;
|
957
926
|
if (splice_to_eof) maxlen_i = -maxlen_i;
|
958
|
-
VALUE
|
959
|
-
char *buf = RSTRING_PTR(str);
|
927
|
+
VALUE buffer = rb_str_new(0, maxlen_i);
|
960
928
|
|
961
929
|
GetBackend(self, backend);
|
962
930
|
src_fd = fd_from_io(src, &src_fptr, 0, 0);
|
@@ -967,7 +935,8 @@ VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
967
935
|
int done;
|
968
936
|
while (1) {
|
969
937
|
backend->base.op_count++;
|
970
|
-
|
938
|
+
ptr = RSTRING_PTR(buffer);
|
939
|
+
ssize_t n = read(src_fd, ptr, maxlen_i);
|
971
940
|
if (n < 0) {
|
972
941
|
int e = errno;
|
973
942
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
@@ -984,7 +953,7 @@ VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
984
953
|
|
985
954
|
while (left > 0) {
|
986
955
|
backend->base.op_count++;
|
987
|
-
ssize_t n = write(dest_fd,
|
956
|
+
ssize_t n = write(dest_fd, ptr, left);
|
988
957
|
if (n < 0) {
|
989
958
|
int e = errno;
|
990
959
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
@@ -994,7 +963,7 @@ VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
994
963
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
995
964
|
}
|
996
965
|
else {
|
997
|
-
|
966
|
+
ptr += n;
|
998
967
|
left -= n;
|
999
968
|
}
|
1000
969
|
}
|
@@ -1008,7 +977,7 @@ VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
1008
977
|
|
1009
978
|
RB_GC_GUARD(watcher.fiber);
|
1010
979
|
RB_GC_GUARD(switchpoint_result);
|
1011
|
-
RB_GC_GUARD(
|
980
|
+
RB_GC_GUARD(buffer);
|
1012
981
|
|
1013
982
|
return INT2FIX(total);
|
1014
983
|
error:
|
@@ -1290,13 +1259,13 @@ inline VALUE Backend_run_idle_tasks(VALUE self) {
|
|
1290
1259
|
return self;
|
1291
1260
|
}
|
1292
1261
|
|
1293
|
-
static inline int splice_chunks_write(Backend_t *backend, int fd, VALUE
|
1294
|
-
char *
|
1295
|
-
int len = RSTRING_LEN(
|
1262
|
+
static inline int splice_chunks_write(Backend_t *backend, int fd, VALUE buffer, struct libev_rw_io *watcher, VALUE *result) {
|
1263
|
+
char *ptr = RSTRING_PTR(buffer);
|
1264
|
+
int len = RSTRING_LEN(buffer);
|
1296
1265
|
int left = len;
|
1297
1266
|
while (left > 0) {
|
1298
1267
|
backend->base.op_count++;
|
1299
|
-
ssize_t n = write(fd,
|
1268
|
+
ssize_t n = write(fd, ptr, left);
|
1300
1269
|
if (n < 0) {
|
1301
1270
|
int err = errno;
|
1302
1271
|
if ((err != EWOULDBLOCK && err != EAGAIN)) return err;
|
@@ -1305,7 +1274,7 @@ static inline int splice_chunks_write(Backend_t *backend, int fd, VALUE str, str
|
|
1305
1274
|
if (TEST_EXCEPTION(*result)) return -1;
|
1306
1275
|
}
|
1307
1276
|
else {
|
1308
|
-
|
1277
|
+
ptr += n;
|
1309
1278
|
left -= n;
|
1310
1279
|
}
|
1311
1280
|
}
|
@@ -1388,8 +1357,8 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
|
|
1388
1357
|
struct libev_rw_io watcher;
|
1389
1358
|
watcher.ctx.fiber = Qnil;
|
1390
1359
|
int maxlen = FIX2INT(chunk_size);
|
1391
|
-
VALUE str = Qnil;
|
1392
1360
|
VALUE chunk_len_value = Qnil;
|
1361
|
+
VALUE buffer;
|
1393
1362
|
|
1394
1363
|
int pipefd[2] = { -1, -1 };
|
1395
1364
|
if (pipe(pipefd) == -1) {
|
@@ -1414,8 +1383,8 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
|
|
1414
1383
|
chunk_len_value = INT2FIX(chunk_len);
|
1415
1384
|
|
1416
1385
|
if (chunk_prefix != Qnil) {
|
1417
|
-
|
1418
|
-
int err = splice_chunks_write(backend, dest_fd,
|
1386
|
+
buffer = (TYPE(chunk_prefix) == T_STRING) ? chunk_prefix : rb_funcall(chunk_prefix, ID_call, 1, chunk_len_value);
|
1387
|
+
int err = splice_chunks_write(backend, dest_fd, buffer, &watcher, &result);
|
1419
1388
|
if (err == -1) goto error; else if (err) goto syscallerror;
|
1420
1389
|
}
|
1421
1390
|
|
@@ -1429,8 +1398,8 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
|
|
1429
1398
|
}
|
1430
1399
|
|
1431
1400
|
if (chunk_postfix != Qnil) {
|
1432
|
-
|
1433
|
-
int err = splice_chunks_write(backend, dest_fd,
|
1401
|
+
buffer = (TYPE(chunk_postfix) == T_STRING) ? chunk_postfix : rb_funcall(chunk_postfix, ID_call, 1, chunk_len_value);
|
1402
|
+
int err = splice_chunks_write(backend, dest_fd, buffer, &watcher, &result);
|
1434
1403
|
if (err == -1) goto error; else if (err) goto syscallerror;
|
1435
1404
|
}
|
1436
1405
|
}
|
@@ -1444,7 +1413,7 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
|
|
1444
1413
|
result = backend_snooze(&backend->base);
|
1445
1414
|
if (TEST_EXCEPTION(result)) goto error;
|
1446
1415
|
}
|
1447
|
-
RB_GC_GUARD(
|
1416
|
+
RB_GC_GUARD(buffer);
|
1448
1417
|
RB_GC_GUARD(chunk_len_value);
|
1449
1418
|
RB_GC_GUARD(result);
|
1450
1419
|
if (pipefd[0] != -1) close(pipefd[0]);
|
data/ext/polyphony/extconf.rb
CHANGED
@@ -5,7 +5,7 @@ require 'mkmf'
|
|
5
5
|
|
6
6
|
dir_config 'polyphony_ext'
|
7
7
|
|
8
|
-
KERNEL_INFO_RE = /Linux (\d)\.(\d+)
|
8
|
+
KERNEL_INFO_RE = /Linux (\d)\.(\d+)(?:\.)?((?:\d+\.?)*)(?:\-)?([\w\-]+)?/
|
9
9
|
def get_config
|
10
10
|
config = { linux: !!(RUBY_PLATFORM =~ /linux/) }
|
11
11
|
return config if !config[:linux]
|
@@ -14,7 +14,7 @@ def get_config
|
|
14
14
|
m = kernel_info.match(KERNEL_INFO_RE)
|
15
15
|
raise "Could not parse Linux kernel information (#{kernel_info.inspect})" if !m
|
16
16
|
|
17
|
-
version, major_revision, distribution = m[1].to_i, m[2].to_i, m[
|
17
|
+
version, major_revision, distribution = m[1].to_i, m[2].to_i, m[4]
|
18
18
|
config[:pidfd_open] = (version == 5) && (major_revision >= 3)
|
19
19
|
|
20
20
|
force_libev = ENV['POLYPHONY_LIBEV'] != nil
|