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 +4 -4
- data/CHANGELOG.md +7 -0
- data/TODO.md +4 -2
- data/ext/um/um.c +27 -34
- data/ext/um/um.h +1 -0
- data/ext/um/um_class.c +4 -6
- data/ext/um/um_stream.c +11 -0
- data/ext/um/um_stream_class.c +9 -0
- data/grant-2025/tasks.md +1 -14
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +5 -0
- data/test/test_async_op.rb +1 -1
- data/test/test_stream.rb +17 -0
- data/test/test_um.rb +190 -11
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c42e434298bf496752efc6fe6a4cc81d04857f28f1151cfc3165ac3c288ec6a2
|
|
4
|
+
data.tar.gz: ec176b165f129aa7d1b6d0bdbc5f4b7e55d5e553569061d89956d0b1aee68503
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
-
-
|
|
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
|
-
|
|
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
|
|
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
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
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
|
|
1018
|
-
|
|
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, &
|
|
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
|
|
1029
|
+
inline int recv_fd_get_fd(struct send_recv_fd_ctx *ctx) {
|
|
1037
1030
|
int fd;
|
|
1038
|
-
struct cmsghdr *cmsgp = CMSG_FIRSTHDR(&
|
|
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
|
|
1050
|
-
|
|
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, &
|
|
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(&
|
|
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) {
|
data/ext/um/um_stream_class.c
CHANGED
|
@@ -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
|
|
155
|
+
- [ ] Add to the TechEmpower benchmarks
|
data/lib/uringmachine/version.rb
CHANGED
data/lib/uringmachine.rb
CHANGED
data/test/test_async_op.rb
CHANGED
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
|
-
|
|
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 <
|
|
303
|
-
class TO3Error <
|
|
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 <
|
|
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 <
|
|
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) }
|