uringmachine 0.27.0 → 0.28.0

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: 1211434f5b2f4aad1e47d1bd166204cce6792a80e3ef845ae4dee097d8e1ea45
4
- data.tar.gz: eff370b4564c88c3daf57cbed3d8b165113ddee697ee1b16aa63ad3452a38c02
3
+ metadata.gz: c42e434298bf496752efc6fe6a4cc81d04857f28f1151cfc3165ac3c288ec6a2
4
+ data.tar.gz: ec176b165f129aa7d1b6d0bdbc5f4b7e55d5e553569061d89956d0b1aee68503
5
5
  SHA512:
6
- metadata.gz: cdb26cf58a41a9f7ad2d025ccc473b0088f4c3e622a65058b1ee6e0aeb95c0eb3775f980cccb60e81b2213ed8fb49263c6500b2c05fbbb71abb156be00dca636
7
- data.tar.gz: 06f509928387d2812578c143dfb96ed031be10994c7b43908babfef02d72d149b8f2a3932dee7a4d3577150b5512addb8b7c44d5b7ea2e63dddb7f2b427df604
6
+ metadata.gz: 1760b892d6ae21c7007fd0a109a78d631da4ae9a79667ad85bc4740ac0e339802ca9cb0bc34114570bf7e6113e4dab704a1c9f40513a196e840b759a494a35b9
7
+ data.tar.gz: 7dfe1426f96ecd1e99af4224c34d3b3173858b5d6c156b949314a0e80c34b836ae738e930ed26662319bc6700401cd0b369028e172ed1b70982cee64fb13f7a1
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ # 0.28.0 2026-02-19
2
+
3
+ - Add `#terminate`
4
+ - Make `#sendv` available also for older kernels (using `#writev`)
5
+ - Implement `Stream#skip`
6
+ - Inherit exceptions from `StandardError` instead of `RuntimeError`
7
+
1
8
  # 0.27.0 2026-02-15
2
9
 
3
10
  - Add `.pr_set_child_subreaper` method
data/TODO.md CHANGED
@@ -1,9 +1,11 @@
1
1
  ## immediate
2
2
 
3
- - Fix all futex value (Queue, Mutex) to be properly aligned
3
+ - Add tests for support for Set in `machine#await_fibers`
4
+ - Add tests for support for Set, Array in `machine#join`
4
5
 
5
- ## Buffer rings - automatic management
6
+ - (?) Fix all futex value (Queue, Mutex) to be properly aligned
6
7
 
8
+ ## Buffer rings - automatic management
7
9
  - Take the buffer_pool branch, rewrite it
8
10
  - Allow multiple stream modes:
9
11
  - :buffer_pool - uses buffer rings
data/ext/um/um.c CHANGED
@@ -977,7 +977,7 @@ VALUE um_shutdown_async(struct um *machine, int fd, int how) {
977
977
  return INT2NUM(fd);
978
978
  }
979
979
 
980
- struct send_recv_fd_data {
980
+ struct send_recv_fd_ctx {
981
981
  struct msghdr msgh;
982
982
  char iobuf[1];
983
983
  struct iovec iov;
@@ -987,41 +987,34 @@ struct send_recv_fd_data {
987
987
  } u;
988
988
  };
989
989
 
990
- inline void recv_fd_prepare(struct send_recv_fd_data *data) {
991
- memset(&data->msgh, 0, sizeof(data->msgh));
992
- data->iov.iov_base = data->iobuf;
993
- data->iov.iov_len = sizeof(data->iobuf);
994
- data->msgh.msg_iov = &data->iov;
995
- data->msgh.msg_iovlen = 1;
996
- data->msgh.msg_control = data->u.buf;
997
- data->msgh.msg_controllen = sizeof(data->u.buf);
998
- }
999
-
1000
- inline void send_fd_prepare(struct send_recv_fd_data *data, int fd) {
1001
- memset(&data->msgh, 0, sizeof(data->msgh));
1002
- data->iov.iov_base = data->iobuf;
1003
- data->iov.iov_len = sizeof(data->iobuf);
1004
- data->msgh.msg_iov = &data->iov;
1005
- data->msgh.msg_iovlen = 1;
1006
- data->msgh.msg_control = data->u.buf;
1007
- data->msgh.msg_controllen = sizeof(data->u.buf);
1008
-
1009
- struct cmsghdr *cmsgp = CMSG_FIRSTHDR(&data->msgh);
1010
- cmsgp->cmsg_level = SOL_SOCKET;
1011
- cmsgp->cmsg_type = SCM_RIGHTS;
1012
- cmsgp->cmsg_len = CMSG_LEN(sizeof(fd));
1013
- memcpy(CMSG_DATA(cmsgp), &fd, sizeof(fd));
990
+ inline void send_recv_fd_setup_ctx(struct send_recv_fd_ctx *ctx, int fd) {
991
+ ctx->iov.iov_base = ctx->iobuf;
992
+ ctx->iov.iov_len = sizeof(ctx->iobuf);
993
+
994
+ memset(&ctx->msgh, 0, sizeof(ctx->msgh));
995
+ ctx->msgh.msg_iov = &ctx->iov;
996
+ ctx->msgh.msg_iovlen = 1;
997
+ ctx->msgh.msg_control = ctx->u.buf;
998
+ ctx->msgh.msg_controllen = sizeof(ctx->u.buf);
999
+
1000
+ if (fd > 0) {
1001
+ struct cmsghdr *cmsgp = CMSG_FIRSTHDR(&ctx->msgh);
1002
+ cmsgp->cmsg_level = SOL_SOCKET;
1003
+ cmsgp->cmsg_type = SCM_RIGHTS;
1004
+ cmsgp->cmsg_len = CMSG_LEN(sizeof(fd));
1005
+ memcpy(CMSG_DATA(cmsgp), &fd, sizeof(fd));
1006
+ }
1014
1007
  }
1015
1008
 
1016
1009
  VALUE um_send_fd(struct um *machine, int sock_fd, int fd) {
1017
- struct send_recv_fd_data data;
1018
- send_fd_prepare(&data, fd);
1010
+ struct send_recv_fd_ctx ctx;
1011
+ send_recv_fd_setup_ctx(&ctx, fd);
1019
1012
 
1020
1013
  VALUE ret = Qnil;
1021
1014
  struct um_op *op = um_op_acquire(machine);
1022
1015
  um_prep_op(machine, op, OP_SENDMSG, 2, 0);
1023
1016
  struct io_uring_sqe *sqe = um_get_sqe(machine, op);
1024
- io_uring_prep_sendmsg(sqe, sock_fd, &data.msgh, 0);
1017
+ io_uring_prep_sendmsg(sqe, sock_fd, &ctx.msgh, 0);
1025
1018
 
1026
1019
  ret = um_yield(machine);
1027
1020
 
@@ -1033,9 +1026,9 @@ VALUE um_send_fd(struct um *machine, int sock_fd, int fd) {
1033
1026
  return ret;
1034
1027
  }
1035
1028
 
1036
- inline int recv_fd_get_fd(struct send_recv_fd_data *data) {
1029
+ inline int recv_fd_get_fd(struct send_recv_fd_ctx *ctx) {
1037
1030
  int fd;
1038
- struct cmsghdr *cmsgp = CMSG_FIRSTHDR(&data->msgh);
1031
+ struct cmsghdr *cmsgp = CMSG_FIRSTHDR(&ctx->msgh);
1039
1032
 
1040
1033
  if (cmsgp == NULL || cmsgp->cmsg_len != CMSG_LEN(sizeof(int)) ||
1041
1034
  cmsgp->cmsg_level != SOL_SOCKET || cmsgp->cmsg_type != SCM_RIGHTS
@@ -1046,17 +1039,17 @@ inline int recv_fd_get_fd(struct send_recv_fd_data *data) {
1046
1039
  }
1047
1040
 
1048
1041
  VALUE um_recv_fd(struct um *machine, int sock_fd) {
1049
- struct send_recv_fd_data data;
1050
- recv_fd_prepare(&data);
1042
+ struct send_recv_fd_ctx ctx;
1043
+ send_recv_fd_setup_ctx(&ctx, -1);
1051
1044
 
1052
1045
  struct um_op *op = um_op_acquire(machine);
1053
1046
  um_prep_op(machine, op, OP_RECVMSG, 2, 0);
1054
1047
  struct io_uring_sqe *sqe = um_get_sqe(machine, op);
1055
- io_uring_prep_recvmsg(sqe, sock_fd, &data.msgh, 0);
1048
+ io_uring_prep_recvmsg(sqe, sock_fd, &ctx.msgh, 0);
1056
1049
 
1057
1050
  VALUE ret = um_yield(machine);
1058
1051
 
1059
- if (likely(um_verify_op_completion(machine, op, true))) ret = INT2NUM(recv_fd_get_fd(&data));
1052
+ if (likely(um_verify_op_completion(machine, op, true))) ret = INT2NUM(recv_fd_get_fd(&ctx));
1060
1053
  um_op_release(machine, op);
1061
1054
 
1062
1055
  RAISE_IF_EXCEPTION(ret);
data/ext/um/um.h CHANGED
@@ -377,6 +377,7 @@ VALUE um_queue_shift(struct um *machine, struct um_queue *queue);
377
377
 
378
378
  VALUE stream_get_line(struct um_stream *stream, VALUE buf, ssize_t maxlen);
379
379
  VALUE stream_get_string(struct um_stream *stream, VALUE buf, ssize_t len);
380
+ VALUE stream_skip(struct um_stream *stream, size_t len);
380
381
  VALUE resp_decode(struct um_stream *stream, VALUE out_buffer);
381
382
  void resp_encode(struct um_write_buffer *buf, VALUE obj);
382
383
  void resp_encode_cmd(struct um_write_buffer *buf, int argc, VALUE *argv);
data/ext/um/um_class.c CHANGED
@@ -747,8 +747,6 @@ VALUE UM_send(VALUE self, VALUE fd, VALUE buffer, VALUE len, VALUE flags) {
747
747
  return um_send(machine, NUM2INT(fd), buffer, NUM2INT(len), NUM2INT(flags));
748
748
  }
749
749
 
750
- #ifdef HAVE_IO_URING_SEND_VECTORIZED
751
-
752
750
  /* call-seq:
753
751
  * machine.sendv(fd, *buffers) -> bytes_sent
754
752
  *
@@ -770,10 +768,13 @@ VALUE UM_sendv(int argc, VALUE *argv, VALUE self) {
770
768
  int fd = NUM2INT(argv[0]);
771
769
  if (argc < 2) return INT2NUM(0);
772
770
 
771
+ #ifdef HAVE_IO_URING_SEND_VECTORIZED
773
772
  return um_sendv(machine, fd, argc - 1, argv + 1);
773
+ #else
774
+ return um_writev(machine, fd, argc - 1, argv + 1);
775
+ #endif
774
776
  }
775
777
 
776
- #endif
777
778
 
778
779
  /* call-seq:
779
780
  * machine.send_bundle(fd, bgid, *buffers) -> bytes_sent
@@ -1492,10 +1493,7 @@ void Init_UM(void) {
1492
1493
  rb_define_method(cUM, "recv", UM_recv, 4);
1493
1494
  rb_define_method(cUM, "recv_each", UM_recv_each, 3);
1494
1495
  rb_define_method(cUM, "send", UM_send, 4);
1495
-
1496
- #ifdef HAVE_IO_URING_SEND_VECTORIZED
1497
1496
  rb_define_method(cUM, "sendv", UM_sendv, -1);
1498
- #endif
1499
1497
 
1500
1498
  rb_define_method(cUM, "send_bundle", UM_send_bundle, -1);
1501
1499
  rb_define_method(cUM, "setsockopt", UM_setsockopt, 4);
data/ext/um/um_stream.c CHANGED
@@ -19,6 +19,7 @@ static inline void stream_check_truncate_buffer(struct um_stream *stream) {
19
19
  }
20
20
  }
21
21
 
22
+ // returns true if eof
22
23
  int stream_read_more(struct um_stream *stream) {
23
24
  stream_check_truncate_buffer(stream);
24
25
 
@@ -104,6 +105,16 @@ VALUE stream_get_string(struct um_stream *stream, VALUE buf, ssize_t len) {
104
105
  return buf;
105
106
  }
106
107
 
108
+ VALUE stream_skip(struct um_stream *stream, size_t len) {
109
+ while (stream->len - stream->pos < len)
110
+ if (!stream_read_more(stream)) {
111
+ return Qnil;
112
+ }
113
+
114
+ stream->pos += len;
115
+ return NUM2INT(len);
116
+ }
117
+
107
118
  VALUE resp_get_line(struct um_stream *stream, VALUE out_buffer) {
108
119
  char *start = RSTRING_PTR(stream->buffer) + stream->pos;
109
120
  while (true) {
@@ -65,6 +65,14 @@ VALUE Stream_get_string(VALUE self, VALUE buf, VALUE len) {
65
65
  return stream_get_string(stream, buf, NUM2LONG(len));
66
66
  }
67
67
 
68
+ // skips `len` bytes in the stream. This function returns nil if eof is
69
+ // encountered.
70
+ VALUE Stream_skip(VALUE self, VALUE len) {
71
+ struct um_stream *stream = Stream_data(self);
72
+
73
+ return stream_skip(stream, NUM2LONG(len));
74
+ }
75
+
68
76
  VALUE Stream_resp_decode(VALUE self) {
69
77
  struct um_stream *stream = Stream_data(self);
70
78
  if (unlikely(stream->eof)) return Qnil;
@@ -104,6 +112,7 @@ void Init_Stream(void) {
104
112
 
105
113
  rb_define_method(cStream, "get_line", Stream_get_line, 2);
106
114
  rb_define_method(cStream, "get_string", Stream_get_string, 2);
115
+ rb_define_method(cStream, "skip", Stream_skip, 1);
107
116
 
108
117
  rb_define_method(cStream, "resp_decode", Stream_resp_decode, 0);
109
118
 
data/grant-2025/tasks.md CHANGED
@@ -147,22 +147,9 @@
147
147
  - [ ] docs (similar to papercraft docs)
148
148
 
149
149
  - [ ] Uma - web server
150
- - [ ] child process workers
151
- - [ ] reforking (following https://github.com/Shopify/pitchfork)
152
- see also: https://byroot.github.io/ruby/performance/2025/03/04/the-pitchfork-story.html
153
- - Monitor worker memory usage - how much is shared
154
- - Choose worker with most served request count as "mold" for next generation
155
- - Perform GC out of band, preferably when there are no active requests
156
- https://railsatscale.com/2024-10-23-next-generation-oob-gc/
157
- - When a worker is promoted to "mold", it:
158
- - Stops `accept`ing requests
159
- - When finally idle, calls `Process.warmup`
160
- - Starts replacing sibling workers with forked workers
161
- see also: https://www.youtube.com/watch?v=kAW5O2dkSU8
162
- - [ ] Each worker is single-threaded (except for worker threads)
163
150
  - [ ] Rack 3.0-compatible
164
151
  see: https://github.com/socketry/protocol-rack
165
152
  - [ ] Rails integration (Railtie)
166
153
  see: https://github.com/socketry/falcon
167
154
  - [ ] Benchmarks
168
- - [ ] Add to the TechEmpower bencchmarks
155
+ - [ ] Add to the TechEmpower benchmarks
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class UringMachine
4
- VERSION = '0.27.0'
4
+ VERSION = '0.28.0'
5
5
  end
data/lib/uringmachine.rb CHANGED
@@ -36,6 +36,11 @@ class UringMachine
36
36
  fiber
37
37
  end
38
38
 
39
+ def terminate(*fibers)
40
+ exception = UM::Terminate.new
41
+ fibers.each { schedule(it, exception) }
42
+ end
43
+
39
44
  # Runs the given block in the given fiber. This method is used to run fibers
40
45
  # indirectly.
41
46
  #
@@ -60,7 +60,7 @@ class AsyncOpTest < UMBaseTest
60
60
  assert_equal true, @op.cancelled?
61
61
  end
62
62
 
63
- class TOError < RuntimeError; end
63
+ class TOError < StandardError; end
64
64
 
65
65
  def test_async_op_await_with_timeout
66
66
  e = nil
data/test/test_stream.rb CHANGED
@@ -98,6 +98,23 @@ class StreamTest < StreamBaseTest
98
98
  ret = @stream.get_string(nil, -4)
99
99
  assert_nil ret
100
100
  end
101
+
102
+ def test_skip
103
+ machine.write(@wfd, "foobar")
104
+ machine.close(@wfd)
105
+
106
+ ret = @stream.get_string(nil, 2)
107
+ assert_equal 'fo', ret
108
+
109
+ ret = @stream.skip(2)
110
+ assert_equal 2, ret
111
+
112
+ ret = @stream.get_string(nil, 2)
113
+ assert_equal 'ar', ret
114
+
115
+ ret = @stream.skip(2)
116
+ assert_nil ret
117
+ end
101
118
  end
102
119
 
103
120
  class StreamRespTest < StreamBaseTest
data/test/test_um.rb CHANGED
@@ -238,7 +238,38 @@ class ScheduleTest < UMBaseTest
238
238
  assert_in_range 0..0.1, t1 - t0
239
239
  end
240
240
 
241
- class TOError < RuntimeError; end
241
+ def test_terminate
242
+ e = nil
243
+ f = machine.spin do
244
+ machine.sleep(1)
245
+ rescue UM::Terminate => e
246
+ end
247
+
248
+ machine.snooze
249
+ machine.terminate(f)
250
+ machine.snooze
251
+ assert_kind_of UM::Terminate, e
252
+ assert_equal true, f.done?
253
+ end
254
+
255
+ def test_terminate_multi
256
+ f1 = machine.spin { machine.sleep(1) }
257
+ f2 = machine.spin { machine.sleep(1) }
258
+ f3 = machine.spin { machine.sleep(1) }
259
+
260
+ machine.snooze
261
+ machine.terminate(f1, f2)
262
+ machine.snooze
263
+ assert_equal true, f1.done?
264
+ assert_equal true, f2.done?
265
+ assert_nil f3.done?
266
+
267
+ machine.terminate(f3)
268
+ machine.snooze
269
+ assert_equal true, f3.done?
270
+ end
271
+
272
+ class TOError < StandardError; end
242
273
 
243
274
  def test_timeout
244
275
  buf = []
@@ -299,8 +330,8 @@ class ScheduleTest < UMBaseTest
299
330
  assert_equal 0, machine.metrics[:ops_pending]
300
331
  end
301
332
 
302
- class TO2Error < RuntimeError; end
303
- class TO3Error < RuntimeError; end
333
+ class TO2Error < StandardError; end
334
+ class TO3Error < StandardError; end
304
335
 
305
336
  def test_timeout_nested
306
337
  e = nil
@@ -351,7 +382,7 @@ class SleepTest < UMBaseTest
351
382
  assert_kind_of C, ret
352
383
  end
353
384
 
354
- class D < RuntimeError; end
385
+ class D < StandardError; end
355
386
 
356
387
  def test_sleep_with_timeout
357
388
  t0 = monotonic_clock
@@ -955,7 +986,7 @@ class WritevTest < UMBaseTest
955
986
  machine.join(f)
956
987
  end
957
988
 
958
- class TOError < RuntimeError; end
989
+ class TOError < StandardError; end
959
990
 
960
991
  def test_writev_timeout
961
992
  r, w = UM.pipe
@@ -1639,8 +1670,6 @@ class SendvTest < UMBaseTest
1639
1670
  end
1640
1671
 
1641
1672
  def test_sendv
1642
- skip "Unavailable on kernel version < 6.17" if UM.kernel_version < 617
1643
-
1644
1673
  ret = machine.sendv(@s1, 'foo', 'bar', 'baz')
1645
1674
  assert_equal 9, ret
1646
1675
 
@@ -1653,8 +1682,6 @@ class SendvTest < UMBaseTest
1653
1682
  end
1654
1683
 
1655
1684
  def test_sendv_io_buffer
1656
- skip "Unavailable on kernel version < 6.17" if UM.kernel_version < 617
1657
-
1658
1685
  buf1 = IO::Buffer.new(6)
1659
1686
  buf1.set_string('foobar')
1660
1687
 
@@ -1673,8 +1700,6 @@ class SendvTest < UMBaseTest
1673
1700
  end
1674
1701
 
1675
1702
  def test_sendv_invalid_buffer
1676
- skip "Unavailable on kernel version < 6.17" if UM.kernel_version < 617
1677
-
1678
1703
  assert_raises(UM::Error) { machine.sendv(@s1, [], 'abc') }
1679
1704
  assert_equal 0, machine.metrics[:ops_pending]
1680
1705
  assert_equal 0, machine.metrics[:ops_free]
@@ -1914,6 +1939,98 @@ class SendRecvFdTest < UMBaseTest
1914
1939
  assert_equal 'foobar', buf
1915
1940
  end
1916
1941
 
1942
+ def test_send_recv_fd_multi
1943
+ r_fd, w_fd = UM.pipe
1944
+
1945
+ res = machine.send_fd(@s1_fd, w_fd)
1946
+ assert_equal w_fd, res
1947
+
1948
+ w_fd2 = machine.recv_fd(@s2_fd)
1949
+ assert_kind_of Integer, w_fd2
1950
+ refute_equal w_fd, w_fd2
1951
+
1952
+ res = machine.send_fd(@s1_fd, r_fd)
1953
+ assert_equal r_fd, res
1954
+
1955
+ r_fd2 = machine.recv_fd(@s2_fd)
1956
+ assert_kind_of Integer, r_fd2
1957
+ refute_equal r_fd, r_fd2
1958
+
1959
+ machine.close(w_fd)
1960
+ machine.write(w_fd2, 'foobar')
1961
+ machine.close(w_fd2)
1962
+
1963
+ buf = +''
1964
+ res = machine.read(r_fd, buf, 12)
1965
+ assert_equal 6, res
1966
+ assert_equal 'foobar', buf
1967
+ ensure
1968
+ machine.close(r_fd) if r_fd rescue nil
1969
+ machine.close(w_fd) if w_fd rescue nil
1970
+ machine.close(r_fd2) if r_fd2 rescue nil
1971
+ machine.close(w_fd2) if w_fd2 rescue nil
1972
+
1973
+ end
1974
+
1975
+ def test_send_recv_fd_mixed_multi
1976
+ r_fd, w_fd = UM.pipe
1977
+
1978
+ machine.send(@s1_fd, 'hi', 2, 0)
1979
+ buf = +''
1980
+ ret = machine.recv(@s2_fd, buf, 2, 0)
1981
+ assert_equal 2, ret
1982
+ assert_equal 'hi', buf
1983
+
1984
+ res = machine.send_fd(@s1_fd, w_fd)
1985
+ assert_equal w_fd, res
1986
+
1987
+ w_fd2 = machine.recv_fd(@s2_fd)
1988
+ assert_kind_of Integer, w_fd2
1989
+ refute_equal w_fd, w_fd2
1990
+
1991
+ res = machine.send_fd(@s1_fd, r_fd)
1992
+ assert_equal r_fd, res
1993
+
1994
+ r_fd2 = machine.recv_fd(@s2_fd)
1995
+ assert_kind_of Integer, r_fd2
1996
+ refute_equal r_fd, r_fd2
1997
+
1998
+ machine.close(w_fd)
1999
+ machine.write(w_fd2, 'foobar')
2000
+ machine.close(w_fd2)
2001
+
2002
+ buf = +''
2003
+ res = machine.read(r_fd, buf, 12)
2004
+ assert_equal 6, res
2005
+ assert_equal 'foobar', buf
2006
+ ensure
2007
+ machine.close(r_fd) if r_fd rescue nil
2008
+ machine.close(w_fd) if w_fd rescue nil
2009
+ machine.close(r_fd2) if r_fd2 rescue nil
2010
+ machine.close(w_fd2) if w_fd2 rescue nil
2011
+
2012
+ end
2013
+
2014
+ def test_send_recv_fd_inverse
2015
+ r_fd, w_fd = UM.pipe
2016
+
2017
+ res = machine.send_fd(@s2_fd, w_fd)
2018
+ assert_equal w_fd, res
2019
+
2020
+ fd = machine.recv_fd(@s1_fd)
2021
+ assert_kind_of Integer, fd
2022
+ refute_equal w_fd, fd
2023
+
2024
+ machine.close(w_fd)
2025
+ machine.write(fd, 'foobar')
2026
+ machine.close(fd)
2027
+
2028
+ buf = +''
2029
+ res = machine.read(r_fd, buf, 12)
2030
+ assert_equal 6, res
2031
+ assert_equal 'foobar', buf
2032
+ end
2033
+
1917
2034
  def test_send_recv_fd_fork
1918
2035
  pid = fork do
1919
2036
  m = UM.new
@@ -1944,6 +2061,68 @@ class SendRecvFdTest < UMBaseTest
1944
2061
  machine.close(w_fd) rescue nil
1945
2062
  end
1946
2063
 
2064
+ def test_send_recv_fd_fork_mixed_msgs
2065
+ skip
2066
+
2067
+ pid = fork do
2068
+ m = UM.new
2069
+ buf = +''
2070
+ ret = m.recv(@s2_fd, buf, 128, 0)
2071
+ p forked_recv: buf, ret: ret
2072
+ ret = m.send(@s2_fd, buf, buf.bytesize, 0)
2073
+ p forked_send: buf, ret: ret
2074
+ fd = m.recv_fd(@s2_fd)
2075
+ p forked_recv_fd: fd
2076
+ ret = m.send(@s2_fd, buf, buf.bytesize, 0)
2077
+ p forked_send: buf, ret: ret
2078
+
2079
+ m.write(fd, 'foo')
2080
+ ensure
2081
+ m.close(fd) if fd rescue nil
2082
+ end
2083
+
2084
+ buf = +''
2085
+
2086
+ machine.send(@s1_fd, 'coocoo', 6, 0)
2087
+ machine.recv(@s1_fd, buf, 128, 0)
2088
+ assert_equal 'coocoo', buf
2089
+
2090
+ r_fd, w_fd = UM.pipe
2091
+ machine.send_fd(@s1_fd, w_fd)
2092
+ machine.recv(@s1_fd, buf, 128, 0)
2093
+ assert_equal 'coocoo', buf
2094
+
2095
+ machine.read(r_fd, buf, 128)
2096
+ assert_equal 'foo', buf
2097
+ ensure
2098
+ if pid
2099
+ Process.kill('KILL', pid) rescue nil
2100
+ Process.wait(pid) rescue nil
2101
+ end
2102
+ machine.close(r_fd) rescue nil
2103
+ machine.close(w_fd) rescue nil
2104
+ end
2105
+
2106
+ def test_send_recv_fd_fork_inverse
2107
+ pid = fork do
2108
+ m = UM.new
2109
+ r, w = UM.pipe
2110
+ m.send_fd(@s2_fd, r)
2111
+
2112
+ buf = +''
2113
+ m.read(r, buf, 128)
2114
+ m.send(@s2_fd, buf)
2115
+ end
2116
+
2117
+ assert_raises(Errno::EINVAL) { machine.recv_fd(@s1_fd) }
2118
+ ensure
2119
+ if pid
2120
+ Process.kill('KILL', pid) rescue nil
2121
+ Process.wait(pid) rescue nil
2122
+ end
2123
+ machine.close(w) rescue nil
2124
+ end
2125
+
1947
2126
  def test_send_fd_bad_sock_fd
1948
2127
  _r_fd, w_fd = UM.pipe
1949
2128
  assert_raises(Errno::ENOTSOCK) { machine.send_fd(0, w_fd) }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uringmachine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.27.0
4
+ version: 0.28.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner