polyphony 0.62 → 0.66

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2cea172818871812ebbafcbee0a4b98d130a351f904d7732a02400ef363eac62
4
- data.tar.gz: f4ef85515436a463d3732f04bbef457426f267fac01f5c5c28619e42334cd745
3
+ metadata.gz: b8e2aa3d011286dda93222164cbf66f1ec4c18b9c212ee7a70dbebd4bc523943
4
+ data.tar.gz: 99b5fb95c682dfad8df33f07d98bfab7f2109b9d4ec0e24720869c2d331f23fb
5
5
  SHA512:
6
- metadata.gz: 489b813f1bb2d7d97f87a60024b0665761571c4227e4fab6c733dcdb62b6ee98760473202c9154eb39a4b544663f759e4da6e70603d483e9f2ec2a64363cd4e1
7
- data.tar.gz: 05b232d7d67120e0983e60855c928beac6e91271fafc87586da7cc7543128fe326be04d126154ac7e0b0c0b249bf41ca90ab902f79f4a5fbf00cad498061f7e7
6
+ metadata.gz: 27c65b6e340d1aad41d38b4b322b98d282f96fe6d136c897ab8de14651b2da3cfc392650600d63983f76b5fb1dc70e4e49116efb289a790a509bec63caa9b9e4
7
+ data.tar.gz: 94e62ac7fbcb6d085af7475d987eca45be191aaf7654c3bacb07c4f7793d450281d3da1b08b12636a49398e97c1043c3a2cd628018925bdc082e02a0859743bc
@@ -7,7 +7,7 @@ jobs:
7
7
  strategy:
8
8
  fail-fast: false
9
9
  matrix:
10
- os: [ubuntu-latest]
10
+ os: [ubuntu-latest, ubuntu-18.04, macos-10.15]
11
11
  ruby: [2.6, 2.7, 3.0]
12
12
 
13
13
  name: >-
