From a6c88da10da34ee93945a5f652dbf5da99b1c8ad Mon Sep 17 00:00:00 2001 From: Sharon Rosner Date: Wed, 13 Nov 2024 11:01:26 +0100 Subject: [PATCH] Implement UM#add --- CHANGELOG.md | 6 ++++++ ext/um/um.c | 14 +++++++++++++ ext/um/um.h | 1 + ext/um/um_class.c | 53 +++++++++++++++++++++++++++++++++-------------- ext/um/um_const.c | 20 ++++++++++++++++++ test/test_um.rb | 30 +++++++++++++++++++++++++++ 6 files changed, 109 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6454571..ca3649c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +- Add `#open` +- Fix `#spin` +- Fix handling of signal interruption. +- Reimplement and simplify um_op +- Add `UM::Queue`, `#push`, `#pop`, `#shift`, `#unshift` +- Add `UM::Mutex`, `#synchronize` - Add `#recv_each` - Add `#getsockopt`, `#setsockopt` - Simplify and improve op management diff --git a/ext/um/um.c b/ext/um/um.c index de77fd5..434ecd3 100644 --- a/ext/um/um.c +++ b/ext/um/um.c @@ -499,6 +499,20 @@ VALUE um_setsockopt(struct um *machine, int fd, int level, int opt, int value) { return raise_if_exception(ret); } +VALUE um_open(struct um *machine, VALUE pathname, int flags, int mode) { + struct um_op op; + um_prep_op(machine, &op, OP_BIND); + struct io_uring_sqe *sqe = um_get_sqe(machine, &op); + io_uring_prep_open(sqe, StringValueCStr(pathname), flags, mode); + + VALUE ret = um_fiber_switch(machine); + if (um_check_completion(machine, &op)) + ret = INT2NUM(op.result.res); + + RB_GC_GUARD(ret); + return raise_if_exception(ret); +} + /******************************************************************************* multishot ops *******************************************************************************/ diff --git a/ext/um/um.h b/ext/um/um.h index 541d2f6..543d047 100644 --- a/ext/um/um.h +++ b/ext/um/um.h @@ -192,6 +192,7 @@ VALUE um_read(struct um *machine, int fd, VALUE buffer, int maxlen, int buffer_o VALUE um_read_each(struct um *machine, int fd, int bgid); VALUE um_write(struct um *machine, int fd, VALUE str, int len); VALUE um_close(struct um *machine, int fd); +VALUE um_open(struct um *machine, VALUE pathname, int flags, int mode); VALUE um_accept(struct um *machine, int fd); VALUE um_accept_each(struct um *machine, int fd); diff --git a/ext/um/um_class.c b/ext/um/um_class.c index 83fc795..18178de 100644 --- a/ext/um/um_class.c +++ b/ext/um/um_class.c @@ -258,6 +258,28 @@ VALUE UM_queue_shift(VALUE self, VALUE queue) { #endif +struct um_open_ctx { + VALUE self; + VALUE fd; +}; + +VALUE UM_open_ensure(VALUE arg) { + struct um_open_ctx *ctx = (struct um_open_ctx *)arg; + UM_close(ctx->self, ctx->fd); + return ctx->self; +} + +VALUE UM_open(VALUE self, VALUE pathname, VALUE flags) { + struct um *machine = get_machine(self); + VALUE ret = um_open(machine, pathname, NUM2INT(flags), S_IRWXU); + if (rb_block_given_p()) { + struct um_open_ctx ctx = { self, ret }; + return rb_ensure(rb_yield, ret, UM_open_ensure, (VALUE)&ctx); + } + else + return ret; +} + VALUE UM_kernel_version(VALUE self) { return INT2NUM(UM_KERNEL_VERSION); } @@ -269,41 +291,42 @@ void Init_UM(void) { rb_define_alloc_func(cUM, UM_allocate); rb_define_method(cUM, "initialize", UM_initialize, 0); - rb_define_method(cUM, "setup_buffer_ring", UM_setup_buffer_ring, 2); rb_define_method(cUM, "pending_count", UM_pending_count, 0); + rb_define_method(cUM, "setup_buffer_ring", UM_setup_buffer_ring, 2); + rb_define_singleton_method(cUM, "kernel_version", UM_kernel_version, 0); + - rb_define_method(cUM, "snooze", UM_snooze, 0); - rb_define_method(cUM, "yield", UM_yield, 0); rb_define_method(cUM, "schedule", UM_schedule, 2); + rb_define_method(cUM, "snooze", UM_snooze, 0); rb_define_method(cUM, "timeout", UM_timeout, 2); + rb_define_method(cUM, "yield", UM_yield, 0); - rb_define_method(cUM, "sleep", UM_sleep, 1); + rb_define_method(cUM, "close", UM_close, 1); + rb_define_method(cUM, "open", UM_open, 2); rb_define_method(cUM, "read", UM_read, -1); rb_define_method(cUM, "read_each", UM_read_each, 2); + rb_define_method(cUM, "sleep", UM_sleep, 1); rb_define_method(cUM, "write", UM_write, -1); - rb_define_method(cUM, "close", UM_close, 1); rb_define_method(cUM, "accept", UM_accept, 1); rb_define_method(cUM, "accept_each", UM_accept_each, 1); - rb_define_method(cUM, "socket", UM_socket, 4); + rb_define_method(cUM, "bind", UM_bind, 3); rb_define_method(cUM, "connect", UM_connect, 3); - rb_define_method(cUM, "send", UM_send, 4); + rb_define_method(cUM, "getsockopt", UM_getsockopt, 3); + rb_define_method(cUM, "listen", UM_listen, 2); rb_define_method(cUM, "recv", UM_recv, 4); rb_define_method(cUM, "recv_each", UM_recv_each, 3); - rb_define_method(cUM, "bind", UM_bind, 3); - rb_define_method(cUM, "listen", UM_listen, 2); - rb_define_method(cUM, "getsockopt", UM_getsockopt, 3); + rb_define_method(cUM, "send", UM_send, 4); rb_define_method(cUM, "setsockopt", UM_setsockopt, 4); + rb_define_method(cUM, "socket", UM_socket, 4); #ifdef HAVE_IO_URING_PREP_FUTEX - rb_define_method(cUM, "synchronize", UM_mutex_synchronize, 1); - rb_define_method(cUM, "push", UM_queue_push, 2); rb_define_method(cUM, "pop", UM_queue_pop, 1); - rb_define_method(cUM, "unshift", UM_queue_unshift, 2); + rb_define_method(cUM, "push", UM_queue_push, 2); rb_define_method(cUM, "shift", UM_queue_shift, 1); + rb_define_method(cUM, "synchronize", UM_mutex_synchronize, 1); + rb_define_method(cUM, "unshift", UM_queue_unshift, 2); #endif - rb_define_singleton_method(cUM, "kernel_version", UM_kernel_version, 0); - um_define_net_constants(cUM); } diff --git a/ext/um/um_const.c b/ext/um/um_const.c index e3d8ece..624276b 100644 --- a/ext/um/um_const.c +++ b/ext/um/um_const.c @@ -1,4 +1,7 @@ #include "ruby.h" + +#include + #include #include #include @@ -12,6 +15,23 @@ #define DEF_CONST_INT(mod, v) rb_define_const(mod, #v, INT2NUM(v)) void um_define_net_constants(VALUE mod) { + DEF_CONST_INT(mod, O_APPEND); + DEF_CONST_INT(mod, O_CLOEXEC); + DEF_CONST_INT(mod, O_CREAT); + DEF_CONST_INT(mod, O_DIRECT); + DEF_CONST_INT(mod, O_DIRECTORY); + DEF_CONST_INT(mod, O_DSYNC); + DEF_CONST_INT(mod, O_EXCL); + DEF_CONST_INT(mod, O_NOCTTY); + DEF_CONST_INT(mod, O_NOFOLLOW); + DEF_CONST_INT(mod, O_PATH); + DEF_CONST_INT(mod, O_RDONLY); + DEF_CONST_INT(mod, O_RDWR); + DEF_CONST_INT(mod, O_SYNC); + DEF_CONST_INT(mod, O_TMPFILE); + DEF_CONST_INT(mod, O_TRUNC); + DEF_CONST_INT(mod, O_WRONLY); + DEF_CONST_INT(mod, SOCK_STREAM); DEF_CONST_INT(mod, SOCK_DGRAM); DEF_CONST_INT(mod, SOCK_RAW); diff --git a/test/test_um.rb b/test/test_um.rb index 26b9cb3..4252171 100644 --- a/test/test_um.rb +++ b/test/test_um.rb @@ -963,3 +963,33 @@ def test_shift_shift_1 end end +class OpenTest < UMBaseTest + PATH = '/tmp/um_open_test' + + def setup + super + FileUtils.rm(PATH, force: true) + end + + def test_open + fd = machine.open(PATH, UM::O_CREAT | UM::O_WRONLY) + assert_kind_of Integer, fd + assert File.file?(PATH) + + machine.write(fd, 'foo') + machine.close(fd) + + assert_equal 'foo', IO.read(PATH) + end + + def test_open_with_block + res = machine.open(PATH, UM::O_CREAT | UM::O_WRONLY) do |fd| + machine.write(fd, 'bar') + fd + end + + assert_kind_of Integer, res + assert_raises(Errno::EBADF) { machine.close(res) } + assert_equal 'bar', IO.read(PATH) + end +end \ No newline at end of file