polyphony 0.80 → 0.82
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/workflows/test.yml +1 -1
- data/CHANGELOG.md +14 -0
- data/Gemfile.lock +1 -1
- data/bin/test +1 -1
- data/examples/core/raw_buffer_test.rb +8 -0
- data/examples/core/zlib_stream.rb +2 -1
- data/ext/polyphony/backend_common.c +18 -0
- data/ext/polyphony/backend_common.h +17 -0
- data/ext/polyphony/backend_io_uring.c +89 -59
- data/ext/polyphony/backend_libev.c +68 -42
- data/ext/polyphony/extconf.rb +1 -1
- data/ext/polyphony/polyphony.c +52 -0
- data/lib/polyphony/adapters/process.rb +2 -2
- data/lib/polyphony/net.rb +15 -15
- data/lib/polyphony/version.rb +1 -1
- data/test/test_io.rb +35 -0
- data/test/test_raw_buffer.rb +37 -0
- data/test/test_socket.rb +49 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8f80cdfe71dec5b03bd98ffb4150beec84fd6e35b70b6e099fb223a1c78706bc
|
4
|
+
data.tar.gz: 8a245a57849a917814d5b8dbb563315e42291c0063f5fc353578af16002209bb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0450fcbbe868c731f2e0b41bb196522f33487700eaf2636bb65d65def95af81d341057c071271aa726934008e19969a36a4e8e97e4775d9bb2660f5750708dc3
|
7
|
+
data.tar.gz: b789f4ad289136b91a24c3f68ddfc4864dbc2ede4989d7dafec09393527f6f93e44362843a406599a8d38f6f6f8e99626cffb88eb7395fdc99c1cbeafead87dc
|
data/.github/workflows/test.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
## 0.82 2022-03-04
|
2
|
+
|
3
|
+
- Use `POLYPHONY_LIBEV` instead of `POLYPHONY_USE_LIBEV` environment variable
|
4
|
+
- Add support for working with raw buffers (#78)
|
5
|
+
|
6
|
+
## 0.81.1 2022-03-03
|
7
|
+
|
8
|
+
- Fix `Backend_recv` regression
|
9
|
+
|
10
|
+
## 0.81 2022-03-03
|
11
|
+
|
12
|
+
- Restore public visibility for `Polyphony::Process.kill_process`
|
13
|
+
- Restore public visibility for `Polyphony::Net.setup_alpn`
|
14
|
+
|
1
15
|
## 0.80 2022-02-28
|
2
16
|
|
3
17
|
- Prevent reentry into `trace_proc`
|
data/Gemfile.lock
CHANGED
data/bin/test
CHANGED
@@ -470,3 +470,21 @@ int backend_getaddrinfo(VALUE host, VALUE port, struct sockaddr **ai_addr) {
|
|
470
470
|
*ai_addr = addrinfo_result->ai_addr;
|
471
471
|
return addrinfo_result->ai_addrlen;
|
472
472
|
}
|
473
|
+
|
474
|
+
struct io_buffer get_io_buffer(VALUE in) {
|
475
|
+
if (FIXNUM_P(in)) {
|
476
|
+
struct raw_buffer *raw = FIX2PTR(in);
|
477
|
+
return (struct io_buffer){ raw->ptr, raw->len, 1 };
|
478
|
+
}
|
479
|
+
return (struct io_buffer){ RSTRING_PTR(in), RSTRING_LEN(in), 0 };
|
480
|
+
}
|
481
|
+
|
482
|
+
VALUE coerce_io_string_or_buffer(VALUE buf) {
|
483
|
+
switch (TYPE(buf)) {
|
484
|
+
case T_STRING:
|
485
|
+
case T_FIXNUM:
|
486
|
+
return buf;
|
487
|
+
default:
|
488
|
+
return StringValue(buf);
|
489
|
+
}
|
490
|
+
}
|
@@ -55,7 +55,24 @@ struct backend_stats backend_base_stats(struct Backend_base *base);
|
|
55
55
|
}
|
56
56
|
#define COND_TRACE(base, ...) if (SHOULD_TRACE(base)) { TRACE(base, __VA_ARGS__); }
|
57
57
|
|
58
|
+
// raw buffers
|
58
59
|
|
60
|
+
struct raw_buffer {
|
61
|
+
char *ptr;
|
62
|
+
int len;
|
63
|
+
};
|
64
|
+
|
65
|
+
struct io_buffer {
|
66
|
+
char *ptr;
|
67
|
+
int len;
|
68
|
+
int raw;
|
69
|
+
};
|
70
|
+
|
71
|
+
#define FIX2PTR(v) ((void *)(FIX2LONG(v)))
|
72
|
+
#define PTR2FIX(p) LONG2FIX((long)p)
|
73
|
+
|
74
|
+
struct io_buffer get_io_buffer(VALUE in);
|
75
|
+
VALUE coerce_io_string_or_buffer(VALUE buf);
|
59
76
|
|
60
77
|
#ifdef POLYPHONY_USE_PIDFD_OPEN
|
61
78
|
int pidfd_open(pid_t pid, unsigned int flags);
|
@@ -332,23 +332,37 @@ VALUE io_uring_backend_wait_fd(Backend_t *backend, int fd, int write) {
|
|
332
332
|
VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof, VALUE pos) {
|
333
333
|
Backend_t *backend;
|
334
334
|
rb_io_t *fptr;
|
335
|
-
|
336
|
-
long buffer_size = dynamic_len ? 4096 : NUM2INT(length);
|
335
|
+
struct io_buffer buffer = get_io_buffer(str);
|
337
336
|
long buf_pos = NUM2INT(pos);
|
338
|
-
int
|
339
|
-
|
337
|
+
int shrinkable_string = 0;
|
338
|
+
int expandable_buffer = 0;
|
340
339
|
long total = 0;
|
341
340
|
int read_to_eof = RTEST(to_eof);
|
342
341
|
VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
|
343
342
|
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
343
|
+
if (buffer.raw) {
|
344
|
+
if (buf_pos < 0 || buf_pos > buffer.len) buf_pos = buffer.len;
|
345
|
+
buffer.ptr += buf_pos;
|
346
|
+
buffer.len -= buf_pos;
|
347
|
+
}
|
348
|
+
else {
|
349
|
+
expandable_buffer = length == Qnil;
|
350
|
+
long expected_read_length = expandable_buffer ? 4096 : FIX2INT(length);
|
351
|
+
long string_cap = rb_str_capacity(str);
|
352
|
+
if (buf_pos < 0 || buf_pos > buffer.len) buf_pos = buffer.len;
|
353
|
+
|
354
|
+
if (string_cap < expected_read_length + buf_pos) {
|
355
|
+
shrinkable_string = io_setstrbuf(&str, expected_read_length + buf_pos);
|
356
|
+
buffer.ptr = RSTRING_PTR(str) + buf_pos;
|
357
|
+
buffer.len = expected_read_length;
|
358
|
+
}
|
359
|
+
else {
|
360
|
+
buffer.ptr += buf_pos;
|
361
|
+
buffer.len = string_cap - buf_pos;
|
362
|
+
if (buffer.len > expected_read_length)
|
363
|
+
buffer.len = expected_read_length;
|
364
|
+
}
|
348
365
|
}
|
349
|
-
else buf_pos = 0;
|
350
|
-
shrinkable = io_setstrbuf(&str, buf_pos + buffer_size);
|
351
|
-
buf = RSTRING_PTR(str) + buf_pos;
|
352
366
|
|
353
367
|
GetBackend(self, backend);
|
354
368
|
if (underlying_io != Qnil) io = underlying_io;
|
@@ -364,7 +378,7 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof,
|
|
364
378
|
int result;
|
365
379
|
int completed;
|
366
380
|
|
367
|
-
io_uring_prep_read(sqe, fptr->fd,
|
381
|
+
io_uring_prep_read(sqe, fptr->fd, buffer.ptr, buffer.len, -1);
|
368
382
|
|
369
383
|
result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
370
384
|
completed = context_store_release(&backend->store, ctx);
|
@@ -383,26 +397,31 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof,
|
|
383
397
|
total += result;
|
384
398
|
if (!read_to_eof) break;
|
385
399
|
|
386
|
-
if (
|
387
|
-
if (!
|
400
|
+
if (result == buffer.len) {
|
401
|
+
if (!expandable_buffer) break;
|
388
402
|
|
389
|
-
// resize buffer
|
390
|
-
rb_str_resize(str,
|
391
|
-
rb_str_modify_expand(str,
|
392
|
-
|
393
|
-
|
394
|
-
|
403
|
+
// resize buffer to double its capacity
|
404
|
+
rb_str_resize(str, total + buf_pos);
|
405
|
+
rb_str_modify_expand(str, rb_str_capacity(str));
|
406
|
+
shrinkable_string = 0;
|
407
|
+
buffer.ptr = RSTRING_PTR(str) + total + buf_pos;
|
408
|
+
buffer.len = rb_str_capacity(str) - total - buf_pos;
|
409
|
+
}
|
410
|
+
else {
|
411
|
+
buffer.ptr += result;
|
412
|
+
buffer.len -= result;
|
413
|
+
if (!buffer.len) break;
|
395
414
|
}
|
396
|
-
else buf += result;
|
397
415
|
}
|
398
416
|
}
|
399
417
|
|
400
|
-
|
401
|
-
|
402
|
-
|
418
|
+
if (!buffer.raw) {
|
419
|
+
io_set_read_length(str, buf_pos + total, shrinkable_string);
|
420
|
+
io_enc_str(str, fptr);
|
421
|
+
}
|
403
422
|
if (!total) return Qnil;
|
404
423
|
|
405
|
-
return str;
|
424
|
+
return buffer.raw ? INT2FIX(total) : str;
|
406
425
|
}
|
407
426
|
|
408
427
|
VALUE Backend_read_loop(VALUE self, VALUE io, VALUE maxlen) {
|
@@ -514,9 +533,9 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
|
514
533
|
Backend_t *backend;
|
515
534
|
rb_io_t *fptr;
|
516
535
|
VALUE underlying_io;
|
517
|
-
|
518
|
-
|
519
|
-
long left = len;
|
536
|
+
|
537
|
+
struct io_buffer buffer = get_io_buffer(str);
|
538
|
+
long left = buffer.len;
|
520
539
|
|
521
540
|
underlying_io = rb_ivar_get(io, ID_ivar_io);
|
522
541
|
if (underlying_io != Qnil) io = underlying_io;
|
@@ -532,7 +551,7 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
|
532
551
|
int result;
|
533
552
|
int completed;
|
534
553
|
|
535
|
-
io_uring_prep_write(sqe, fptr->fd,
|
554
|
+
io_uring_prep_write(sqe, fptr->fd, buffer.ptr, left, 0);
|
536
555
|
|
537
556
|
result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
538
557
|
completed = context_store_release(&backend->store, ctx);
|
@@ -546,12 +565,12 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
|
546
565
|
if (result < 0)
|
547
566
|
rb_syserr_fail(-result, strerror(-result));
|
548
567
|
else {
|
549
|
-
|
568
|
+
buffer.ptr += result;
|
550
569
|
left -= result;
|
551
570
|
}
|
552
571
|
}
|
553
572
|
|
554
|
-
return INT2NUM(len);
|
573
|
+
return INT2NUM(buffer.len);
|
555
574
|
}
|
556
575
|
|
557
576
|
VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
@@ -638,21 +657,36 @@ VALUE Backend_write_m(int argc, VALUE *argv, VALUE self) {
|
|
638
657
|
VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length, VALUE pos) {
|
639
658
|
Backend_t *backend;
|
640
659
|
rb_io_t *fptr;
|
641
|
-
|
642
|
-
long len = dynamic_len ? 4096 : NUM2INT(length);
|
660
|
+
struct io_buffer buffer = get_io_buffer(str);
|
643
661
|
long buf_pos = NUM2INT(pos);
|
644
|
-
int
|
645
|
-
|
662
|
+
int shrinkable_string = 0;
|
663
|
+
int expandable_buffer = 0;
|
646
664
|
long total = 0;
|
647
|
-
VALUE underlying_io = rb_ivar_get(io, ID_ivar_io)
|
665
|
+
VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
|
648
666
|
|
649
|
-
if (
|
650
|
-
|
651
|
-
|
667
|
+
if (buffer.raw) {
|
668
|
+
if (buf_pos < 0 || buf_pos > buffer.len) buf_pos = buffer.len;
|
669
|
+
buffer.ptr += buf_pos;
|
670
|
+
buffer.len -= buf_pos;
|
671
|
+
}
|
672
|
+
else {
|
673
|
+
expandable_buffer = length == Qnil;
|
674
|
+
long expected_read_length = expandable_buffer ? 4096 : FIX2INT(length);
|
675
|
+
long string_cap = rb_str_capacity(str);
|
676
|
+
if (buf_pos < 0 || buf_pos > buffer.len) buf_pos = buffer.len;
|
677
|
+
|
678
|
+
if (string_cap < expected_read_length + buf_pos) {
|
679
|
+
shrinkable_string = io_setstrbuf(&str, expected_read_length + buf_pos);
|
680
|
+
buffer.ptr = RSTRING_PTR(str) + buf_pos;
|
681
|
+
buffer.len = expected_read_length;
|
682
|
+
}
|
683
|
+
else {
|
684
|
+
buffer.ptr += buf_pos;
|
685
|
+
buffer.len = string_cap - buf_pos;
|
686
|
+
if (buffer.len > expected_read_length)
|
687
|
+
buffer.len = expected_read_length;
|
688
|
+
}
|
652
689
|
}
|
653
|
-
else buf_pos = 0;
|
654
|
-
shrinkable = io_setstrbuf(&str, buf_pos + len);
|
655
|
-
buf = RSTRING_PTR(str) + buf_pos;
|
656
690
|
|
657
691
|
GetBackend(self, backend);
|
658
692
|
if (underlying_io != Qnil) io = underlying_io;
|
@@ -668,7 +702,7 @@ VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length, VALUE pos) {
|
|
668
702
|
int result;
|
669
703
|
int completed;
|
670
704
|
|
671
|
-
io_uring_prep_recv(sqe, fptr->fd,
|
705
|
+
io_uring_prep_recv(sqe, fptr->fd, buffer.ptr, buffer.len, 0);
|
672
706
|
|
673
707
|
result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
674
708
|
completed = context_store_release(&backend->store, ctx);
|
@@ -687,12 +721,13 @@ VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length, VALUE pos) {
|
|
687
721
|
}
|
688
722
|
}
|
689
723
|
|
690
|
-
|
691
|
-
|
692
|
-
|
724
|
+
if (!buffer.raw) {
|
725
|
+
io_set_read_length(str, buf_pos + total, shrinkable_string);
|
726
|
+
io_enc_str(str, fptr);
|
727
|
+
}
|
693
728
|
if (!total) return Qnil;
|
694
729
|
|
695
|
-
return str;
|
730
|
+
return buffer.raw ? INT2FIX(total) : str;
|
696
731
|
}
|
697
732
|
|
698
733
|
VALUE Backend_recv_loop(VALUE self, VALUE io, VALUE maxlen) {
|
@@ -802,10 +837,10 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
|
|
802
837
|
Backend_t *backend;
|
803
838
|
rb_io_t *fptr;
|
804
839
|
VALUE underlying_io;
|
805
|
-
|
806
|
-
|
807
|
-
long left;
|
808
|
-
int flags_int;
|
840
|
+
|
841
|
+
struct io_buffer buffer = get_io_buffer(str);
|
842
|
+
long left = buffer.len;
|
843
|
+
int flags_int = NUM2INT(flags);
|
809
844
|
|
810
845
|
underlying_io = rb_ivar_get(io, ID_ivar_io);
|
811
846
|
if (underlying_io != Qnil) io = underlying_io;
|
@@ -814,11 +849,6 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
|
|
814
849
|
GetOpenFile(io, fptr);
|
815
850
|
io_unset_nonblock(fptr, io);
|
816
851
|
|
817
|
-
buf = StringValuePtr(str);
|
818
|
-
len = RSTRING_LEN(str);
|
819
|
-
left = len;
|
820
|
-
flags_int = NUM2INT(flags);
|
821
|
-
|
822
852
|
while (left > 0) {
|
823
853
|
VALUE resume_value = Qnil;
|
824
854
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_SEND);
|
@@ -826,7 +856,7 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
|
|
826
856
|
int result;
|
827
857
|
int completed;
|
828
858
|
|
829
|
-
io_uring_prep_send(sqe, fptr->fd,
|
859
|
+
io_uring_prep_send(sqe, fptr->fd, buffer.ptr, left, flags_int);
|
830
860
|
|
831
861
|
result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
832
862
|
completed = context_store_release(&backend->store, ctx);
|
@@ -840,12 +870,12 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
|
|
840
870
|
if (result < 0)
|
841
871
|
rb_syserr_fail(-result, strerror(-result));
|
842
872
|
else {
|
843
|
-
|
873
|
+
buffer.ptr += result;
|
844
874
|
left -= result;
|
845
875
|
}
|
846
876
|
}
|
847
877
|
|
848
|
-
return INT2NUM(len);
|
878
|
+
return INT2NUM(buffer.len);
|
849
879
|
}
|
850
880
|
|
851
881
|
VALUE io_uring_backend_accept(Backend_t *backend, VALUE server_socket, VALUE socket_class, int loop) {
|
@@ -270,21 +270,40 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof,
|
|
270
270
|
Backend_t *backend;
|
271
271
|
struct libev_io watcher;
|
272
272
|
rb_io_t *fptr;
|
273
|
-
|
274
|
-
|
273
|
+
|
274
|
+
struct io_buffer buffer = get_io_buffer(str);
|
275
275
|
long buf_pos = NUM2INT(pos);
|
276
|
-
|
277
|
-
|
278
|
-
if (buf_pos < 0 || buf_pos > current_len) buf_pos = current_len;
|
279
|
-
}
|
280
|
-
else buf_pos = 0;
|
281
|
-
int shrinkable = io_setstrbuf(&str, buf_pos + len);
|
282
|
-
char *buf = RSTRING_PTR(str) + buf_pos;
|
276
|
+
int shrinkable_string = 0;
|
277
|
+
int expandable_buffer = 0;
|
283
278
|
long total = 0;
|
284
279
|
VALUE switchpoint_result = Qnil;
|
285
280
|
int read_to_eof = RTEST(to_eof);
|
286
281
|
VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
|
287
282
|
|
283
|
+
if (buffer.raw) {
|
284
|
+
if (buf_pos < 0 || buf_pos > buffer.len) buf_pos = buffer.len;
|
285
|
+
buffer.ptr += buf_pos;
|
286
|
+
buffer.len -= buf_pos;
|
287
|
+
}
|
288
|
+
else {
|
289
|
+
expandable_buffer = length == Qnil;
|
290
|
+
long expected_read_length = expandable_buffer ? 4096 : FIX2INT(length);
|
291
|
+
long string_cap = rb_str_capacity(str);
|
292
|
+
if (buf_pos < 0 || buf_pos > buffer.len) buf_pos = buffer.len;
|
293
|
+
|
294
|
+
if (string_cap < expected_read_length + buf_pos) {
|
295
|
+
shrinkable_string = io_setstrbuf(&str, expected_read_length + buf_pos);
|
296
|
+
buffer.ptr = RSTRING_PTR(str) + buf_pos;
|
297
|
+
buffer.len = expected_read_length;
|
298
|
+
}
|
299
|
+
else {
|
300
|
+
buffer.ptr += buf_pos;
|
301
|
+
buffer.len = string_cap - buf_pos;
|
302
|
+
if (buffer.len > expected_read_length)
|
303
|
+
buffer.len = expected_read_length;
|
304
|
+
}
|
305
|
+
}
|
306
|
+
|
288
307
|
GetBackend(self, backend);
|
289
308
|
if (underlying_io != Qnil) io = underlying_io;
|
290
309
|
GetOpenFile(io, fptr);
|
@@ -295,8 +314,8 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof,
|
|
295
314
|
|
296
315
|
while (1) {
|
297
316
|
backend->base.op_count++;
|
298
|
-
ssize_t
|
299
|
-
if (
|
317
|
+
ssize_t result = read(fptr->fd, buffer.ptr, buffer.len);
|
318
|
+
if (result < 0) {
|
300
319
|
int e = errno;
|
301
320
|
if (e != EWOULDBLOCK && e != EAGAIN) rb_syserr_fail(e, strerror(e));
|
302
321
|
|
@@ -308,32 +327,39 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof,
|
|
308
327
|
switchpoint_result = backend_snooze(&backend->base);
|
309
328
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
310
329
|
|
311
|
-
if (
|
312
|
-
|
330
|
+
if (!result) break; // EOF
|
331
|
+
|
332
|
+
total += result;
|
313
333
|
if (!read_to_eof) break;
|
314
334
|
|
315
|
-
if (
|
316
|
-
if (!
|
335
|
+
if (result == buffer.len) {
|
336
|
+
if (!expandable_buffer) break;
|
317
337
|
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
338
|
+
// resize buffer to double its capacity
|
339
|
+
rb_str_resize(str, total + buf_pos);
|
340
|
+
rb_str_modify_expand(str, rb_str_capacity(str));
|
341
|
+
shrinkable_string = 0;
|
342
|
+
buffer.ptr = RSTRING_PTR(str) + total + buf_pos;
|
343
|
+
buffer.len = rb_str_capacity(str) - total - buf_pos;
|
344
|
+
}
|
345
|
+
else {
|
346
|
+
buffer.ptr += result;
|
347
|
+
buffer.len -= result;
|
348
|
+
if (!buffer.len) break;
|
323
349
|
}
|
324
|
-
else buf += n;
|
325
350
|
}
|
326
351
|
}
|
327
352
|
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
353
|
+
if (!buffer.raw) {
|
354
|
+
io_set_read_length(str, buf_pos + total, shrinkable_string);
|
355
|
+
io_enc_str(str, fptr);
|
356
|
+
}
|
357
|
+
if (!total) return Qnil;
|
332
358
|
|
333
359
|
RB_GC_GUARD(watcher.fiber);
|
334
360
|
RB_GC_GUARD(switchpoint_result);
|
335
361
|
|
336
|
-
return str;
|
362
|
+
return buffer.raw ? INT2FIX(total) : str;
|
337
363
|
error:
|
338
364
|
return RAISE_EXCEPTION(switchpoint_result);
|
339
365
|
}
|
@@ -453,9 +479,9 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
|
453
479
|
rb_io_t *fptr;
|
454
480
|
VALUE switchpoint_result = Qnil;
|
455
481
|
VALUE underlying_io;
|
456
|
-
|
457
|
-
|
458
|
-
long left = len;
|
482
|
+
|
483
|
+
struct io_buffer buffer = get_io_buffer(str);
|
484
|
+
long left = buffer.len;
|
459
485
|
|
460
486
|
underlying_io = rb_ivar_get(io, ID_ivar_io);
|
461
487
|
if (underlying_io != Qnil) io = underlying_io;
|
@@ -467,8 +493,8 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
|
467
493
|
|
468
494
|
while (left > 0) {
|
469
495
|
backend->base.op_count++;
|
470
|
-
ssize_t
|
471
|
-
if (
|
496
|
+
ssize_t result = write(fptr->fd, buffer.ptr, left);
|
497
|
+
if (result < 0) {
|
472
498
|
int e = errno;
|
473
499
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
474
500
|
|
@@ -477,8 +503,8 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
|
477
503
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
478
504
|
}
|
479
505
|
else {
|
480
|
-
|
481
|
-
left -=
|
506
|
+
buffer.ptr += result;
|
507
|
+
left -= result;
|
482
508
|
}
|
483
509
|
}
|
484
510
|
|
@@ -491,7 +517,7 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
|
491
517
|
RB_GC_GUARD(watcher.fiber);
|
492
518
|
RB_GC_GUARD(switchpoint_result);
|
493
519
|
|
494
|
-
return INT2NUM(len);
|
520
|
+
return INT2NUM(buffer.len);
|
495
521
|
error:
|
496
522
|
return RAISE_EXCEPTION(switchpoint_result);
|
497
523
|
}
|
@@ -743,9 +769,9 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
|
|
743
769
|
rb_io_t *fptr;
|
744
770
|
VALUE switchpoint_result = Qnil;
|
745
771
|
VALUE underlying_io;
|
746
|
-
|
747
|
-
|
748
|
-
long left = len;
|
772
|
+
|
773
|
+
struct io_buffer buffer = get_io_buffer(str);
|
774
|
+
long left = buffer.len;
|
749
775
|
int flags_int = NUM2INT(flags);
|
750
776
|
|
751
777
|
underlying_io = rb_ivar_get(io, ID_ivar_io);
|
@@ -758,8 +784,8 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
|
|
758
784
|
|
759
785
|
while (left > 0) {
|
760
786
|
backend->base.op_count++;
|
761
|
-
ssize_t
|
762
|
-
if (
|
787
|
+
ssize_t result = send(fptr->fd, buffer.ptr, left, flags_int);
|
788
|
+
if (result < 0) {
|
763
789
|
int e = errno;
|
764
790
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
765
791
|
|
@@ -768,8 +794,8 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
|
|
768
794
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
769
795
|
}
|
770
796
|
else {
|
771
|
-
|
772
|
-
left -=
|
797
|
+
buffer.ptr += result;
|
798
|
+
left -= result;
|
773
799
|
}
|
774
800
|
}
|
775
801
|
|
@@ -782,7 +808,7 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
|
|
782
808
|
RB_GC_GUARD(watcher.fiber);
|
783
809
|
RB_GC_GUARD(switchpoint_result);
|
784
810
|
|
785
|
-
return INT2NUM(len);
|
811
|
+
return INT2NUM(buffer.len);
|
786
812
|
error:
|
787
813
|
return RAISE_EXCEPTION(switchpoint_result);
|
788
814
|
}
|
data/ext/polyphony/extconf.rb
CHANGED
@@ -16,7 +16,7 @@ def get_config
|
|
16
16
|
version, major_revision, distribution = m[1].to_i, m[2].to_i, m[3]
|
17
17
|
config[:pidfd_open] = (version == 5) && (major_revision >= 3)
|
18
18
|
|
19
|
-
force_libev = ENV['
|
19
|
+
force_libev = ENV['POLYPHONY_LIBEV'] != nil
|
20
20
|
config[:io_uring] = !force_libev &&
|
21
21
|
(version == 5) && (major_revision >= 6) && (distribution != 'linuxkit')
|
22
22
|
config
|
data/ext/polyphony/polyphony.c
CHANGED
@@ -118,6 +118,52 @@ VALUE Polyphony_backend_write(int argc, VALUE *argv, VALUE self) {
|
|
118
118
|
return Backend_write_m(argc, argv, BACKEND());
|
119
119
|
}
|
120
120
|
|
121
|
+
VALUE Polyphony_with_raw_buffer(VALUE self, VALUE size) {
|
122
|
+
struct raw_buffer buffer;
|
123
|
+
buffer.len = NUM2INT(size);
|
124
|
+
buffer.ptr = malloc(buffer.len);
|
125
|
+
if (!buffer.ptr)
|
126
|
+
rb_raise(rb_eRuntimeError, "Failed to allocate buffer");
|
127
|
+
|
128
|
+
VALUE return_value = rb_yield(PTR2FIX(&buffer));
|
129
|
+
free(buffer.ptr);
|
130
|
+
return return_value;
|
131
|
+
}
|
132
|
+
|
133
|
+
VALUE Polyphony_raw_buffer_get(int argc, VALUE *argv, VALUE self) {
|
134
|
+
VALUE buf = Qnil;
|
135
|
+
VALUE len = Qnil;
|
136
|
+
rb_scan_args(argc, argv, "11", &buf, &len);
|
137
|
+
|
138
|
+
struct raw_buffer *buffer = FIX2PTR(buf);
|
139
|
+
int length = (len == Qnil) ? buffer->len : FIX2INT(len);
|
140
|
+
|
141
|
+
if (length > buffer->len) length = buffer->len;
|
142
|
+
return rb_utf8_str_new(buffer->ptr, length);
|
143
|
+
}
|
144
|
+
|
145
|
+
VALUE Polyphony_raw_buffer_set(VALUE self, VALUE buf, VALUE str) {
|
146
|
+
struct raw_buffer *buffer = FIX2PTR(buf);
|
147
|
+
int len = RSTRING_LEN(str);
|
148
|
+
if (len > buffer->len)
|
149
|
+
rb_raise(rb_eRuntimeError, "Given string does not fit in given buffer");
|
150
|
+
|
151
|
+
memcpy(buffer->ptr, RSTRING_PTR(str), len);
|
152
|
+
buffer->len = len;
|
153
|
+
return self;
|
154
|
+
}
|
155
|
+
|
156
|
+
VALUE Polyphony_raw_buffer_size(VALUE self, VALUE buf) {
|
157
|
+
struct raw_buffer *buffer = FIX2PTR(buf);
|
158
|
+
return INT2FIX(buffer->len);
|
159
|
+
}
|
160
|
+
|
161
|
+
VALUE Polyphony_backend_test(VALUE self, VALUE io, VALUE str) {
|
162
|
+
struct raw_buffer buffer = { RSTRING_PTR(str), RSTRING_LEN(str) };
|
163
|
+
VALUE args[2] = { io, PTR2FIX(&buffer) };
|
164
|
+
return Polyphony_backend_write(2, args, self);
|
165
|
+
}
|
166
|
+
|
121
167
|
// VALUE Polyphony_backend_close(VALUE self, VALUE io) {
|
122
168
|
// return Backend_close(BACKEND(), io);
|
123
169
|
// }
|
@@ -149,6 +195,12 @@ void Init_Polyphony() {
|
|
149
195
|
// rb_define_singleton_method(mPolyphony, "backend_close", Polyphony_backend_close, 1);
|
150
196
|
rb_define_singleton_method(mPolyphony, "backend_verify_blocking_mode", Backend_verify_blocking_mode, 2);
|
151
197
|
|
198
|
+
rb_define_singleton_method(mPolyphony, "__with_raw_buffer__", Polyphony_with_raw_buffer, 1);
|
199
|
+
rb_define_singleton_method(mPolyphony, "__raw_buffer_get__", Polyphony_raw_buffer_get, -1);
|
200
|
+
rb_define_singleton_method(mPolyphony, "__raw_buffer_set__", Polyphony_raw_buffer_set, 2);
|
201
|
+
rb_define_singleton_method(mPolyphony, "__raw_buffer_size__", Polyphony_raw_buffer_size, 1);
|
202
|
+
rb_define_singleton_method(mPolyphony, "backend_test", Polyphony_backend_test, 2);
|
203
|
+
|
152
204
|
rb_define_global_function("snooze", Polyphony_snooze, 0);
|
153
205
|
rb_define_global_function("suspend", Polyphony_suspend, 0);
|
154
206
|
|
@@ -24,8 +24,6 @@ module Polyphony
|
|
24
24
|
kill_process(pid) unless terminated || pid.nil?
|
25
25
|
end
|
26
26
|
|
27
|
-
private
|
28
|
-
|
29
27
|
def kill_process(pid)
|
30
28
|
cancel_after(5) do
|
31
29
|
kill_and_await('TERM', pid)
|
@@ -34,6 +32,8 @@ module Polyphony
|
|
34
32
|
kill_and_await(-9, pid)
|
35
33
|
end
|
36
34
|
|
35
|
+
private
|
36
|
+
|
37
37
|
def kill_and_await(sig, pid)
|
38
38
|
::Process.kill(sig, pid)
|
39
39
|
Polyphony.backend_waitpid(pid)
|
data/lib/polyphony/net.rb
CHANGED
@@ -53,6 +53,21 @@ module Polyphony
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
|
+
# Sets up ALPN negotiation for the given context. The ALPN handler for the
|
57
|
+
# context will select the first protocol from the list given by the client
|
58
|
+
# that appears in the list of given protocols, according to the specified
|
59
|
+
# order.
|
60
|
+
#
|
61
|
+
# @param context [SSLContext] SSL context
|
62
|
+
# @param protocols [Array] array of supported protocols
|
63
|
+
# @return [void]
|
64
|
+
def setup_alpn(context, protocols)
|
65
|
+
context.alpn_protocols = protocols
|
66
|
+
context.alpn_select_cb = lambda do |peer_protocols|
|
67
|
+
(protocols & peer_protocols).first
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
56
71
|
private
|
57
72
|
|
58
73
|
# Creates a listening `Socket` instance.
|
@@ -114,21 +129,6 @@ module Polyphony
|
|
114
129
|
setup_alpn(context, opts[:alpn_protocols]) if opts[:alpn_protocols]
|
115
130
|
OpenSSL::SSL::SSLServer.new(socket, context)
|
116
131
|
end
|
117
|
-
|
118
|
-
# Sets up ALPN negotiation for the given context. The ALPN handler for the
|
119
|
-
# context will select the first protocol from the list given by the client
|
120
|
-
# that appears in the list of given protocols, according to the specified
|
121
|
-
# order.
|
122
|
-
#
|
123
|
-
# @param context [SSLContext] SSL context
|
124
|
-
# @param protocols [Array] array of supported protocols
|
125
|
-
# @return [void]
|
126
|
-
def setup_alpn(context, protocols)
|
127
|
-
context.alpn_protocols = protocols
|
128
|
-
context.alpn_select_cb = lambda do |peer_protocols|
|
129
|
-
(protocols & peer_protocols).first
|
130
|
-
end
|
131
|
-
end
|
132
132
|
end
|
133
133
|
end
|
134
134
|
end
|
data/lib/polyphony/version.rb
CHANGED
data/test/test_io.rb
CHANGED
@@ -281,6 +281,41 @@ class IOTest < MiniTest::Test
|
|
281
281
|
end
|
282
282
|
end
|
283
283
|
|
284
|
+
class IOWithRawBufferTest < MiniTest::Test
|
285
|
+
def setup
|
286
|
+
super
|
287
|
+
@i, @o = IO.pipe
|
288
|
+
end
|
289
|
+
|
290
|
+
def test_write_with_raw_buffer
|
291
|
+
Polyphony.__with_raw_buffer__(64) do |b|
|
292
|
+
Polyphony.__raw_buffer_set__(b, 'foobar')
|
293
|
+
@o << b
|
294
|
+
@o.close
|
295
|
+
end
|
296
|
+
|
297
|
+
str = @i.read
|
298
|
+
assert_equal 'foobar', str
|
299
|
+
end
|
300
|
+
|
301
|
+
def test_read_with_raw_buffer
|
302
|
+
@o << '*' * 65
|
303
|
+
@o.close
|
304
|
+
chunks = []
|
305
|
+
Polyphony.__with_raw_buffer__(64) do |b|
|
306
|
+
res = @i.read(64, b)
|
307
|
+
assert_equal 64, res
|
308
|
+
chunks << Polyphony.__raw_buffer_get__(b, res)
|
309
|
+
|
310
|
+
res = @i.read(64, b)
|
311
|
+
assert_equal 1, res
|
312
|
+
assert_equal 64, Polyphony.__raw_buffer_size__(b)
|
313
|
+
chunks << Polyphony.__raw_buffer_get__(b, res)
|
314
|
+
end
|
315
|
+
assert_equal ['*' * 64, '*'], chunks
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
284
319
|
class IOClassMethodsTest < MiniTest::Test
|
285
320
|
def test_binread
|
286
321
|
s = IO.binread(__FILE__)
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'helper'
|
4
|
+
require 'msgpack'
|
5
|
+
|
6
|
+
class RawBufferTest < MiniTest::Test
|
7
|
+
def test_with_raw_buffer
|
8
|
+
result = Polyphony.__with_raw_buffer__(64) do |b|
|
9
|
+
assert_kind_of Integer, b
|
10
|
+
assert_equal 64, Polyphony.__raw_buffer_size__(b)
|
11
|
+
:foo
|
12
|
+
end
|
13
|
+
assert_equal :foo, result
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_raw_buffer_get_set
|
17
|
+
Polyphony.__with_raw_buffer__(64) do |b|
|
18
|
+
# should raise if buffer not big enough
|
19
|
+
assert_raises { Polyphony.__raw_buffer_set__(b, '*' * 65) }
|
20
|
+
|
21
|
+
Polyphony.__raw_buffer_set__(b, 'foobar')
|
22
|
+
assert_equal 6, Polyphony.__raw_buffer_size__(b)
|
23
|
+
|
24
|
+
str = Polyphony.__raw_buffer_get__(b)
|
25
|
+
assert_equal 'foobar', str
|
26
|
+
|
27
|
+
str = Polyphony.__raw_buffer_get__(b, 3)
|
28
|
+
assert_equal 'foo', str
|
29
|
+
|
30
|
+
Polyphony.__raw_buffer_set__(b, '')
|
31
|
+
assert_equal 0, Polyphony.__raw_buffer_size__(b)
|
32
|
+
|
33
|
+
str = Polyphony.__raw_buffer_get__(b)
|
34
|
+
assert_equal '', str
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/test/test_socket.rb
CHANGED
@@ -193,6 +193,55 @@ class SocketTest < MiniTest::Test
|
|
193
193
|
end
|
194
194
|
end
|
195
195
|
|
196
|
+
class SocketWithRawBufferTest < MiniTest::Test
|
197
|
+
def start_tcp_server_on_random_port(host = '127.0.0.1')
|
198
|
+
port = rand(1100..60000)
|
199
|
+
server = TCPServer.new(host, port)
|
200
|
+
[port, server]
|
201
|
+
rescue Errno::EADDRINUSE
|
202
|
+
retry
|
203
|
+
end
|
204
|
+
|
205
|
+
def setup
|
206
|
+
super
|
207
|
+
|
208
|
+
port, server = start_tcp_server_on_random_port
|
209
|
+
connector = spin { @o = TCPSocket.new('127.0.0.1', port) }
|
210
|
+
@i = server.accept
|
211
|
+
end
|
212
|
+
|
213
|
+
def test_send_with_raw_buffer
|
214
|
+
Polyphony.__with_raw_buffer__(64) do |b|
|
215
|
+
Polyphony.__raw_buffer_set__(b, 'foobar')
|
216
|
+
@o << b
|
217
|
+
@o.close
|
218
|
+
end
|
219
|
+
|
220
|
+
str = @i.read
|
221
|
+
assert_equal 'foobar', str
|
222
|
+
end
|
223
|
+
|
224
|
+
def test_recv_with_raw_buffer
|
225
|
+
@o << '*' * 65
|
226
|
+
@o.close
|
227
|
+
chunks = []
|
228
|
+
Polyphony.__with_raw_buffer__(64) do |b|
|
229
|
+
res = @i.recv(64, 0, b)
|
230
|
+
assert_equal 64, res
|
231
|
+
chunks << Polyphony.__raw_buffer_get__(b, res)
|
232
|
+
|
233
|
+
res = @i.recv(64, 0, b)
|
234
|
+
assert_equal 1, res
|
235
|
+
assert_equal 64, Polyphony.__raw_buffer_size__(b)
|
236
|
+
chunks << Polyphony.__raw_buffer_get__(b, res)
|
237
|
+
|
238
|
+
res = @i.recv(64, 0, b)
|
239
|
+
assert_nil res
|
240
|
+
end
|
241
|
+
assert_equal ['*' * 64, '*'], chunks
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
196
245
|
if IS_LINUX
|
197
246
|
class HTTPClientTest < MiniTest::Test
|
198
247
|
|
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.
|
4
|
+
version: '0.82'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-03-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -232,6 +232,7 @@ files:
|
|
232
232
|
- examples/core/nested.rb
|
233
233
|
- examples/core/pingpong.rb
|
234
234
|
- examples/core/queue.rb
|
235
|
+
- examples/core/raw_buffer_test.rb
|
235
236
|
- examples/core/recurrent-timer.rb
|
236
237
|
- examples/core/resource_delegate.rb
|
237
238
|
- examples/core/ring.rb
|
@@ -398,6 +399,7 @@ files:
|
|
398
399
|
- test/test_kernel.rb
|
399
400
|
- test/test_process_supervision.rb
|
400
401
|
- test/test_queue.rb
|
402
|
+
- test/test_raw_buffer.rb
|
401
403
|
- test/test_resource_pool.rb
|
402
404
|
- test/test_signal.rb
|
403
405
|
- test/test_socket.rb
|