uringmachine 0.29.2 → 0.31.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.
@@ -62,10 +62,10 @@ end
62
62
 
63
63
  require 'stringio'
64
64
 
65
- RE_REQUEST_LINE = /^([a-z]+)\s+([^\s]+)\s+(http\/[0-9\.]{1,3})/i
65
+ RE_REQUEST_LINE = /^([a-z]+)\s+([^\s]+)\s+(http\/1\.1)/i
66
66
  RE_HEADER_LINE = /^([a-z0-9\-]+)\:\s+(.+)/i
67
67
 
68
- def get_line(fd, sio, buffer)
68
+ def read_line(fd, sio, buffer)
69
69
  while true
70
70
  line = sio.gets(chomp: true)
71
71
  return line if line
@@ -76,7 +76,7 @@ def get_line(fd, sio, buffer)
76
76
  end
77
77
 
78
78
  def get_request_line(fd, sio, buffer)
79
- line = get_line(fd, sio, buffer)
79
+ line = read_line(fd, sio, buffer)
80
80
 
81
81
  m = line.match(RE_REQUEST_LINE)
82
82
  return nil if !m
@@ -96,7 +96,7 @@ def parse_headers(fd)
96
96
  return nil if !headers
97
97
 
98
98
  while true
99
- line = get_line(fd, sio, buffer)
99
+ line = read_line(fd, sio, buffer)
100
100
  break if line.empty?
101
101
 
102
102
  m = line.match(RE_HEADER_LINE)
@@ -129,15 +129,15 @@ ensure
129
129
  ($machine.close(wfd) rescue nil) if wfd
130
130
  end
131
131
 
132
- def stream_parse_headers(fd)
133
- stream = UM::Stream.new($machine, fd)
132
+ def connection_parse_headers(fd)
133
+ conn = UM::Connection.new($machine, fd)
134
134
 
135
135
  buf = String.new(capacity: 65536)
136
- headers = stream_get_request_line(stream, buf)
136
+ headers = connection_get_request_line(conn, buf)
137
137
  return nil if !headers
138
138
 
139
139
  while true
140
- line = stream.get_line(buf, 0)
140
+ line = conn.read_line(0)
141
141
  break if line.empty?
142
142
 
143
143
  m = line.match(RE_HEADER_LINE)
@@ -149,8 +149,8 @@ def stream_parse_headers(fd)
149
149
  headers
150
150
  end
151
151
 
152
- def stream_get_request_line(stream, buf)
153
- line = stream.get_line(buf, 0)
152
+ def connection_get_request_line(conn, buf)
153
+ line = conn.read_line(0)
154
154
 
155
155
  m = line.match(RE_REQUEST_LINE)
156
156
  return nil if !m
@@ -162,12 +162,12 @@ def stream_get_request_line(stream, buf)
162
162
  }
163
163
  end
164
164
 
165
- def parse_http_stream
165
+ def parse_http_connection
166
166
  rfd, wfd = UM.pipe
167
167
  queue = UM::Queue.new
168
168
 
169
169
  $machine.spin do
170
- headers = stream_parse_headers(rfd)
170
+ headers = connection_parse_headers(rfd)
171
171
  $machine.push(queue, headers)
172
172
  rescue Exception => e
173
173
  p e
@@ -188,7 +188,7 @@ def compare_allocs
188
188
  p(
189
189
  alloc_http_parser: alloc_count { x.times { parse_http_parser } },
190
190
  alloc_stringio: alloc_count { x.times { parse_http_stringio } },
191
- alloc_stream: alloc_count { x.times { parse_http_stream } }
191
+ alloc_connection: alloc_count { x.times { parse_http_connection } }
192
192
  )
193
193
  ensure
194
194
  GC.enable
@@ -213,8 +213,8 @@ def benchmark
213
213
  x.config(:time => 5, :warmup => 3)
214
214
 
215
215
  x.report("http_parser") { parse_http_parser }
216
- x.report("stringio") { parse_http_stringio }
217
- x.report("stream") { parse_http_stream }
216
+ x.report("stringio") { parse_http_stringio }
217
+ x.report("connection") { parse_http_connection }
218
218
 
219
219
  x.compare!
220
220
  end
@@ -12,8 +12,8 @@ require 'uringmachine'
12
12
  RE_REQUEST_LINE = /^([a-z]+)\s+([^\s]+)\s+(http\/[0-9\.]{1,3})/i
13
13
  RE_HEADER_LINE = /^([a-z0-9\-]+)\:\s+(.+)/i
14
14
 
15
- def stream_get_request_line(stream, buf)
16
- line = stream.get_line(buf, 0)
15
+ def connection_get_request_line(conn, buf)
16
+ line = conn.read_line(0)
17
17
  m = line&.match(RE_REQUEST_LINE)
18
18
  return nil if !m
19
19
 
@@ -26,12 +26,12 @@ end
26
26
 
27
27
  class InvalidHeadersError < StandardError; end
28
28
 
29
- def get_headers(stream, buf)
30
- headers = stream_get_request_line(stream, buf)
29
+ def get_headers(conn, buf)
30
+ headers = connection_get_request_line(conn, buf)
31
31
  return nil if !headers
32
32
 
33
33
  while true
34
- line = stream.get_line(buf, 0)
34
+ line = conn.read_line(0)
35
35
  break if line.empty?
36
36
 
37
37
  m = line.match(RE_HEADER_LINE)
@@ -51,17 +51,21 @@ def send_response(machine, fd)
51
51
  end
52
52
 
53
53
  def handle_connection(machine, fd)
54
- stream = UM::Stream.new(machine, fd)
54
+ conn = UM::Connection.new(machine, fd)
55
55
  buf = String.new(capacity: 65536)
56
56
 
57
57
  while true
58
- headers = get_headers(stream, buf)
58
+ headers = get_headers(conn, buf)
59
59
  break if !headers
60
60
 
61
61
  send_response(machine, fd)
62
62
  end
63
63
  rescue InvalidHeadersError, SystemCallError => e
64
64
  # ignore
65
+ rescue => e
66
+ p e
67
+ p e.backtrace
68
+ exit!
65
69
  ensure
66
70
  machine.close_async(fd)
67
71
  end
@@ -12,8 +12,8 @@ require 'uringmachine'
12
12
  RE_REQUEST_LINE = /^([a-z]+)\s+([^\s]+)\s+(http\/[0-9\.]{1,3})/i
13
13
  RE_HEADER_LINE = /^([a-z0-9\-]+)\:\s+(.+)/i
14
14
 
15
- def stream_get_request_line(stream, buf)
16
- line = stream.get_line(buf, 0)
15
+ def connection_get_request_line(conn, buf)
16
+ line = conn.read_line(0)
17
17
  m = line&.match(RE_REQUEST_LINE)
18
18
  return nil if !m
19
19
 
@@ -26,12 +26,12 @@ end
26
26
 
27
27
  class InvalidHeadersError < StandardError; end
28
28
 
29
- def get_headers(stream, buf)
30
- headers = stream_get_request_line(stream, buf)
29
+ def get_headers(conn, buf)
30
+ headers = connection_get_request_line(conn, buf)
31
31
  return nil if !headers
32
32
 
33
33
  while true
34
- line = stream.get_line(buf, 0)
34
+ line = conn.read_line(0)
35
35
  break if line.empty?
36
36
 
37
37
  m = line.match(RE_HEADER_LINE)
@@ -51,11 +51,11 @@ def send_response(machine, fd)
51
51
  end
52
52
 
53
53
  def handle_connection(machine, fd)
54
- stream = UM::Stream.new(machine, fd)
54
+ conn = UM::Connection.new(machine, fd)
55
55
  buf = String.new(capacity: 65536)
56
56
 
57
57
  while true
58
- headers = get_headers(stream, buf)
58
+ headers = get_headers(conn, buf)
59
59
  break if !headers
60
60
 
61
61
  send_response(machine, fd)
@@ -12,8 +12,8 @@ require 'uringmachine'
12
12
  RE_REQUEST_LINE = /^([a-z]+)\s+([^\s]+)\s+(http\/[0-9\.]{1,3})/i
13
13
  RE_HEADER_LINE = /^([a-z0-9\-]+)\:\s+(.+)/i
14
14
 
15
- def stream_get_request_line(stream, buf)
16
- line = stream.get_line(buf, 0)
15
+ def connection_get_request_line(conn, buf)
16
+ line = conn.read_line(0)
17
17
  m = line&.match(RE_REQUEST_LINE)
18
18
  return nil if !m
19
19
 
@@ -26,12 +26,12 @@ end
26
26
 
27
27
  class InvalidHeadersError < StandardError; end
28
28
 
29
- def get_headers(stream, buf)
30
- headers = stream_get_request_line(stream, buf)
29
+ def get_headers(conn, buf)
30
+ headers = connection_get_request_line(conn, buf)
31
31
  return nil if !headers
32
32
 
33
33
  while true
34
- line = stream.get_line(buf, 0)
34
+ line = conn.read_line(0)
35
35
  break if line.empty?
36
36
 
37
37
  m = line.match(RE_HEADER_LINE)
@@ -53,11 +53,11 @@ end
53
53
 
54
54
  def handle_connection(machine, fd)
55
55
  machine.setsockopt(fd, UM::IPPROTO_TCP, UM::TCP_NODELAY, true)
56
- stream = UM::Stream.new(machine, fd)
56
+ conn = UM::Connection.new(machine, fd)
57
57
  buf = String.new(capacity: 65536)
58
58
 
59
59
  while true
60
- headers = get_headers(stream, buf)
60
+ headers = get_headers(conn, buf)
61
61
  break if !headers
62
62
 
63
63
  send_response(machine, fd)
@@ -12,8 +12,8 @@ require 'uringmachine'
12
12
  RE_REQUEST_LINE = /^([a-z]+)\s+([^\s]+)\s+(http\/[0-9\.]{1,3})/i
13
13
  RE_HEADER_LINE = /^([a-z0-9\-]+)\:\s+(.+)/i
14
14
 
15
- def stream_get_request_line(stream, buf)
16
- line = stream.get_line(buf, 0)
15
+ def connection_get_request_line(conn, buf)
16
+ line = conn.read_line(0)
17
17
  m = line&.match(RE_REQUEST_LINE)
18
18
  return nil if !m
19
19
 
@@ -26,12 +26,12 @@ end
26
26
 
27
27
  class InvalidHeadersError < StandardError; end
28
28
 
29
- def get_headers(stream, buf)
30
- headers = stream_get_request_line(stream, buf)
29
+ def get_headers(conn, buf)
30
+ headers = connection_get_request_line(conn, buf)
31
31
  return nil if !headers
32
32
 
33
33
  while true
34
- line = stream.get_line(buf, 0)
34
+ line = conn.read_line(0)
35
35
  break if line.empty?
36
36
 
37
37
  m = line.match(RE_HEADER_LINE)
@@ -52,11 +52,11 @@ end
52
52
 
53
53
  def handle_connection(machine, fd)
54
54
  machine.setsockopt(fd, UM::IPPROTO_TCP, UM::TCP_NODELAY, true)
55
- stream = UM::Stream.new(machine, fd)
55
+ conn = UM::Connection.new(machine, fd)
56
56
  buf = String.new(capacity: 65536)
57
57
 
58
58
  while true
59
- headers = get_headers(stream, buf)
59
+ headers = get_headers(conn, buf)
60
60
  break if !headers
61
61
 
62
62
  send_response(machine, fd)
data/benchmark/openssl.rb CHANGED
@@ -24,54 +24,82 @@ Socket.do_not_reverse_lookup = true
24
24
  tcps = TCPServer.new("127.0.0.1", 0)
25
25
  port = tcps.connect_address.ip_port
26
26
 
27
- ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx)
28
-
29
- Thread.new do
30
- Thread.current.report_on_exception = false
31
- loop do
32
- begin
33
- ssl = ssls.accept
34
- rescue OpenSSL::SSL::SSLError, IOError, Errno::EBADF, Errno::EINVAL,
35
- Errno::ECONNABORTED, Errno::ENOTSOCK, Errno::ECONNRESET
36
- retry
37
- end
38
-
39
- Thread.new do
40
- Thread.current.report_on_exception = false
27
+ pid = fork do
28
+ ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx)
41
29
 
30
+ Thread.new do
31
+ Thread.current.report_on_exception = false
32
+ loop do
42
33
  begin
43
- while line = ssl.gets
44
- ssl.write(line)
34
+ ssl = ssls.accept
35
+ rescue OpenSSL::SSL::SSLError, IOError, Errno::EBADF, Errno::EINVAL,
36
+ Errno::ECONNABORTED, Errno::ENOTSOCK, Errno::ECONNRESET
37
+ retry
38
+ end
39
+
40
+ Thread.new do
41
+ Thread.current.report_on_exception = false
42
+
43
+ begin
44
+ while line = ssl.gets
45
+ ssl.write(line)
46
+ end
47
+ ensure
48
+ ssl.close
45
49
  end
46
- ensure
47
- ssl.close
50
+ true
48
51
  end
49
- true
50
52
  end
51
53
  end
54
+ sleep
55
+ rescue Interrupt
52
56
  end
53
57
 