data/CHANGELOG.md CHANGED
@@ -1,3 +1,21 @@
1
+ ## 0.66 2021-08-01
2
+
3
+ - Fix all splicing APIs on non-linux OSes (#63)
4
+ - Add GC marking of buffers when cancelling read/write ops in io_uring backend
5
+
6
+ ## 0.65 2021-07-29
7
+
8
+ - Add `#__polyphony_read_method__` method for read method detection
9
+
10
+ ## 0.64 2021-07-26
11
+
12
+ - Add optional raise_on_eof argument to `#readpartial`
13
+
14
+ ## 0.63 2021-07-26
15
+
16
+ - Add support for specifying buf and buf_pos in `IO#read`
17
+ - Fix `Socket#read` to work and conform to `IO#read` interface
18
+
1
19
  ## 0.62 2021-07-21
2
20
 
3
21
  - Add `runqueue_size` to backend stats
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- polyphony (0.62)
4
+ polyphony (0.66)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/Rakefile CHANGED
@@ -9,8 +9,8 @@ Rake::ExtensionTask.new("polyphony_ext") do |ext|
9
9
  end
10
10
 
11
11
  task :recompile => [:clean, :compile]
12
-
13
12
  task :default => [:compile, :test]
13
+
14
14
  task :test do
15
15
  exec 'ruby test/run.rb'
16
16
  end
@@ -25,6 +25,8 @@ VALUE SYM_send;
25
25
  VALUE SYM_splice;
26
26
  VALUE SYM_write;
27
27
 
28
+ VALUE eArgumentError;
29
+
28
30
  #ifdef POLYPHONY_UNSET_NONBLOCK
29
31
  #define io_unset_nonblock(fptr, io) io_verify_blocking_mode(fptr, io, Qtrue)
30
32
  #else
@@ -45,6 +47,7 @@ typedef struct Backend_t {
45
47
  static void Backend_mark(void *ptr) {
46
48
  Backend_t *backend = ptr;
47
49
  backend_base_mark(&backend->base);
50
+ context_store_mark_taken_buffers(&backend->store);
48
51
  }
49
52
 
50
53
  static void Backend_free(void *ptr) {
@@ -349,8 +352,11 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof,
349
352
 
350
353
  int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
351
354
  int completed = context_store_release(&backend->store, ctx);
352
- RAISE_IF_EXCEPTION(resume_value);
353
- if (!completed) return resume_value;
355
+ if (!completed) {
356
+ context_attach_buffers(ctx, 1, &str);
357
+ RAISE_IF_EXCEPTION(resume_value);
358
+ return resume_value;
359
+ }
354
360
  RB_GC_GUARD(resume_value);
355
361
 
356
362
  if (result < 0)
@@ -410,8 +416,11 @@ VALUE Backend_read_loop(VALUE self, VALUE io, VALUE maxlen) {
410
416
 
411
417
  ssize_t result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
412
418
  int completed = context_store_release(&backend->store, ctx);
413
- RAISE_IF_EXCEPTION(resume_value);
414
- if (!completed) return resume_value;
419
+ if (!completed) {
420
+ context_attach_buffers(ctx, 1, &str);
421
+ RAISE_IF_EXCEPTION(resume_value);
422
+ return resume_value;
423
+ }
415
424
  RB_GC_GUARD(resume_value);
416
425
 
417
426
  if (result < 0)
@@ -457,8 +466,11 @@ VALUE Backend_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method) {
457
466
 
458
467
  ssize_t result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
459
468
  int completed = context_store_release(&backend->store, ctx);
460
- RAISE_IF_EXCEPTION(resume_value);
461
- if (!completed) return resume_value;
469
+ if (!completed) {
470
+ context_attach_buffers(ctx, 1, &str);
471
+ RAISE_IF_EXCEPTION(resume_value);
472
+ return resume_value;
473
+ }
462
474
  RB_GC_GUARD(resume_value);
463
475
 
464
476
  if (result < 0)
@@ -500,8 +512,11 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
500
512
 
501
513
  int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
502
514
  int completed = context_store_release(&backend->store, ctx);
503
- RAISE_IF_EXCEPTION(resume_value);
504
- if (!completed) return resume_value;
515
+ if (!completed) {
516
+ context_attach_buffers(ctx, 1, &str);
517
+ RAISE_IF_EXCEPTION(resume_value);
518
+ return resume_value;
519
+ }
505
520
  RB_GC_GUARD(resume_value);
506
521
 
507
522
  if (result < 0)
@@ -549,12 +564,10 @@ VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
549
564
 
550
565
  int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
551
566
  int completed = context_store_release(&backend->store, ctx);
552
- if (TEST_EXCEPTION(resume_value)) {
553
- free(iov);
554
- RAISE_EXCEPTION(resume_value);
555
- }
556
567
  if (!completed) {
557
568
  free(iov);
569
+ context_attach_buffers(ctx, argc, argv);
570
+ RAISE_IF_EXCEPTION(resume_value);
558
571
  return resume_value;
559
572
  }
560
573
  RB_GC_GUARD(resume_value);
@@ -588,8 +601,7 @@ VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
588
601
 
589
602
  VALUE Backend_write_m(int argc, VALUE *argv, VALUE self) {
590
603
  if (argc < 2)
591
- // TODO: raise ArgumentError
592
- rb_raise(rb_eRuntimeError, "(wrong number of arguments (expected 2 or more))");
604
+ rb_raise(eArgumentError, "(wrong number of arguments (expected 2 or more))");
593
605
 
594
606
  return (argc == 2) ?
595
607
  Backend_write(self, argv[0], argv[1]) :
@@ -628,8 +640,11 @@ VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length, VALUE pos) {
628
640
 
629
641
  int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
630
642
  int completed = context_store_release(&backend->store, ctx);
631
- RAISE_IF_EXCEPTION(resume_value);
632
- if (!completed) return resume_value;
643
+ if (!completed) {
644
+ context_attach_buffers(ctx, 1, &str);
645
+ RAISE_IF_EXCEPTION(resume_value);
646
+ return resume_value;
647
+ }
633
648
  RB_GC_GUARD(resume_value);
634
649
 
635
650
  if (result < 0)
@@ -675,8 +690,11 @@ VALUE Backend_recv_loop(VALUE self, VALUE io, VALUE maxlen) {
675
690
 
676
691
  int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
677
692
  int completed = context_store_release(&backend->store, ctx);
678
- RAISE_IF_EXCEPTION(resume_value);
679
- if (!completed) return resume_value;
693
+ if (!completed) {
694
+ context_attach_buffers(ctx, 1, &str);
695
+ RAISE_IF_EXCEPTION(resume_value);
696
+ return resume_value;
697
+ }
680
698
  RB_GC_GUARD(resume_value);
681
699
 
682
700
  if (result < 0)
@@ -721,8 +739,11 @@ VALUE Backend_recv_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method)
721
739
 
722
740
  int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
723
741
  int completed = context_store_release(&backend->store, ctx);
724
- RAISE_IF_EXCEPTION(resume_value);
725
- if (!completed) return resume_value;
742
+ if (!completed) {
743
+ context_attach_buffers(ctx, 1, &str);
744
+ RAISE_IF_EXCEPTION(resume_value);
745
+ return resume_value;
746
+ }
726
747
  RB_GC_GUARD(resume_value);
727
748
 
728
749
  if (result < 0)
@@ -764,8 +785,11 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
764
785
 
765
786
  int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
766
787
  int completed = context_store_release(&backend->store, ctx);
767
- RAISE_IF_EXCEPTION(resume_value);
768
- if (!completed) return resume_value;
788
+ if (!completed) {
789
+ context_attach_buffers(ctx, 1, &str);
790
+ RAISE_IF_EXCEPTION(resume_value);
791
+ return resume_value;
792
+ }
769
793
  RB_GC_GUARD(resume_value);
770
794
 
771
795
  if (result < 0)
@@ -1165,6 +1189,24 @@ struct io_uring_sqe *Backend_chain_prepare_splice(Backend_t *backend, VALUE src,
1165
1189
  return sqe;
1166
1190
  }
1167
1191
 
1192
+ void Backend_chain_ctx_attach_buffers(op_context_t *ctx, int argc, VALUE *argv) {
1193
+ int count = 0;
1194
+ if (argc > 1) ctx->buffers = malloc(sizeof(VALUE) * (argc - 1));
1195
+
1196
+ for (int i = 0; i < argc; i++) {
1197
+ VALUE op = argv[i];
1198
+ VALUE op_type = RARRAY_AREF(op, 0);
1199
+
1200
+ if (op_type == SYM_write || op_type == SYM_send) {
1201
+ if (!count) ctx->buffer0 = RARRAY_AREF(op, 2);
1202
+ else ctx->buffers[count - 1] = RARRAY_AREF(op, 2);
1203
+ count++;
1204
+ }
1205
+ }
1206
+ ctx->buffer_count = count;
1207
+ }
1208
+
1209
+
1168
1210
  VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
1169
1211
  VALUE resume_value = Qnil;
1170
1212
  unsigned int sqe_count = 0;
@@ -1218,6 +1260,8 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
1218
1260
  int result = ctx->result;
1219
1261
  int completed = context_store_release(&backend->store, ctx);
1220
1262
  if (!completed) {
1263
+ Backend_chain_ctx_attach_buffers(ctx, argc, argv);
1264
+
1221
1265
  // op was not completed (an exception was raised), so we need to cancel it
1222
1266
  ctx->result = -ECANCELED;
1223
1267
  struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
@@ -1409,6 +1453,7 @@ syscallerror:
1409
1453
  if (pipefd[1] != -1) close(pipefd[1]);
1410
1454
  rb_syserr_fail(err, strerror(err));
1411
1455
  error:
1456
+ context_attach_buffers_v(ctx, 4, prefix, postfix, chunk_prefix, chunk_postfix);
1412
1457
  if (pipefd[0] != -1) close(pipefd[0]);
1413
1458
  if (pipefd[1] != -1) close(pipefd[1]);
1414
1459
  return RAISE_EXCEPTION(switchpoint_result);
@@ -1469,7 +1514,6 @@ void Init_Backend() {
1469
1514
  rb_define_method(cBackend, "waitpid", Backend_waitpid, 1);
1470
1515
  rb_define_method(cBackend, "write", Backend_write_m, -1);
1471
1516
 
1472
-
1473
1517
  #ifdef POLYPHONY_UNSET_NONBLOCK
1474
1518
  ID_ivar_is_nonblocking = rb_intern("@is_nonblocking");
1475
1519
  #endif
@@ -1480,6 +1524,8 @@ void Init_Backend() {
1480
1524
  SYM_write = ID2SYM(rb_intern("write"));
1481
1525
 
1482
1526
  backend_setup_stats_symbols();
1527
+
1528
+ eArgumentError = rb_const_get(rb_cObject, rb_intern("ArgumentError"));
1483
1529
  }
1484
1530
 
1485
1531
  #endif // POLYPHONY_BACKEND_LIBURING
@@ -50,6 +50,7 @@ inline op_context_t *context_store_acquire(op_context_store_t *store, enum op_ty
50
50
  ctx->resume_value = Qnil;
51
51
  ctx->ref_count = 2;
52
52
  ctx->result = 0;
53
+ ctx->buffer_count = 0;
53
54
 
54
55
  store->taken_count++;
55
56
 
@@ -67,6 +68,8 @@ inline int context_store_release(op_context_store_t *store, op_context_t *ctx) {
67
68
  ctx->ref_count--;
68
69
  if (ctx->ref_count) return 0;
69
70
 
71
+ if (ctx->buffer_count > 1) free(ctx->buffers);
72
+
70
73
  store->taken_count--;
71
74
  store->available_count++;
72
75
 
@@ -93,3 +96,42 @@ void context_store_free(op_context_store_t *store) {
93
96
  store->taken = next;
94
97
  }
95
98
  }
99
+
100
+ inline void context_store_mark_taken_buffers(op_context_store_t *store) {
101
+ op_context_t *ctx = store->taken;
102
+ while (ctx) {
103
+ for (unsigned int i = 0; i < ctx->buffer_count; i++)
104
+ rb_gc_mark(i == 0 ? ctx->buffer0 : ctx->buffers[i - 1]);
105
+ ctx = ctx->next;
106
+ }
107
+ }
108
+
109
+ inline void context_attach_buffers(op_context_t *ctx, unsigned int count, VALUE *buffers) {
110
+ // attaching buffers to the context is done in order to ensure that any GC
111
+ // pass done before the context is released will mark those buffers, even if
112
+ // the fiber has already been resumed and the buffers are not in use anymore.
113
+ // This is done in order to prevent a possible race condition where on the
114
+ // kernel side the buffers are still in use, but in userspace they have
115
+ // effectively been freed after a GC pass.
116
+ ctx->buffer_count = count;
117
+ if (count > 1)
118
+ ctx->buffers = malloc(sizeof(VALUE) * (count - 1));
119
+ for (unsigned int i = 0; i < count; i++)
120
+ if (!i) ctx->buffer0 = buffers[0];
121
+ else ctx->buffers[i - 1] = buffers[i];
122
+ }
123
+
124
+ inline void context_attach_buffers_v(op_context_t *ctx, unsigned int count, ...) {
125
+ va_list values;
126
+
127
+ va_start(values, count);
128
+
129
+ ctx->buffer_count = count;
130
+ if (count > 1)
131
+ ctx->buffers = malloc(sizeof(VALUE) * (count - 1));
132
+ for (unsigned int i = 0; i < count; i++)
133
+ if (!i) ctx->buffer0 = va_arg(values, VALUE);
134
+ else ctx->buffers[i - 1] = va_arg(values, VALUE);
135
+
136
+ va_end(values);
137
+ }
@@ -27,6 +27,9 @@ typedef struct op_context {
27
27
  int result;
28
28
  VALUE fiber;
29
29
  VALUE resume_value;
30
+ unsigned int buffer_count;
31
+ VALUE buffer0;
32
+ VALUE *buffers;
30
33
  } op_context_t;
31
34
 
32
35
  typedef struct op_context_store {
@@ -43,14 +46,8 @@ void context_store_initialize(op_context_store_t *store);
43
46
  op_context_t *context_store_acquire(op_context_store_t *store, enum op_type type);
44
47
  int context_store_release(op_context_store_t *store, op_context_t *ctx);
45
48
  void context_store_free(op_context_store_t *store);
46
-
47
- inline unsigned int OP_CONTEXT_RELEASE(op_context_store_t *store, op_context_t *ctx) {
48
- int completed = !ctx->ref_count;
49
- if (ctx->ref_count)
50
- ctx->ref_count -= 1;
51
- else
52
- context_store_release(store, ctx);
53
- return completed;
54
- }
49
+ void context_store_mark_taken_buffers(op_context_store_t *store);
50
+ void context_attach_buffers(op_context_t *ctx, unsigned int count, VALUE *buffers);
51
+ void context_attach_buffers_v(op_context_t *ctx, unsigned int count, ...);
55
52
 
56
53
  #endif /* BACKEND_IO_URING_CONTEXT_H */
@@ -941,9 +941,8 @@ VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
941
941
  error:
942
942
  return RAISE_EXCEPTION(switchpoint_result);
943
943
  }
944
- #endif
945
-
946
- VALUE Backend_fake_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
944
+ #else
945
+ VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
947
946
  Backend_t *backend;
948
947
  struct libev_io watcher;
949
948
  VALUE switchpoint_result = Qnil;
@@ -1018,7 +1017,7 @@ error:
1018
1017
  return RAISE_EXCEPTION(switchpoint_result);
1019
1018
  }
1020
1019
 
1021
- VALUE Backend_fake_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
1020
+ VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
1022
1021
  Backend_t *backend;
1023
1022
  struct libev_io watcher;
1024
1023
  VALUE switchpoint_result = Qnil;
@@ -1097,6 +1096,7 @@ done:
1097
1096
  error:
1098
1097
  return RAISE_EXCEPTION(switchpoint_result);
1099
1098
  }
1099
+ #endif
1100
1100
 
1101
1101
  VALUE Backend_wait_io(VALUE self, VALUE io, VALUE write) {
1102
1102
  Backend_t *backend;
@@ -1384,6 +1384,64 @@ inline int splice_chunks_write(Backend_t *backend, int fd, VALUE str, struct lib
1384
1384
  return 0;
1385
1385
  }
1386
1386
 
1387
+ static inline int splice_chunks_splice(Backend_t *backend, int src_fd, int dest_fd, int maxlen,
1388
+ struct libev_rw_io *watcher, VALUE *result, int *chunk_len) {
1389
+ #ifdef POLYPHONY_LINUX
1390
+ backend->base.op_count++;
1391
+ while (1) {
1392
+ *chunk_len = splice(src_fd, 0, dest_fd, 0, maxlen, 0);
1393
+ if (*chunk_len >= 0) return 0;
1394
+
1395
+ int err = errno;
1396
+ if (err != EWOULDBLOCK && err != EAGAIN) return err;
1397
+
1398
+ *result = libev_wait_rw_fd_with_watcher(backend, src_fd, dest_fd, watcher);
1399
+ if (TEST_EXCEPTION(*result)) return -1;
1400
+ }
1401
+ #else
1402
+ char *buf = malloc(maxlen);
1403
+ int ret;
1404
+
1405
+ backend->base.op_count++;
1406
+ while (1) {
1407
+ *chunk_len = read(src_fd, buf, maxlen);
1408
+ if (*chunk_len >= 0) break;
1409
+
1410
+ ret = errno;
1411
+ if ((ret != EWOULDBLOCK && ret != EAGAIN)) goto done;
1412
+
1413
+ *result = libev_wait_rw_fd_with_watcher(backend, src_fd, -1, watcher);
1414
+ if (TEST_EXCEPTION(*result)) goto exception;
1415
+ }
1416
+
1417
+ backend->base.op_count++;
1418
+ char *ptr = buf;
1419
+ int left = *chunk_len;
1420
+ while (left > 0) {
1421
+ ssize_t n = write(dest_fd, ptr, left);
1422
+ if (n < 0) {
1423
+ ret = errno;
1424
+ if ((ret != EWOULDBLOCK && ret != EAGAIN)) goto done;
1425
+
1426
+ *result = libev_wait_rw_fd_with_watcher(backend, -1, dest_fd, watcher);
1427
+
1428
+ if (TEST_EXCEPTION(*result)) goto exception;
1429
+ }
1430
+ else {
1431
+ ptr += n;
1432
+ left -= n;
1433
+ }
1434
+ }
1435
+ ret = 0;
1436
+ goto done;
1437
+ exception:
1438
+ ret = -1;
1439
+ done:
1440
+ free(buf);
1441
+ return ret;
1442
+ #endif
1443
+ }
1444
+
1387
1445
  VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VALUE postfix, VALUE chunk_prefix, VALUE chunk_postfix, VALUE chunk_size) {
1388
1446
  Backend_t *backend;
1389
1447
  GetBackend(self, backend);
@@ -1421,26 +1479,13 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
1421
1479
  fcntl(pipefd[1], F_SETFL, O_NONBLOCK);
1422
1480
 
1423
1481
  if (prefix != Qnil) {
1424
- int err = splice_chunks_write(backend, dest_fptr->fd, prefix, &watcher, &result);
1482
+ err = splice_chunks_write(backend, dest_fptr->fd, prefix, &watcher, &result);
1425
1483
  if (err == -1) goto error; else if (err) goto syscallerror;
1426
1484
  }
1427
1485
  while (1) {
1428
- int chunk_len;
1429
- // splice to pipe
1430
- while (1) {
1431
- backend->base.op_count++;
1432
- chunk_len = splice(src_fptr->fd, 0, pipefd[1], 0, maxlen, 0);
1433
- if (chunk_len < 0) {
1434
- err = errno;
1435
- if (err != EWOULDBLOCK && err != EAGAIN) goto syscallerror;
1436
-
1437
- result = libev_wait_rw_fd_with_watcher(backend, src_fptr->fd, pipefd[1], &watcher);
1438
- if (TEST_EXCEPTION(result)) goto error;
1439
- }
1440
- else {
1441
- break;
1442
- }
1443
- }
1486
+ int chunk_len = 0;
1487
+ err = splice_chunks_splice(backend, src_fptr->fd, pipefd[1], maxlen, &watcher, &result, &chunk_len);
1488
+ if (err == -1) goto error; else if (err) goto syscallerror;
1444
1489
  if (chunk_len == 0) break;
1445
1490
 
1446
1491
  total += chunk_len;
@@ -1453,20 +1498,12 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
1453
1498
  }
1454
1499
 
1455
1500
  int left = chunk_len;
1456
- while (1) {
1457
- backend->base.op_count++;
1458
- int n = splice(pipefd[0], 0, dest_fptr->fd, 0, left, 0);
1459
- if (n < 0) {
1460
- err = errno;
1461
- if (err != EWOULDBLOCK && err != EAGAIN) goto syscallerror;
1501
+ while (left > 0) {
1502
+ int len;
1503
+ err = splice_chunks_splice(backend, pipefd[0], dest_fptr->fd, left, &watcher, &result, &len);
1504
+ if (err == -1) goto error; else if (err) goto syscallerror;
1462
1505
 
1463
- result = libev_wait_rw_fd_with_watcher(backend, pipefd[0], dest_fptr->fd, &watcher);
1464
- if (TEST_EXCEPTION(result)) goto error;
1465
- }
1466
- else {
1467
- left -= n;
1468
- if (left == 0) break;
1469
- }
1506
+ left -= len;
1470
1507
  }
1471
1508
 
1472
1509
  if (chunk_postfix != Qnil) {
@@ -1550,13 +1587,8 @@ void Init_Backend() {
1550
1587
  rb_define_method(cBackend, "sendv", Backend_sendv, 3);
1551
1588
  rb_define_method(cBackend, "sleep", Backend_sleep, 1);
1552
1589
 
1553
- #ifdef POLYPHONY_LINUX
1554
1590
  rb_define_method(cBackend, "splice", Backend_splice, 3);
1555
1591
  rb_define_method(cBackend, "splice_to_eof", Backend_splice_to_eof, 3);
1556
- #else
1557
- rb_define_method(cBackend, "splice", Backend_fake_splice, 3);
1558
- rb_define_method(cBackend, "splice_to_eof", Backend_fake_splice_to_eof, 3);
1559
- #endif
1560
1592
 
1561
1593
  rb_define_method(cBackend, "timeout", Backend_timeout, -1);
1562
1594
  rb_define_method(cBackend, "timer_loop", Backend_timer_loop, 1);
@@ -78,7 +78,7 @@ inline void queue_schedule_blocked_fibers_to_capacity(Queue_t *queue) {
78
78
  }
79
79
  }
80
80
 
81
- inline void capped_queue_block_push(Queue_t *queue) {
81
+ static inline void capped_queue_block_push(Queue_t *queue) {
82
82
  VALUE fiber = rb_fiber_current();
83
83
  VALUE backend = rb_ivar_get(rb_thread_current(), ID_ivar_backend);
84
84
  VALUE switchpoint_result;
@@ -44,15 +44,15 @@ inline void runqueue_clear(runqueue_t *runqueue) {
44
44
  runqueue_ring_buffer_clear(&runqueue->entries);
45
45
  }
46
46
 
47
- inline long runqueue_size(runqueue_t *runqueue) {
47
+ inline unsigned int runqueue_size(runqueue_t *runqueue) {
48
48
  return runqueue->entries.size;
49
49
  }
50
50
 
51
- inline long runqueue_len(runqueue_t *runqueue) {
51
+ inline unsigned int runqueue_len(runqueue_t *runqueue) {
52
52
  return runqueue->entries.count;
53
53
  }
54
54
 
55
- inline long runqueue_max_len(runqueue_t *runqueue) {
55
+ inline unsigned int runqueue_max_len(runqueue_t *runqueue) {
56
56
  unsigned int max_len = runqueue->high_watermark;
57
57
  runqueue->high_watermark = 0;
58
58
  return max_len;
@@ -19,9 +19,9 @@ runqueue_entry runqueue_shift(runqueue_t *runqueue);
19
19
  void runqueue_delete(runqueue_t *runqueue, VALUE fiber);
20
20
  int runqueue_index_of(runqueue_t *runqueue, VALUE fiber);
21
21
  void runqueue_clear(runqueue_t *runqueue);
22
- long runqueue_size(runqueue_t *runqueue);
23
- long runqueue_len(runqueue_t *runqueue);
24
- long runqueue_max_len(runqueue_t *runqueue);
22
+ unsigned int runqueue_size(runqueue_t *runqueue);
23
+ unsigned int runqueue_len(runqueue_t *runqueue);
24
+ unsigned int runqueue_max_len(runqueue_t *runqueue);
25
25
  int runqueue_empty_p(runqueue_t *runqueue);
26
26
 
27
27
  #endif /* RUNQUEUE_H */
@@ -76,6 +76,10 @@ end
76
76
 
77
77
  # IO instance method patches
78
78
  class ::IO
79
+ def __polyphony_read_method__
80
+ :backend_read
81
+ end
82
+
79
83
  # def each(sep = $/, limit = nil, chomp: nil)
80
84
  # sep, limit = $/, sep if sep.is_a?(Integer)
81
85
  # end
@@ -108,7 +112,11 @@ class ::IO
108
112
  end
109
113
 
110
114
  alias_method :orig_read, :read
111
- def read(len = nil)
115
+ def read(len = nil, buf = nil, buf_pos = 0)
116
+ if buf
117
+ return Polyphony.backend_read(self, buf, len, true, buf_pos)
118
+ end
119
+
112
120
  @read_buffer ||= +''
113
121
  result = Polyphony.backend_read(self, @read_buffer, len, true, -1)
114
122
  return nil unless result
@@ -119,9 +127,9 @@ class ::IO
119
127
  end
120
128
 
121
129
  alias_method :orig_readpartial, :read
122
- def readpartial(len, str = +'', buffer_pos = 0)
130
+ def readpartial(len, str = +'', buffer_pos = 0, raise_on_eof = true)
123
131
  result = Polyphony.backend_read(self, str, len, false, buffer_pos)
124
- raise EOFError unless result
132
+ raise EOFError if !result && raise_on_eof
125
133
 
126
134
  result
127
135
  end
@@ -5,6 +5,10 @@ require_relative './socket'
5
5
 
6
6
  # OpenSSL socket helper methods (to make it compatible with Socket API) and overrides
7
7
  class ::OpenSSL::SSL::SSLSocket
8
+ def __polyphony_read_method__
9
+ :readpartial
10
+ end
11
+
8
12
  alias_method :orig_initialize, :initialize
9
13
  def initialize(socket, context = nil)
10
14
  socket = socket.respond_to?(:io) ? socket.io || socket : socket
@@ -64,7 +68,21 @@ class ::OpenSSL::SSL::SSLSocket
64
68
  # @sync = osync
65
69
  end
66
70
 
67
- def readpartial(maxlen, buf = +'', buffer_pos = 0)
71
+ alias_method :orig_read, :read
72
+ def read(maxlen = nil, buf = nil, buf_pos = 0)
73
+ return readpartial(maxlen, buf, buf_pos) if buf
74
+
75
+ buf = +''
76
+ return readpartial(maxlen, buf) if maxlen
77
+
78
+ while true
79
+ readpartial(4096, buf, -1)
80
+ end
81
+ rescue EOFError
82
+ buf
83
+ end
84
+
85
+ def readpartial(maxlen, buf = +'', buffer_pos = 0, raise_on_eof = true)
68
86
  if buffer_pos != 0
69
87
  if (result = sysread(maxlen, +''))
70
88
  if buffer_pos == -1
@@ -76,7 +94,9 @@ class ::OpenSSL::SSL::SSLSocket
76
94
  else
77
95
  result = sysread(maxlen, buf)
78
96
  end
79
- result || (raise EOFError)
97
+
98
+ raise EOFError if !result && raise_on_eof
99
+ result
80
100
  end
81
101
 
82
102
  def read_loop(maxlen = 8192)
@@ -5,6 +5,12 @@ require 'socket'
5
5
  require_relative './io'
6
6
  require_relative '../core/thread_pool'
7
7
 
8
+ class BasicSocket
9
+ def __polyphony_read_method__
10
+ :backend_recv
11
+ end
12
+ end
13
+
8
14
  # Socket overrides (eventually rewritten in C)
9
15
  class ::Socket
10
16
  def accept
@@ -22,6 +28,23 @@ class ::Socket
22
28
  Polyphony.backend_connect(self, addr.ip_address, addr.ip_port)
23
29
  end
24
30
 
31
+ alias_method :orig_read, :read
32
+ def read(maxlen = nil, buf = nil, buf_pos = 0)
33
+ return Polyphony.backend_recv(self, buf, maxlen, buf_pos) if buf
34
+ return Polyphony.backend_recv(self, buf || +'', maxlen, 0) if maxlen
35
+
36
+ buf = +''
37
+ len = buf.bytesize
38
+ while true
39
+ Polyphony.backend_recv(self, buf, maxlen || 4096, -1)
40
+ new_len = buf.bytesize
41
+ break if new_len == len
42
+
43
+ len = new_len
44
+ end
45
+ buf
46
+ end
47
+
25
48
  def recv(maxlen, flags = 0, outbuf = nil)
26
49
  Polyphony.backend_recv(self, outbuf || +'', maxlen, 0)
27
50
  end
@@ -60,8 +83,9 @@ class ::Socket
60
83
  # Polyphony.backend_send(self, mesg, 0)
61
84
  # end
62
85
 
63
- def readpartial(maxlen, str = +'', buffer_pos = 0)
64
- Polyphony.backend_recv(self, str, maxlen, buffer_pos)
86
+ def readpartial(maxlen, str = +'', buffer_pos = 0, raise_on_eof = true)
87
+ result = Polyphony.backend_recv(self, str, maxlen, buffer_pos)
88
+ raise EOFError if !result && raise_on_eof
65
89
  end
66
90
 
67
91
  ZERO_LINGER = [0, 0].pack('ii').freeze
@@ -140,6 +164,23 @@ class ::TCPSocket
140
164
  setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEPORT, 1)
141
165
  end
142
166
 
167
+ alias_method :orig_read, :read
168
+ def read(maxlen = nil, buf = nil, buf_pos = 0)
169
+ return Polyphony.backend_recv(self, buf, maxlen, buf_pos) if buf
170
+ return Polyphony.backend_recv(self, buf || +'', maxlen, 0) if maxlen
171
+
172
+ buf = +''
173
+ len = buf.bytesize
174
+ while true
175
+ Polyphony.backend_recv(self, buf, maxlen || 4096, -1)
176
+ new_len = buf.bytesize
177
+ break if new_len == len
178
+
179
+ len = new_len
180
+ end
181
+ buf
182
+ end
183
+
143
184
  def recv(maxlen, flags = 0, outbuf = nil)
144
185
  Polyphony.backend_recv(self, outbuf || +'', maxlen, 0)
145
186
  end
@@ -165,11 +206,10 @@ class ::TCPSocket
165
206
  # Polyphony.backend_send(self, mesg, 0)
166
207
  # end
167
208
 
168
- def readpartial(maxlen, str = +'', buffer_pos = 0)
209
+ def readpartial(maxlen, str = +'', buffer_pos = 0, raise_on_eof)
169
210
  result = Polyphony.backend_recv(self, str, maxlen, buffer_pos)
170
- raise EOFError unless result
171
-
172
- str
211
+ raise EOFError if !result && raise_on_eof
212
+ result
173
213
  end
174
214
 
175
215
  def read_nonblock(len, str = nil, exception: true)
@@ -217,6 +257,23 @@ class ::UNIXServer
217
257
  end
218
258
 
219
259
  class ::UNIXSocket
260
+ alias_method :orig_read, :read
261
+ def read(maxlen = nil, buf = nil, buf_pos = 0)
262
+ return Polyphony.backend_recv(self, buf, maxlen, buf_pos) if buf
263
+ return Polyphony.backend_recv(self, buf || +'', maxlen, 0) if maxlen
264
+
265
+ buf = +''
266
+ len = buf.bytesize
267
+ while true
268
+ Polyphony.backend_recv(self, buf, maxlen || 4096, -1)
269
+ new_len = buf.bytesize
270
+ break if new_len == len
271
+
272
+ len = new_len
273
+ end
274
+ buf
275
+ end
276
+
220
277
  def recv(maxlen, flags = 0, outbuf = nil)
221
278
  Polyphony.backend_recv(self, outbuf || +'', maxlen, 0)
222
279
  end
@@ -242,11 +299,10 @@ class ::UNIXSocket
242
299
  Polyphony.backend_send(self, mesg, 0)
243
300
  end
244
301
 
245
- def readpartial(maxlen, str = +'', buffer_pos = 0)
302
+ def readpartial(maxlen, str = +'', buffer_pos = 0, raise_on_eof)
246
303
  result = Polyphony.backend_recv(self, str, maxlen, buffer_pos)
247
- raise EOFError unless result
248
-
249
- str
304
+ raise EOFError if !result && raise_on_eof
305
+ result
250
306
  end
251
307
 
252
308
  def read_nonblock(len, str = nil, exception: true)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polyphony
4
- VERSION = '0.62'
4
+ VERSION = '0.66'
5
5
  end
data/test/helper.rb CHANGED
@@ -15,6 +15,8 @@ require 'minitest/reporters'
15
15
 
16
16
  ::Exception.__disable_sanitized_backtrace__ = true
17
17
 
18
+ IS_LINUX = RUBY_PLATFORM =~ /linux/
19
+
18
20
  # Minitest::Reporters.use! [
19
21
  # Minitest::Reporters::SpecReporter.new
20
22
  # ]
data/test/test_backend.rb CHANGED
@@ -26,7 +26,7 @@ class BackendTest < MiniTest::Test
26
26
  @backend.sleep 0.01
27
27
  count += 1
28
28
  }.await
29
- assert_in_range 0.02..0.04, Time.now - t0
29
+ assert_in_range 0.02..0.06, Time.now - t0 if IS_LINUX
30
30
  assert_equal 3, count
31
31
  end
32
32
 
@@ -98,6 +98,32 @@ class BackendTest < MiniTest::Test
98
98
  assert_equal return_value, buf
99
99
  end
100
100
 
101
+ def test_read_concat_big
102
+ i, o = IO.pipe
103
+
104
+ body = " " * 4000
105
+
106
+ data = "post /?q=time&blah=blah HTTP/1\r\nHost: dev.realiteq.net\r\n\r\n" +
107
+ "get /?q=time HTTP/1.1\r\nContent-Length: #{body.bytesize}\r\n\r\n#{body}" +
108
+ "get /?q=time HTTP/1.1\r\nCookie: foo\r\nCookie: bar\r\n\r\n"
109
+
110
+ o << data
111
+ o.close
112
+
113
+ buf = +''
114
+
115
+ @backend.read(i, buf, 4096, false, -1)
116
+ assert_equal 4096, buf.bytesize
117
+
118
+ @backend.read(i, buf, 1, false, -1)
119
+ assert_equal 4097, buf.bytesize
120
+
121
+ @backend.read(i, buf, 4096, false, -1)
122
+
123
+ assert_equal data.bytesize, buf.bytesize
124
+ assert_equal data, buf
125
+ end
126
+
101
127
  def test_waitpid
102
128
  pid = fork do
103
129
  @backend.post_fork
@@ -217,6 +243,8 @@ class BackendTest < MiniTest::Test
217
243
  end
218
244
 
219
245
  def test_timer_loop
246
+ skip unless IS_LINUX
247
+
220
248
  i = 0
221
249
  f = spin do
222
250
  @backend.timer_loop(0.01) { i += 1 }
@@ -231,6 +259,8 @@ class BackendTest < MiniTest::Test
231
259
  end
232
260
 
233
261
  def test_timeout
262
+ skip unless IS_LINUX
263
+
234
264
  buffer = []
235
265
  assert_raises(Polyphony::TimeoutException) do
236
266
  @backend.timeout(0.01, Polyphony::TimeoutException) do
@@ -262,6 +292,8 @@ class BackendTest < MiniTest::Test
262
292
  end
263
293
 
264
294
  def test_nested_timeout
295
+ skip unless IS_LINUX
296
+
265
297
  buffer = []
266
298
  assert_raises(MyTimeoutException) do
267
299
  @backend.timeout(0.01, MyTimeoutException) do
@@ -321,8 +353,8 @@ class BackendTest < MiniTest::Test
321
353
 
322
354
 
323
355
  def test_splice_chunks
324
- body = 'abcd' * 250
325
- chunk_size = 750
356
+ body = 'abcd' * 4
357
+ chunk_size = 12
326
358
 
327
359
  buf = +''
328
360
  r, w = IO.pipe
@@ -347,7 +379,7 @@ class BackendTest < MiniTest::Test
347
379
  w.close
348
380
  reader.await
349
381
 
350
- expected = "Content-Type: foo\r\n\r\n#{750.to_s(16)}\r\n#{body[0..749]}\r\n#{250.to_s(16)}\r\n#{body[750..999]}\r\n0\r\n\r\n"
382
+ expected = "Content-Type: foo\r\n\r\n#{12.to_s(16)}\r\n#{body[0..11]}\r\n#{4.to_s(16)}\r\n#{body[12..15]}\r\n0\r\n\r\n"
351
383
  assert_equal expected, buf
352
384
  ensure
353
385
  o.close
@@ -368,6 +400,9 @@ class BackendTest < MiniTest::Test
368
400
  assert_equal count, GC.count
369
401
  sleep 0.05
370
402
  assert_equal count, GC.count
403
+
404
+ return unless IS_LINUX
405
+
371
406
  # The idle tasks are ran at most once per fiber switch, before the backend
372
407
  # is polled. Therefore, the second sleep will not have triggered a GC, since
373
408
  # only 0.05s have passed since the gc period was set.
@@ -137,7 +137,7 @@ class MoveOnAfterTest < MiniTest::Test
137
137
  t1 = Time.now
138
138
 
139
139
  assert_nil v
140
- assert_in_range 0.014..0.02, t1 - t0
140
+ assert_in_range 0.014..0.02, t1 - t0 if IS_LINUX
141
141
  end
142
142
 
143
143
  def test_move_on_after_without_block
@@ -152,6 +152,8 @@ class MoveOnAfterTest < MiniTest::Test
152
152
  end
153
153
 
154
154
  def test_nested_move_on_after
155
+ skip unless IS_LINUX
156
+
155
157
  t0 = Time.now
156
158
  o = move_on_after(0.01, with_value: 1) do
157
159
  move_on_after(0.02, with_value: 2) do
@@ -210,7 +212,7 @@ class CancelAfterTest < MiniTest::Test
210
212
  sleep 0.007
211
213
  end
212
214
  t1 = Time.now
213
- assert_in_range 0.014..0.024, t1 - t0
215
+ assert_in_range 0.014..0.024, t1 - t0 if IS_LINUX
214
216
  end
215
217
 
216
218
  class CustomException < Exception
@@ -399,7 +401,7 @@ class ThrottledLoopTest < MiniTest::Test
399
401
  end
400
402
  f.await
401
403
  t1 = Time.now
402
- assert_in_range 0.075..0.15, t1 - t0
404
+ assert_in_range 0.075..0.15, t1 - t0 if IS_LINUX
403
405
  assert_equal [1, 2, 3, 4, 5], buffer
404
406
  end
405
407
  end
@@ -415,6 +417,8 @@ class GlobalAPIEtcTest < MiniTest::Test
415
417
  end
416
418
 
417
419
  def test_every
420
+ skip unless IS_LINUX
421
+
418
422
  buffer = []
419
423
  t0 = Time.now
420
424
  f = spin do
@@ -429,7 +433,7 @@ class GlobalAPIEtcTest < MiniTest::Test
429
433
  t0 = Time.now
430
434
  sleep 0.1
431
435
  elapsed = Time.now - t0
432
- assert (0.05..0.15).include? elapsed
436
+ assert (0.05..0.15).include? elapsed if IS_LINUX
433
437
 
434
438
  f = spin { sleep }
435
439
  snooze
data/test/test_io.rb CHANGED
@@ -73,6 +73,26 @@ class IOTest < MiniTest::Test
73
73
  assert_equal [:wait_readable, 'foo'], results
74
74
  end
75
75
 
76
+ def test_read
77
+ i, o = IO.pipe
78
+
79
+ o << 'hi'
80
+ assert_equal 'hi', i.read(2)
81
+
82
+ o << 'foobarbaz'
83
+ assert_equal 'foo', i.read(3)
84
+ assert_equal 'bar', i.read(3)
85
+
86
+ buf = +'abc'
87
+ assert_equal 'baz', i.read(3, buf)
88
+ assert_equal 'baz', buf
89
+
90
+ buf = +'def'
91
+ o << 'foobar'
92
+ assert_equal 'deffoobar', i.read(6, buf, -1)
93
+ assert_equal 'deffoobar', buf
94
+ end
95
+
76
96
  def test_readpartial
77
97
  i, o = IO.pipe
78
98
 
@@ -331,6 +351,8 @@ class IOClassMethodsTest < MiniTest::Test
331
351
  end
332
352
 
333
353
  def test_popen
354
+ skip unless IS_LINUX
355
+
334
356
  counter = 0
335
357
  timer = spin { throttled_loop(200) { counter += 1 } }
336
358
 
data/test/test_socket.rb CHANGED
@@ -12,7 +12,6 @@ class SocketTest < MiniTest::Test
12
12
  def test_tcp
13
13
  port = rand(1234..5678)
14
14
  server = TCPServer.new('127.0.0.1', port)
15
-
16
15
  server_fiber = spin do
17
16
  while (socket = server.accept)
18
17
  spin do
@@ -34,6 +33,45 @@ class SocketTest < MiniTest::Test
34
33
  server&.close
35
34
  end
36
35
 
36
+ def test_read
37
+ port = rand(1234..5678)
38
+ server = TCPServer.new('127.0.0.1', port)
39
+ server_fiber = spin do
40
+ while (socket = server.accept)
41
+ spin do
42
+ while (data = socket.read(8192))
43
+ socket << data
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ snooze
50
+ client = TCPSocket.new('127.0.0.1', port)
51
+
52
+ client << 'hi'
53
+ assert_equal 'hi', client.read(2)
54
+
55
+ client << 'foobarbaz'
56
+ assert_equal 'foo', client.read(3)
57
+ assert_equal 'bar', client.read(3)
58
+
59
+ buf = +'abc'
60
+ assert_equal 'baz', client.read(3, buf)
61
+ assert_equal 'baz', buf
62
+
63
+ buf = +'def'
64
+ client << 'foobar'
65
+ assert_equal 'deffoobar', client.read(6, buf, -1)
66
+ assert_equal 'deffoobar', buf
67
+
68
+ client.close
69
+ ensure
70
+ server_fiber&.stop
71
+ server_fiber&.await
72
+ server&.close
73
+ end
74
+
37
75
  # sending multiple strings at once
38
76
  def test_sendv
39
77
  port = rand(1234..5678)
@@ -120,19 +158,22 @@ class SocketTest < MiniTest::Test
120
158
  end
121
159
  end
122
160
 
123
- class HTTPClientTest < MiniTest::Test
124
- require 'json'
161
+ if IS_LINUX
162
+ class HTTPClientTest < MiniTest::Test
125
163
 
126
- def test_http
127
- res = HTTParty.get('http://ipinfo.io/')
164
+ require 'json'
128
165
 
129
- response = JSON.load(res.body)
130
- assert_equal 'https://ipinfo.io/missingauth', response['readme']
131
- end
166
+ def test_http
167
+ res = HTTParty.get('http://ipinfo.io/')
132
168
 
133
- def test_https
134
- res = HTTParty.get('https://ipinfo.io/')
135
- response = JSON.load(res.body)
136
- assert_equal 'https://ipinfo.io/missingauth', response['readme']
169
+ response = JSON.load(res.body)
170
+ assert_equal 'https://ipinfo.io/missingauth', response['readme']
171
+ end
172
+
173
+ def test_https
174
+ res = HTTParty.get('https://ipinfo.io/')
175
+ response = JSON.load(res.body)
176
+ assert_equal 'https://ipinfo.io/missingauth', response['readme']
177
+ end
137
178
  end
138
179
  end
data/test/test_thread.rb CHANGED
@@ -180,6 +180,9 @@ class ThreadTest < MiniTest::Test
180
180
  assert_equal count, GC.count
181
181
  sleep 0.05
182
182
  assert_equal count, GC.count
183
+
184
+ return unless IS_LINUX
185
+
183
186
  # The idle tasks are ran at most once per fiber switch, before the backend
184
187
  # is polled. Therefore, the second sleep will not have triggered a GC, since
185
188
  # only 0.05s have passed since the gc period was set.
data/test/test_timer.rb CHANGED
@@ -19,7 +19,7 @@ class TimerMoveOnAfterTest < MiniTest::Test
19
19
  end
20
20
  t1 = Time.now
21
21
 
22
- assert_in_range 0.1..0.15, t1 - t0
22
+ assert_in_range 0.1..0.15, t1 - t0 if IS_LINUX
23
23
  assert_nil v
24
24
  end
25
25
 
@@ -31,11 +31,13 @@ class TimerMoveOnAfterTest < MiniTest::Test
31
31
  end
32
32
  t1 = Time.now
33
33
 
34
- assert_in_range 0.01..0.05, t1 - t0
34
+ assert_in_range 0.01..0.05, t1 - t0 if IS_LINUX
35
35
  assert_equal :bar, v
36
36
  end
37
37
 
38
38
  def test_timer_move_on_after_with_reset
39
+ skip unless IS_LINUX
40
+
39
41
  t0 = Time.now
40
42
  v = @timer.move_on_after(0.01, with_value: :moved_on) do
41
43
  sleep 0.007
@@ -71,7 +73,7 @@ class TimerCancelAfterTest < MiniTest::Test
71
73
  end
72
74
  end
73
75
  t1 = Time.now
74
- assert_in_range 0.01..0.03, t1 - t0
76
+ assert_in_range 0.01..0.03, t1 - t0 if IS_LINUX
75
77
  end
76
78
 
77
79
  def test_timer_cancel_after_with_reset
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: polyphony
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.62'
4
+ version: '0.66'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-07-21 00:00:00.000000000 Z
11
+ date: 2021-08-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler