polyphony 0.81.1 → 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 +5 -0
- data/Gemfile.lock +1 -1
- data/bin/test +1 -1
- data/ext/polyphony/backend_common.c +18 -0
- data/ext/polyphony/backend_common.h +17 -0
- data/ext/polyphony/backend_io_uring.c +60 -69
- data/ext/polyphony/backend_libev.c +68 -42
- data/ext/polyphony/extconf.rb +1 -1
- data/ext/polyphony/polyphony.c +45 -1
- data/ext/polyphony/polyphony.h +0 -11
- 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 +3 -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
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);
|
@@ -102,24 +102,6 @@ static VALUE Backend_initialize(VALUE self) {
|
|
102
102
|
return self;
|
103
103
|
}
|
104
104
|
|
105
|
-
static inline struct io_buffer get_io_buffer(VALUE in) {
|
106
|
-
if (FIXNUM_P(in)) {
|
107
|
-
struct raw_buffer *raw = (struct raw_buffer *)(FIX2LONG(in));
|
108
|
-
return (struct io_buffer){ raw->base, raw->size, 1 };
|
109
|
-
}
|
110
|
-
return (struct io_buffer){ RSTRING_PTR(in), RSTRING_LEN(in), 0 };
|
111
|
-
}
|
112
|
-
|
113
|
-
static inline VALUE coerce_io_string_or_buffer(VALUE buf) {
|
114
|
-
switch (TYPE(buf)) {
|
115
|
-
case T_STRING:
|
116
|
-
case T_FIXNUM:
|
117
|
-
return buf;
|
118
|
-
default:
|
119
|
-
return StringValue(buf);
|
120
|
-
}
|
121
|
-
}
|
122
|
-
|
123
105
|
VALUE Backend_finalize(VALUE self) {
|
124
106
|
Backend_t *backend;
|
125
107
|
GetBackend(self, backend);
|
@@ -359,26 +341,26 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof,
|
|
359
341
|
VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
|
360
342
|
|
361
343
|
if (buffer.raw) {
|
362
|
-
if (buf_pos < 0 || buf_pos > buffer.
|
363
|
-
buffer.
|
364
|
-
buffer.
|
344
|
+
if (buf_pos < 0 || buf_pos > buffer.len) buf_pos = buffer.len;
|
345
|
+
buffer.ptr += buf_pos;
|
346
|
+
buffer.len -= buf_pos;
|
365
347
|
}
|
366
348
|
else {
|
367
349
|
expandable_buffer = length == Qnil;
|
368
350
|
long expected_read_length = expandable_buffer ? 4096 : FIX2INT(length);
|
369
351
|
long string_cap = rb_str_capacity(str);
|
370
|
-
if (buf_pos < 0 || buf_pos > buffer.
|
352
|
+
if (buf_pos < 0 || buf_pos > buffer.len) buf_pos = buffer.len;
|
371
353
|
|
372
354
|
if (string_cap < expected_read_length + buf_pos) {
|
373
355
|
shrinkable_string = io_setstrbuf(&str, expected_read_length + buf_pos);
|
374
|
-
buffer.
|
375
|
-
buffer.
|
356
|
+
buffer.ptr = RSTRING_PTR(str) + buf_pos;
|
357
|
+
buffer.len = expected_read_length;
|
376
358
|
}
|
377
359
|
else {
|
378
|
-
buffer.
|
379
|
-
buffer.
|
380
|
-
if (buffer.
|
381
|
-
buffer.
|
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;
|
382
364
|
}
|
383
365
|
}
|
384
366
|
|
@@ -396,7 +378,7 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof,
|
|
396
378
|
int result;
|
397
379
|
int completed;
|
398
380
|
|
399
|
-
io_uring_prep_read(sqe, fptr->fd, buffer.
|
381
|
+
io_uring_prep_read(sqe, fptr->fd, buffer.ptr, buffer.len, -1);
|
400
382
|
|
401
383
|
result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
402
384
|
completed = context_store_release(&backend->store, ctx);
|
@@ -415,20 +397,20 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof,
|
|
415
397
|
total += result;
|
416
398
|
if (!read_to_eof) break;
|
417
399
|
|
418
|
-
if (result == buffer.
|
400
|
+
if (result == buffer.len) {
|
419
401
|
if (!expandable_buffer) break;
|
420
402
|
|
421
403
|
// resize buffer to double its capacity
|
422
404
|
rb_str_resize(str, total + buf_pos);
|
423
405
|
rb_str_modify_expand(str, rb_str_capacity(str));
|
424
406
|
shrinkable_string = 0;
|
425
|
-
buffer.
|
426
|
-
buffer.
|
407
|
+
buffer.ptr = RSTRING_PTR(str) + total + buf_pos;
|
408
|
+
buffer.len = rb_str_capacity(str) - total - buf_pos;
|
427
409
|
}
|
428
410
|
else {
|
429
|
-
buffer.
|
430
|
-
buffer.
|
431
|
-
if (!buffer.
|
411
|
+
buffer.ptr += result;
|
412
|
+
buffer.len -= result;
|
413
|
+
if (!buffer.len) break;
|
432
414
|
}
|
433
415
|
}
|
434
416
|
}
|
@@ -437,7 +419,6 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof,
|
|
437
419
|
io_set_read_length(str, buf_pos + total, shrinkable_string);
|
438
420
|
io_enc_str(str, fptr);
|
439
421
|
}
|
440
|
-
|
441
422
|
if (!total) return Qnil;
|
442
423
|
|
443
424
|
return buffer.raw ? INT2FIX(total) : str;
|
@@ -554,7 +535,7 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
|
554
535
|
VALUE underlying_io;
|
555
536
|
|
556
537
|
struct io_buffer buffer = get_io_buffer(str);
|
557
|
-
long left = buffer.
|
538
|
+
long left = buffer.len;
|
558
539
|
|
559
540
|
underlying_io = rb_ivar_get(io, ID_ivar_io);
|
560
541
|
if (underlying_io != Qnil) io = underlying_io;
|
@@ -570,7 +551,7 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
|
570
551
|
int result;
|
571
552
|
int completed;
|
572
553
|
|
573
|
-
io_uring_prep_write(sqe, fptr->fd, buffer.
|
554
|
+
io_uring_prep_write(sqe, fptr->fd, buffer.ptr, left, 0);
|
574
555
|
|
575
556
|
result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
576
557
|
completed = context_store_release(&backend->store, ctx);
|
@@ -584,13 +565,12 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
|
584
565
|
if (result < 0)
|
585
566
|
rb_syserr_fail(-result, strerror(-result));
|
586
567
|
else {
|
587
|
-
buffer.
|
588
|
-
buffer.size -= result;
|
568
|
+
buffer.ptr += result;
|
589
569
|
left -= result;
|
590
570
|
}
|
591
571
|
}
|
592
572
|
|
593
|
-
return INT2NUM(buffer.
|
573
|
+
return INT2NUM(buffer.len);
|
594
574
|
}
|
595
575
|
|
596
576
|
VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
@@ -677,21 +657,36 @@ VALUE Backend_write_m(int argc, VALUE *argv, VALUE self) {
|
|
677
657
|
VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length, VALUE pos) {
|
678
658
|
Backend_t *backend;
|
679
659
|
rb_io_t *fptr;
|
680
|
-
|
681
|
-
long len = dynamic_len ? 4096 : NUM2INT(length);
|
660
|
+
struct io_buffer buffer = get_io_buffer(str);
|
682
661
|
long buf_pos = NUM2INT(pos);
|
683
|
-
int
|
684
|
-
|
662
|
+
int shrinkable_string = 0;
|
663
|
+
int expandable_buffer = 0;
|
685
664
|
long total = 0;
|
686
|
-
VALUE underlying_io = rb_ivar_get(io, ID_ivar_io)
|
665
|
+
VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
|
687
666
|
|
688
|
-
if (
|
689
|
-
|
690
|
-
|
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
|
+
}
|
691
689
|
}
|
692
|
-
else buf_pos = 0;
|
693
|
-
shrinkable = io_setstrbuf(&str, buf_pos + len);
|
694
|
-
buf = RSTRING_PTR(str) + buf_pos;
|
695
690
|
|
696
691
|
GetBackend(self, backend);
|
697
692
|
if (underlying_io != Qnil) io = underlying_io;
|
@@ -707,7 +702,7 @@ VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length, VALUE pos) {
|
|
707
702
|
int result;
|
708
703
|
int completed;
|
709
704
|
|
710
|
-
io_uring_prep_recv(sqe, fptr->fd,
|
705
|
+
io_uring_prep_recv(sqe, fptr->fd, buffer.ptr, buffer.len, 0);
|
711
706
|
|
712
707
|
result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
713
708
|
completed = context_store_release(&backend->store, ctx);
|
@@ -726,12 +721,13 @@ VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length, VALUE pos) {
|
|
726
721
|
}
|
727
722
|
}
|
728
723
|
|
729
|
-
|
730
|
-
|
731
|
-
|
724
|
+
if (!buffer.raw) {
|
725
|
+
io_set_read_length(str, buf_pos + total, shrinkable_string);
|
726
|
+
io_enc_str(str, fptr);
|
727
|
+
}
|
732
728
|
if (!total) return Qnil;
|
733
729
|
|
734
|
-
return str;
|
730
|
+
return buffer.raw ? INT2FIX(total) : str;
|
735
731
|
}
|
736
732
|
|
737
733
|
VALUE Backend_recv_loop(VALUE self, VALUE io, VALUE maxlen) {
|
@@ -841,10 +837,10 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
|
|
841
837
|
Backend_t *backend;
|
842
838
|
rb_io_t *fptr;
|
843
839
|
VALUE underlying_io;
|
844
|
-
|
845
|
-
|
846
|
-
long left;
|
847
|
-
int flags_int;
|
840
|
+
|
841
|
+
struct io_buffer buffer = get_io_buffer(str);
|
842
|
+
long left = buffer.len;
|
843
|
+
int flags_int = NUM2INT(flags);
|
848
844
|
|
849
845
|
underlying_io = rb_ivar_get(io, ID_ivar_io);
|
850
846
|
if (underlying_io != Qnil) io = underlying_io;
|
@@ -853,11 +849,6 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
|
|
853
849
|
GetOpenFile(io, fptr);
|
854
850
|
io_unset_nonblock(fptr, io);
|
855
851
|
|
856
|
-
buf = StringValuePtr(str);
|
857
|
-
len = RSTRING_LEN(str);
|
858
|
-
left = len;
|
859
|
-
flags_int = NUM2INT(flags);
|
860
|
-
|
861
852
|
while (left > 0) {
|
862
853
|
VALUE resume_value = Qnil;
|
863
854
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_SEND);
|
@@ -865,7 +856,7 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
|
|
865
856
|
int result;
|
866
857
|
int completed;
|
867
858
|
|
868
|
-
io_uring_prep_send(sqe, fptr->fd,
|
859
|
+
io_uring_prep_send(sqe, fptr->fd, buffer.ptr, left, flags_int);
|
869
860
|
|
870
861
|
result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
871
862
|
completed = context_store_release(&backend->store, ctx);
|
@@ -879,12 +870,12 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
|
|
879
870
|
if (result < 0)
|
880
871
|
rb_syserr_fail(-result, strerror(-result));
|
881
872
|
else {
|
882
|
-
|
873
|
+
buffer.ptr += result;
|
883
874
|
left -= result;
|
884
875
|
}
|
885
876
|
}
|
886
877
|
|
887
|
-
return INT2NUM(len);
|
878
|
+
return INT2NUM(buffer.len);
|
888
879
|
}
|
889
880
|
|
890
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,9 +118,49 @@ 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
|
+
|
121
161
|
VALUE Polyphony_backend_test(VALUE self, VALUE io, VALUE str) {
|
122
162
|
struct raw_buffer buffer = { RSTRING_PTR(str), RSTRING_LEN(str) };
|
123
|
-
VALUE args[2] = { io,
|
163
|
+
VALUE args[2] = { io, PTR2FIX(&buffer) };
|
124
164
|
return Polyphony_backend_write(2, args, self);
|
125
165
|
}
|
126
166
|
|
@@ -155,6 +195,10 @@ void Init_Polyphony() {
|
|
155
195
|
// rb_define_singleton_method(mPolyphony, "backend_close", Polyphony_backend_close, 1);
|
156
196
|
rb_define_singleton_method(mPolyphony, "backend_verify_blocking_mode", Backend_verify_blocking_mode, 2);
|
157
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);
|
158
202
|
rb_define_singleton_method(mPolyphony, "backend_test", Polyphony_backend_test, 2);
|
159
203
|
|
160
204
|
rb_define_global_function("snooze", Polyphony_snooze, 0);
|
data/ext/polyphony/polyphony.h
CHANGED
@@ -135,15 +135,4 @@ VALUE Thread_switch_fiber(VALUE thread);
|
|
135
135
|
|
136
136
|
VALUE Polyphony_snooze(VALUE self);
|
137
137
|
|
138
|
-
struct raw_buffer {
|
139
|
-
char *base;
|
140
|
-
int size;
|
141
|
-
};
|
142
|
-
|
143
|
-
struct io_buffer {
|
144
|
-
char *base;
|
145
|
-
int size;
|
146
|
-
int raw;
|
147
|
-
};
|
148
|
-
|
149
138
|
#endif /* POLYPHONY_H */
|
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-03-
|
11
|
+
date: 2022-03-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -399,6 +399,7 @@ files:
|
|
399
399
|
- test/test_kernel.rb
|
400
400
|
- test/test_process_supervision.rb
|
401
401
|
- test/test_queue.rb
|
402
|
+
- test/test_raw_buffer.rb
|
402
403
|
- test/test_resource_pool.rb
|
403
404
|
- test/test_signal.rb
|
404
405
|
- test/test_socket.rb
|