54
- @ssl_stock = OpenSSL::SSL::SSLSocket.open("127.0.0.1", port)
58
+ at_exit {
59
+ Process.kill('SIGINT', pid)
60
+ Process.wait(pid)
61
+ }
62
+
63
+ begin
64
+ @ssl_stock = OpenSSL::SSL::SSLSocket.open("127.0.0.1", port)
65
+ rescue => e
66
+ p e
67
+ exit!
68
+ end
55
69
  @ssl_stock.sync_close = true
56
70
  @ssl_stock.connect
57
71
 
58
- um = UM.new
72
+ @um = UM.new
59
73
 
60
74
  @ssl_um = OpenSSL::SSL::SSLSocket.open("127.0.0.1", port)
61
75
  @ssl_um.sync_close = true
62
- um.ssl_set_bio(@ssl_um)
76
+ @um.ssl_set_bio(@ssl_um)
63
77
  @ssl_um.connect
64
78
 
79
+ @ssl_conn = OpenSSL::SSL::SSLSocket.open("127.0.0.1", port)
80
+ @ssl_conn.sync_close = true
81
+ @um.ssl_set_bio(@ssl_conn)
82
+ @ssl_conn.connect
83
+
84
+ @conn = @um.connection(@ssl_conn, :ssl)
85
+
65
86
  @msg = 'abc' * 1000
87
+ @msg_newline = @msg + "\n"
66
88
 
67
89
  def do_io(ssl)
68
90
  ssl.puts @msg
69
91
  ssl.gets
70
92
  end
71
93
 
94
+ def do_io_connection(ssl, um, conn)
95
+ um.ssl_write(ssl, @msg_newline, 0)
96
+ conn.read_line(0)
97
+ end
98
+
72
99
  Benchmark.ips do |x|
73
100
  x.report('stock') { do_io(@ssl_stock) }
74
101
  x.report('UM BIO') { do_io(@ssl_um) }
102
+ x.report('UM Stream') { do_io_connection(@ssl_conn, @um, @conn) }
75
103
 
76
104
  x.compare!(order: :baseline)
77
105
  end
