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 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