Skip to content

Commit 81bc6bc

Browse files
committed
Implement #recv_each
1 parent 8338c37 commit 81bc6bc

File tree

6 files changed

+106
-9
lines changed

6 files changed

+106
-9
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
- Add `#recv_each`
2+
- Add `#getsockopt`, `#setsockopt`
3+
- Simplify and improve op management
4+
15
# 2024-10-06 Version 0.4
26

37
- Add socket constants

TODO.md

+15
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
1+
- send_bundle / recv_bundle (kernel >= 6.10)
12
- splice
23
- sendto
34
- recvfrom
5+
- poll
6+
- tee
7+
- open / openat
8+
- fsync
9+
- mkdir / mkdirat
10+
- statx
11+
- link / linkat / unlink / unlinkat / symlink
12+
- rename / renameat
13+
- waitid
14+
- fadvise
15+
- madvise
16+
- getxattr / setxattr
17+
- shutdown
18+
- futex wait wake
419

520
- queues

ext/um/um.c

+37-9
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ struct op_ensure_ctx {
268268
void *read_buf;
269269
int read_maxlen;
270270
struct __kernel_timespec ts;
271+
int flags;
271272
};
272273

273274
VALUE um_timeout_ensure(VALUE arg) {
@@ -390,7 +391,7 @@ int um_read_each_safe_loop_singleshot(struct op_ensure_ctx *ctx, int total) {
390391
}
391392
}
392393

393-
int um_read_each_multishot_process_results(struct op_ensure_ctx *ctx, int *total) {
394+
int read_each_multishot_process_results(struct op_ensure_ctx *ctx, int *total) {
394395
__s32 result = 0;
395396
__u32 flags = 0;
396397
__s32 bad_result = 0;
@@ -441,7 +442,7 @@ VALUE um_read_each_safe_loop(VALUE arg) {
441442
if (!ctx->op->list_results.head)
442443
rb_raise(rb_eRuntimeError, "no result found!\n");
443444

444-
if (!um_read_each_multishot_process_results(ctx, &total))
445+
if (!read_each_multishot_process_results(ctx, &total))
445446
return INT2NUM(total);
446447
}
447448
}
@@ -539,7 +540,6 @@ VALUE um_socket(struct um *machine, int domain, int type, int protocol, uint fla
539540
int result = 0;
540541

541542
io_uring_prep_socket(sqe, domain, type, protocol, flags);
542-
543543
um_await_op(machine, op, &result, NULL);
544544

545545
um_raise_on_error_result(result);
@@ -552,7 +552,6 @@ VALUE um_connect(struct um *machine, int fd, const struct sockaddr *addr, sockle
552552
int result = 0;
553553

554554
io_uring_prep_connect(sqe, fd, addr, addrlen);
555-
556555
um_await_op(machine, op, &result, NULL);
557556

558557
um_raise_on_error_result(result);
@@ -565,7 +564,6 @@ VALUE um_send(struct um *machine, int fd, VALUE buffer, int len, int flags) {
565564
int result = 0;
566565

567566
io_uring_prep_send(sqe, fd, RSTRING_PTR(buffer), len, flags);
568-
569567
um_await_op(machine, op, &result, NULL);
570568

571569
um_raise_on_error_result(result);
@@ -579,21 +577,52 @@ VALUE um_recv(struct um *machine, int fd, VALUE buffer, int maxlen, int flags) {
579577

580578
void *ptr = um_prepare_read_buffer(buffer, maxlen, 0);
581579
io_uring_prep_recv(sqe, fd, ptr, maxlen, flags);
582-
583580
um_await_op(machine, op, &result, NULL);
584581

585582
um_raise_on_error_result(result);
586583
um_update_read_buffer(machine, buffer, 0, result, flags);
587584
return INT2NUM(result);
588585
}
589586

587+
static inline void recv_each_prepare_op(struct op_ensure_ctx *ctx) {
588+
struct um_op *op = um_op_idle_checkout(ctx->machine, OP_RECV_MULTISHOT);
589+
struct io_uring_sqe *sqe = um_get_sqe(ctx->machine, op);
590+
io_uring_prep_recv_multishot(sqe, ctx->fd, 0, -1, ctx->bgid);
591+
sqe->buf_group = ctx->bgid;
592+
sqe->flags |= IOSQE_BUFFER_SELECT;
593+
op->flags |= OP_F_MULTISHOT;
594+
ctx->op = op;
595+
}
596+
597+
VALUE recv_each_safe_loop(VALUE arg) {
598+
struct op_ensure_ctx *ctx = (struct op_ensure_ctx *)arg;
599+
int total = 0;
600+
recv_each_prepare_op(ctx);
601+
602+
while (1) {
603+
um_await_op(ctx->machine, ctx->op, NULL, NULL);
604+
if (!ctx->op->aux)
605+
rb_raise(rb_eRuntimeError, "no associated schedule op found");
606+
ctx->op->aux = NULL;
607+
if (!ctx->op->list_results.head)
608+
rb_raise(rb_eRuntimeError, "no result found!\n");
609+
610+
if (!read_each_multishot_process_results(ctx, &total))
611+
return INT2NUM(total);
612+
}
613+
}
614+
615+
VALUE um_recv_each(struct um *machine, int fd, int bgid, int flags) {
616+
struct op_ensure_ctx ctx = { .machine = machine, .fd = fd, .bgid = bgid, .read_buf = NULL, .flags = flags };
617+
return rb_ensure(recv_each_safe_loop, (VALUE)&ctx, um_multishot_ensure, (VALUE)&ctx);
618+
}
619+
590620
VALUE um_bind(struct um *machine, int fd, struct sockaddr *addr, socklen_t addrlen) {
591621
struct um_op *op = um_op_idle_checkout(machine, OP_BIND);
592622
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
593623
int result = 0;
594624

595625
io_uring_prep_bind(sqe, fd, addr, addrlen);
596-
597626
um_await_op(machine, op, &result, NULL);
598627

599628
um_raise_on_error_result(result);
@@ -606,7 +635,6 @@ VALUE um_listen(struct um *machine, int fd, int backlog) {
606635
int result = 0;
607636

608637
io_uring_prep_listen(sqe, fd, backlog);
609-
610638
um_await_op(machine, op, &result, NULL);
611639

612640
um_raise_on_error_result(result);
@@ -660,4 +688,4 @@ VALUE um_debug(struct um *machine) {
660688
printf("scheduled head %p tail %p\n", machine->list_scheduled.head, machine->list_scheduled.tail);
661689
printf("\n");
662690
return machine->self;
663-
}
691+
}

ext/um/um.h

+1
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ VALUE um_socket(struct um *machine, int domain, int type, int protocol, uint fla
178178
VALUE um_connect(struct um *machine, int fd, const struct sockaddr *addr, socklen_t addrlen);
179179
VALUE um_send(struct um *machine, int fd, VALUE buffer, int len, int flags);
180180
VALUE um_recv(struct um *machine, int fd, VALUE buffer, int maxlen, int flags);
181+
VALUE um_recv_each(struct um *machine, int fd, int bgid, int flags);
181182
VALUE um_bind(struct um *machine, int fd, struct sockaddr *addr, socklen_t addrlen);
182183
VALUE um_listen(struct um *machine, int fd, int backlog);
183184
VALUE um_getsockopt(struct um *machine, int fd, int level, int opt);

ext/um/um_class.c

+6
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,11 @@ VALUE UM_recv(VALUE self, VALUE fd, VALUE buffer, VALUE maxlen, VALUE flags) {
166166
return um_recv(machine, NUM2INT(fd), buffer, NUM2INT(maxlen), NUM2INT(flags));
167167
}
168168

169+
VALUE UM_recv_each(VALUE self, VALUE fd, VALUE bgid, VALUE flags) {
170+
struct um *machine = get_machine(self);
171+
return um_recv_each(machine, NUM2INT(fd), NUM2INT(bgid), NUM2INT(flags));
172+
}
173+
169174
VALUE UM_bind(VALUE self, VALUE fd, VALUE host, VALUE port) {
170175
struct sockaddr_in addr;
171176
memset(&addr, 0, sizeof(addr));
@@ -250,6 +255,7 @@ void Init_UM(void) {
250255
rb_define_method(cUM, "connect", UM_connect, 3);
251256
rb_define_method(cUM, "send", UM_send, 4);
252257
rb_define_method(cUM, "recv", UM_recv, 4);
258+
rb_define_method(cUM, "recv_each", UM_recv_each, 3);
253259
rb_define_method(cUM, "bind", UM_bind, 3);
254260
rb_define_method(cUM, "listen", UM_listen, 2);
255261
rb_define_method(cUM, "getsockopt", UM_getsockopt, 3);

test/test_um.rb

+43
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,49 @@ def test_recv
574574
end
575575
end
576576

577+
class RecvEachTest < UMBaseTest
578+
def setup
579+
super
580+
@port = assign_port
581+
@server = TCPServer.open('127.0.0.1', @port)
582+
end
583+
584+
def teardown
585+
@server&.close
586+
super
587+
end
588+
589+
def test_recv_each
590+
t = Thread.new do
591+
conn = @server.accept
592+
conn.write('abc')
593+
sleep 0.01
594+
conn.write('def')
595+
sleep 0.01
596+
conn.write('ghi')
597+
sleep 0.01
598+
conn.close
599+
sleep
600+
end
601+
602+
fd = machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
603+
res = machine.connect(fd, '127.0.0.1', @port)
604+
assert_equal 0, res
605+
606+
bgid = machine.setup_buffer_ring(4096, 1024)
607+
assert_equal 0, bgid
608+
609+
bufs = []
610+
611+
machine.recv_each(fd, bgid, 0) do |buf|
612+
bufs << buf
613+
end
614+
assert_equal ['abc', 'def', 'ghi'], bufs
615+
ensure
616+
t&.kill
617+
end
618+
end
619+
577620
class BindTest < UMBaseTest
578621
def setup
579622
super

0 commit comments

Comments
 (0)