polyphony 0.81.1 → 0.82
Sign up to get free protection for your applications and to get access to all the features.
- 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
|