@@ -78,7 +78,7 @@ buffers, to using managed buffers from the buffer pool.
78
78
  ```ruby
79
79
  machine.stream_recv(fd) do |stream|
80
80
  loop do
81
- line = stream.get_line(max: 60)
81
+ line = stream.read_line(max: 60)
82
82
  if (size = parse_size(line))
83
83
  data = stream.read(size)
84
84
  process_data(data)
@@ -0,0 +1,52 @@
1
+ @runqueue = []
2
+ @active_reads = {}; @active_timers = {}
3
+
4
+ def fiber_switch
5
+ while true
6
+ next_fiber, value = @runqueue.shift
7
+ return next_fiber.transfer value if next_fiber
8
+
9
+ process_events
10
+ end
11
+ end
12
+
13
+ def process_events
14
+ shortest_timeout = @active_timers.values.min - Time.now
15
+ process_reads(shortest_timeout)
16
+ now = Time.now
17
+ @active_timers.select { |_, t| t <= now }.keys.each {
18
+ @runqueue << it
19
+ @active_timers.delete(it)
20
+ }
21
+ end
22
+
23
+ def process_reads(timeout)
24
+ r, _ = IO.select(@active_reads.keys, [], [], timeout)
25
+ r&.each { |io|
26
+ @runqueue << [@active_reads[io], io.readpartial(256)]
27
+ @active_reads.delete(io)
28
+ }
29
+ end
30
+
31
+ def do_read(io)
32
+ @active_reads[io] = Fiber.current
33
+ fiber_switch
34
+ end
35
+
36
+ def do_sleep(time)
37
+ fiber = Fiber.current
38
+ @active_timers[fiber] = Time.now + time
39
+ fiber_switch
40
+ end
41
+
42
+ @runqueue << Fiber.new {
43
+ input = do_read(STDIN)
44
+ puts "Got: #{input}"
45
+ }
46
+
47
+ @runqueue << Fiber.new {
48
+ do_sleep(5)
49
+ puts "5 seconds have elapsed!"
50
+ }
51
+
52
+ fiber_switch
@@ -0,0 +1,26 @@
1
+ @fiber1 = Fiber.new {
2
+ count = 0
3
+ # read from STDIN
4
+ while true
5
+ count += 1
6
+ input = STDIN.read_nonblock(256, exception: false)
7
+ if input == :wait_readable
8
+ @fiber2.transfer
9
+ else
10
+ break
11
+ end
12
+ end
13
+ puts "Got: #{input} after #{count} tries"
14
+ }
15
+
16
+ @fiber2 = Fiber.new {
17
+ last = Time.now
18
+
19
+ # sleep
20
+ while Time.now < last + 5
21
+ @fiber1.transfer
22
+ end
23
+ STDOUT << "5 seconds have elapsed!\n"
24
+ }
25
+
26
+ @fiber1.transfer
@@ -0,0 +1,33 @@
1
+ @runqueue = []
2
+ def fiber_switch
3
+ next_fiber = @runqueue.shift
4
+ @runqueue << Fiber.current
5
+ next_fiber.transfer
6
+ end
7
+
8
+ @runqueue << Fiber.new {
9
+ count = 0
10
+ # read from STDIN
11
+ while true
12
+ count += 1
13
+ input = STDIN.read_nonblock(256, exception: false)
14
+ if input == :wait_readable
15
+ fiber_switch
16
+ else
17
+ break
18
+ end
19
+ end
20
+ puts "Got: #{input} after #{count} tries"
21
+ }
22
+
23
+ @runqueue << Fiber.new {
24
+ last = Time.now
25
+
26
+ # sleep
27
+ while Time.now < last + 10
28
+ fiber_switch
29
+ end
30
+ STDOUT << "10 seconds have elapsed!\n"
31
+ }
32
+
33
+ @runqueue.shift.transfer
@@ -0,0 +1,24 @@
1
+ #include <liburing.h>
2
+
3
+ struct io_uring ring;
4
+ struct io_uring_sqe *sqe;
5
+ struct io_uring_cqe *cqe;
6
+ int ret;
7
+ char buf[100];
8
+
9
+ ret = io_uring_queue_init(8, &ring, 0);
10
+ sqe = io_uring_get_sqe(&ring);
11
+ io_uring_prep_read(sqe, STDIN_FILENO, buf, 100, 0);
12
+ sqe->user_data = 42;
13
+ io_uring_submit(&ring);
14
+
15
+ ...
16
+
17
+ ret = io_uring_wait_cqe(&ring, &cqe);
18
+ if (!ret) {
19
+ if (cqe->user_data == 42) {
20
+ int len = cqe->res;
21
+ printf("Got: %d\n", len);
22
+ }
23
+ io_uring_cqe_seen(&ring, cqe);
24
+ }
data/examples/pg.rb CHANGED
@@ -66,9 +66,9 @@ $machine.listen(server_fd, UM::SOMAXCONN)
66
66
  puts 'Listening on port 1234'
67
67
 
68
68
  def handle_connection(fd)
69
- stream = UM::Stream.new($machine, fd)
69
+ conn = UM::Connection.new($machine, fd)
70
70
 
71
- while (l = stream.gets)
71
+ while (l = conn.gets)
72
72
  $machine.write(fd, "You said: #{l}")
73
73
  end
74
74
  rescue Exception => e
data/examples/stream.rb CHANGED
@@ -66,9 +66,9 @@ $machine.listen(server_fd, UM::SOMAXCONN)
66
66
  puts 'Listening on port 1234'
67
67
 
68
68
  def handle_connection(fd)
69
- stream = UM::Stream.new($machine, fd)
69
+ conn = UM::Stream.new($machine, fd)
70
70
 
71
- while (l = stream.gets)
71
+ while (l = conn.gets)
72
72
  $machine.write(fd, "You said: #{l}")
73
73
  end
74
74
  rescue Exception => e
data/ext/um/um.c CHANGED
@@ -652,11 +652,11 @@ VALUE um_write(struct um *machine, int fd, VALUE buffer, size_t len, __u64 file_
652
652
  return ret;
653
653
  }
654
654
 
655
- size_t um_write_raw(struct um *machine, int fd, const char *buffer, size_t maxlen) {
655
+ size_t um_write_raw(struct um *machine, int fd, const char *buffer, size_t len) {
656
656
  struct um_op *op = um_op_acquire(machine);
657
657
  um_prep_op(machine, op, OP_WRITE, 2, 0);
658
658
  struct io_uring_sqe *sqe = um_get_sqe(machine, op);
659
- io_uring_prep_write(sqe, fd, buffer, maxlen, 0);
659
+ io_uring_prep_write(sqe, fd, buffer, len, 0);
660
660
 
661
661
  int res = 0;
662
662
  VALUE ret = um_yield(machine);
@@ -831,6 +831,23 @@ VALUE um_send(struct um *machine, int fd, VALUE buffer, size_t len, int flags) {
831
831
  return ret;
832
832
  }
833
833
 
834
+ size_t um_send_raw(struct um *machine, int fd, const char *buffer, size_t len, int flags) {
835
+ struct um_op *op = um_op_acquire(machine);
836
+ um_prep_op(machine, op, OP_SEND, 2, 0);
837
+ struct io_uring_sqe *sqe = um_get_sqe(machine, op);
838
+ io_uring_prep_send(sqe, fd, buffer, len, flags);
839
+
840
+ int res = 0;
841
+ VALUE ret = um_yield(machine);
842
+
843
+ if (likely(um_verify_op_completion(machine, op, true))) res = op->result.res;
844
+ um_op_release(machine, op);
845
+
846
+ RAISE_IF_EXCEPTION(ret);
847
+ RB_GC_GUARD(ret);
848
+ return res;
849
+ }
850
+
834
851
  // for some reason we don't get this define from liburing/io_uring.h
835
852
  #define IORING_SEND_VECTORIZED (1U << 5)
836
853
 
@@ -1285,6 +1302,57 @@ VALUE um_statx(struct um *machine, int dirfd, VALUE path, int flags, unsigned in
1285
1302
  return statx_to_hash(&stat);
1286
1303
  }
1287
1304
 
1305
+ VALUE um_splice(struct um *machine, int in_fd, int out_fd, uint nbytes) {
1306
+ struct um_op *op = um_op_acquire(machine);
1307
+ um_prep_op(machine, op, OP_SPLICE, 2, 0);
1308
+ struct io_uring_sqe *sqe = um_get_sqe(machine, op);
1309
+ io_uring_prep_splice(sqe, in_fd, -1, out_fd, -1, nbytes, 0);
1310
+
1311
+ VALUE ret = um_yield(machine);
1312
+
1313
+ if (likely(um_verify_op_completion(machine, op, false))) ret = INT2NUM(op->result.res);
1314
+ um_op_release(machine, op);
1315
+
1316
+ RAISE_IF_EXCEPTION(ret);
1317
+ RB_GC_GUARD(ret);
1318
+
1319
+ return ret;
1320
+ }
1321
+
1322
+ VALUE um_tee(struct um *machine, int in_fd, int out_fd, uint nbytes) {
1323
+ struct um_op *op = um_op_acquire(machine);
1324
+ um_prep_op(machine, op, OP_TEE, 2, 0);
1325
+ struct io_uring_sqe *sqe = um_get_sqe(machine, op);
1326
+ io_uring_prep_tee(sqe, in_fd, out_fd, nbytes, 0);
1327
+
1328
+ VALUE ret = um_yield(machine);
1329
+
1330
+ if (likely(um_verify_op_completion(machine, op, false))) ret = INT2NUM(op->result.res);
1331
+ um_op_release(machine, op);
1332
+
1333
+ RAISE_IF_EXCEPTION(ret);
1334
+ RB_GC_GUARD(ret);
1335
+
1336
+ return ret;
1337
+ }
1338
+
1339
+ VALUE um_fsync(struct um *machine, int fd) {
1340
+ struct um_op *op = um_op_acquire(machine);
1341
+ um_prep_op(machine, op, OP_FSYNC, 2, 0);
1342
+ struct io_uring_sqe *sqe = um_get_sqe(machine, op);
1343
+ io_uring_prep_fsync(sqe, fd, 0);
1344
+
1345
+ VALUE ret = um_yield(machine);
1346
+
1347
+ if (likely(um_verify_op_completion(machine, op, false))) ret = INT2NUM(op->result.res);
1348
+ um_op_release(machine, op);
1349
+
1350
+ RAISE_IF_EXCEPTION(ret);
1351
+ RB_GC_GUARD(ret);
1352
+
1353
+ return ret;
1354
+ }
1355
+
1288
1356
  /*******************************************************************************
1289
1357
  multishot ops
1290
1358
  *******************************************************************************/
@@ -1427,7 +1495,7 @@ int read_recv_each_multishot_process_result(struct op_ctx *ctx, struct um_op_res
1427
1495
  return false;
1428
1496
 
1429
1497
  *total += result->res;
1430
- VALUE buf = um_get_string_from_buffer_ring(ctx->machine, ctx->bgid, result->res, result->flags);
1498
+ VALUE buf = um_read_from_buffer_ring(ctx->machine, ctx->bgid, result->res, result->flags);
1431
1499
  rb_yield(buf);
1432
1500
  RB_GC_GUARD(buf);
1433
1501