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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f4584f87975e018fe58887f4c6786bfe8c631a7d2fed3717e6822d72741fcc92
4
- data.tar.gz: 9353ed759d256a035619d0b18dc53569fba6fdbb0709d79defb585fbf5f63f5a
3
+ metadata.gz: 8f80cdfe71dec5b03bd98ffb4150beec84fd6e35b70b6e099fb223a1c78706bc
4
+ data.tar.gz: 8a245a57849a917814d5b8dbb563315e42291c0063f5fc353578af16002209bb
5
5
  SHA512:
6
- metadata.gz: c4d2d6e7457e49b4803b44e2125b54465a1104635b3d0a1d127538335401eeca6612095a2dcde9b6e149d939d15c6de2a1cbdf892a114535a5f0bd00ea1936e8
7
- data.tar.gz: 5f4eb0a66dec6614d542d2c89cad791e2eb7e27ab9ae74f6bf60c8d4bd9831a098f531be6a619d4f13662631e86f1ac6ddc7bf5bf5f005b8926a4dfc3c7e43ef
6
+ metadata.gz: 0450fcbbe868c731f2e0b41bb196522f33487700eaf2636bb65d65def95af81d341057c071271aa726934008e19969a36a4e8e97e4775d9bb2660f5750708dc3
7
+ data.tar.gz: b789f4ad289136b91a24c3f68ddfc4864dbc2ede4989d7dafec09393527f6f93e44362843a406599a8d38f6f6f8e99626cffb88eb7395fdc99c1cbeafead87dc
@@ -16,7 +16,7 @@ jobs:
16
16
  runs-on: ${{matrix.os}}
17
17
 
18
18
  env:
19
- POLYPHONY_USE_LIBEV: "1"
19
+ POLYPHONY_LIBEV: "1"
20
20
 
21
21
  steps:
22
22
  - name: Setup machine
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
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
+
1
6
  ## 0.81.1 2022-03-03
2
7
 
3
8
  - Fix `Backend_recv` regression
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- polyphony (0.81.1)
4
+ polyphony (0.82)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/bin/test CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env bash
2
2
  set -e
3
- clear && POLYPHONY_USE_LIBEV=1 rake recompile && ruby test/run.rb
3
+ clear && POLYPHONY_LIBEV=1 rake recompile && ruby test/run.rb
4
4
  clear && rake recompile && ruby test/run.rb
@@ -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.size) buf_pos = buffer.size;
363
- buffer.base += buf_pos;
364
- buffer.size -= buf_pos;
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.size) buf_pos = buffer.size;
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.base = RSTRING_PTR(str) + buf_pos;
375
- buffer.size = expected_read_length;
356
+ buffer.ptr = RSTRING_PTR(str) + buf_pos;
357
+ buffer.len = expected_read_length;
376
358
  }
377
359
  else {
378
- buffer.base += buf_pos;
379
- buffer.size = string_cap - buf_pos;
380
- if (buffer.size > expected_read_length)
381
- buffer.size = expected_read_length;
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.base, buffer.size, -1);
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.size) {
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.base = RSTRING_PTR(str) + total + buf_pos;
426
- buffer.size = rb_str_capacity(str) - total - buf_pos;
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.base += result;
430
- buffer.size -= result;
431
- if (!buffer.size) break;
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.size;
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.base, left, 0);
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.base += result;
588
- buffer.size -= result;
568
+ buffer.ptr += result;
589
569
  left -= result;
590
570
  }
591
571
  }
592
572
 
593
- return INT2NUM(buffer.size);
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
- long dynamic_len = length == Qnil;
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 shrinkable;
684
- char *buf;
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 (str != Qnil) {
689
- int current_len = RSTRING_LEN(str);
690
- if (buf_pos < 0 || buf_pos > current_len) buf_pos = current_len;
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, buf, len - total, 0);
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
- io_set_read_length(str, buf_pos + total, shrinkable);
730
- io_enc_str(str, fptr);
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
- char *buf;
845
- long len;
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, buf, left, flags_int);
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
- buf += result;
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
- long dynamic_len = length == Qnil;
274
- long len = dynamic_len ? 4096 : NUM2INT(length);
273
+
274
+ struct io_buffer buffer = get_io_buffer(str);
275
275
  long buf_pos = NUM2INT(pos);
276
- if (str != Qnil) {
277
- int current_len = RSTRING_LEN(str);
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 n = read(fptr->fd, buf, len - total);
299
- if (n < 0) {
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 (n == 0) break; // EOF
312
- total = total + n;
330
+ if (!result) break; // EOF
331
+
332
+ total += result;
313
333
  if (!read_to_eof) break;
314
334
 
315
- if (total == len) {
316
- if (!dynamic_len) break;
335
+ if (result == buffer.len) {
336
+ if (!expandable_buffer) break;
317
337
 
318
- rb_str_resize(str, buf_pos + total);
319
- rb_str_modify_expand(str, len);
320
- buf = RSTRING_PTR(str) + buf_pos + total;
321
- shrinkable = 0;
322
- len += len;
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
- io_set_read_length(str, buf_pos + total, shrinkable);
329
- io_enc_str(str, fptr);
330
-
331
- if (total == 0) return Qnil;
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
- char *buf = StringValuePtr(str);
457
- long len = RSTRING_LEN(str);
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 n = write(fptr->fd, buf, left);
471
- if (n < 0) {
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
- buf += n;
481
- left -= n;
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
- char *buf = StringValuePtr(str);
747
- long len = RSTRING_LEN(str);
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 n = send(fptr->fd, buf, left, flags_int);
762
- if (n < 0) {
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
- buf += n;
772
- left -= n;
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
  }
@@ -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['POLYPHONY_USE_LIBEV'] != nil
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
@@ -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, LONG2FIX((long)&buffer) };
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);
@@ -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 */
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polyphony
4
- VERSION = '0.81.1'
4
+ VERSION = '0.82'
5
5
  end
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.81.1
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-03 00:00:00.000000000 Z
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