From f3be084adf80ea7bcca2fb73ac139afb67112501 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20M=C3=BCller?= Date: Sat, 25 May 2024 11:07:37 +0200 Subject: [PATCH] Extract `#system_read` and `#system_write` for `FileDescriptor` and `Socket` (#14626) --- src/crystal/system/file_descriptor.cr | 4 ++++ src/crystal/system/socket.cr | 4 ++-- src/crystal/system/unix/file_descriptor.cr | 4 ++-- src/crystal/system/unix/socket.cr | 4 ++-- src/crystal/system/wasi/socket.cr | 4 ++-- src/crystal/system/win32/file_descriptor.cr | 22 +++++++++------------ src/crystal/system/win32/socket.cr | 4 ++-- src/io/evented.cr | 20 ++++++++----------- src/io/file_descriptor.cr | 10 ++++++++++ src/socket.cr | 10 ++++++++++ 10 files changed, 51 insertions(+), 35 deletions(-) diff --git a/src/crystal/system/file_descriptor.cr b/src/crystal/system/file_descriptor.cr index db50f1f3fd73..5497c3066803 100644 --- a/src/crystal/system/file_descriptor.cr +++ b/src/crystal/system/file_descriptor.cr @@ -13,6 +13,10 @@ module Crystal::System::FileDescriptor # For the duration of the block, enables raw mode if *enable* is true, enables # cooked mode otherwise. # private def system_raw(enable : Bool, & : ->) + + # private def system_read(slice : Bool) : Int32 + + # private def system_write(slice : Bool) : Int32 end {% if flag?(:wasi) %} diff --git a/src/crystal/system/socket.cr b/src/crystal/system/socket.cr index 8e91e18dbd4b..592045f2fbce 100644 --- a/src/crystal/system/socket.cr +++ b/src/crystal/system/socket.cr @@ -71,9 +71,9 @@ module Crystal::System::Socket # def self.fcntl(fd, cmd, arg = 0) - # private def unbuffered_read(slice : Bytes) : Int32 + # private def system_read(slice : Bytes) : Int32 - # private def unbuffered_write(slice : Bytes) : Nil + # private def system_write(slice : Bytes) : Int32 # private def system_close diff --git a/src/crystal/system/unix/file_descriptor.cr b/src/crystal/system/unix/file_descriptor.cr index 2a2f25951d6c..0501c1851522 100644 --- a/src/crystal/system/unix/file_descriptor.cr +++ b/src/crystal/system/unix/file_descriptor.cr @@ -17,7 +17,7 @@ module Crystal::System::FileDescriptor STDOUT_HANDLE = 1 STDERR_HANDLE = 2 - private def unbuffered_read(slice : Bytes) : Int32 + private def system_read(slice : Bytes) : Int32 evented_read(slice, "Error reading file") do LibC.read(fd, slice, slice.size).tap do |return_code| if return_code == -1 && Errno.value == Errno::EBADF @@ -27,7 +27,7 @@ module Crystal::System::FileDescriptor end end - private def unbuffered_write(slice : Bytes) : Nil + private def system_write(slice : Bytes) : Int32 evented_write(slice, "Error writing file") do |slice| LibC.write(fd, slice, slice.size).tap do |return_code| if return_code == -1 && Errno.value == Errno::EBADF diff --git a/src/crystal/system/unix/socket.cr b/src/crystal/system/unix/socket.cr index 4a66c4dd2b1d..0e7c79b120a1 100644 --- a/src/crystal/system/unix/socket.cr +++ b/src/crystal/system/unix/socket.cr @@ -250,13 +250,13 @@ module Crystal::System::Socket LibC.isatty(fd) == 1 end - private def unbuffered_read(slice : Bytes) : Int32 + private def system_read(slice : Bytes) : Int32 evented_read(slice, "Error reading socket") do LibC.recv(fd, slice, slice.size, 0).to_i32 end end - private def unbuffered_write(slice : Bytes) : Nil + private def system_write(slice : Bytes) : Int32 evented_write(slice, "Error writing to socket") do |slice| LibC.send(fd, slice, slice.size, 0) end diff --git a/src/crystal/system/wasi/socket.cr b/src/crystal/system/wasi/socket.cr index 239ab4a9fdbd..124c019520b8 100644 --- a/src/crystal/system/wasi/socket.cr +++ b/src/crystal/system/wasi/socket.cr @@ -161,13 +161,13 @@ module Crystal::System::Socket LibC.isatty(fd) == 1 end - private def unbuffered_read(slice : Bytes) : Int32 + private def system_read(slice : Bytes) : Int32 evented_read(slice, "Error reading socket") do LibC.recv(fd, slice, slice.size, 0).to_i32 end end - private def unbuffered_write(slice : Bytes) : Nil + private def system_write(slice : Bytes) : Int32 evented_write(slice, "Error writing to socket") do |slice| LibC.send(fd, slice, slice.size, 0) end diff --git a/src/crystal/system/win32/file_descriptor.cr b/src/crystal/system/win32/file_descriptor.cr index 53b3c6eb3d1b..97f1242f2ef8 100644 --- a/src/crystal/system/win32/file_descriptor.cr +++ b/src/crystal/system/win32/file_descriptor.cr @@ -19,7 +19,7 @@ module Crystal::System::FileDescriptor @system_blocking = true - private def unbuffered_read(slice : Bytes) : Int32 + private def system_read(slice : Bytes) : Int32 handle = windows_handle if ConsoleUtils.console?(handle) ConsoleUtils.read(handle, slice) @@ -48,19 +48,15 @@ module Crystal::System::FileDescriptor bytes_read.to_i32 end - private def unbuffered_write(slice : Bytes) : Nil + private def system_write(slice : Bytes) : Int32 handle = windows_handle - until slice.empty? - if system_blocking? - bytes_written = write_blocking(handle, slice) - else - bytes_written = overlapped_operation(handle, "WriteFile", write_timeout, writing: true) do |overlapped| - ret = LibC.WriteFile(handle, slice, slice.size, out byte_count, overlapped) - {ret, byte_count} - end - end - - slice += bytes_written + if system_blocking? + write_blocking(handle, slice).to_i32 + else + overlapped_operation(handle, "WriteFile", write_timeout, writing: true) do |overlapped| + ret = LibC.WriteFile(handle, slice, slice.size, out byte_count, overlapped) + {ret, byte_count} + end.to_i32 end end diff --git a/src/crystal/system/win32/socket.cr b/src/crystal/system/win32/socket.cr index f567cffdcee2..ee3e0174a7ea 100644 --- a/src/crystal/system/win32/socket.cr +++ b/src/crystal/system/win32/socket.cr @@ -445,7 +445,7 @@ module Crystal::System::Socket LibC.GetConsoleMode(LibC::HANDLE.new(fd), out _) != 0 end - private def unbuffered_read(slice : Bytes) : Int32 + private def system_read(slice : Bytes) : Int32 wsabuf = wsa_buffer(slice) bytes_read = overlapped_read(fd, "WSARecv", connreset_is_error: false) do |overlapped| @@ -457,7 +457,7 @@ module Crystal::System::Socket bytes_read.to_i32 end - private def unbuffered_write(slice : Bytes) : Nil + private def system_write(slice : Bytes) : Int32 wsabuf = wsa_buffer(slice) bytes = overlapped_write(fd, "WSASend") do |overlapped| diff --git a/src/io/evented.cr b/src/io/evented.cr index ed2c18352ff0..0561fa5619f1 100644 --- a/src/io/evented.cr +++ b/src/io/evented.cr @@ -30,22 +30,18 @@ module IO::Evented resume_pending_readers end - def evented_write(slice : Bytes, errno_msg : String, &) : Nil - return if slice.empty? - + def evented_write(slice : Bytes, errno_msg : String, &) : Int32 begin loop do - # TODO: Investigate why the .to_i64 is needed as a workaround for #8230 - bytes_written = (yield slice).to_i64 + bytes_written = yield slice if bytes_written != -1 - slice += bytes_written - return if slice.size == 0 + return bytes_written.to_i32 + end + + if Errno.value == Errno::EAGAIN + wait_writable else - if Errno.value == Errno::EAGAIN - wait_writable - else - raise IO::Error.from_errno(errno_msg, target: self) - end + raise IO::Error.from_errno(errno_msg, target: self) end end ensure diff --git a/src/io/file_descriptor.cr b/src/io/file_descriptor.cr index cf5324a006d6..bdcc6cafde91 100644 --- a/src/io/file_descriptor.cr +++ b/src/io/file_descriptor.cr @@ -263,6 +263,16 @@ class IO::FileDescriptor < IO pp.text inspect end + private def unbuffered_read(slice : Bytes) : Int32 + system_read(slice) + end + + private def unbuffered_write(slice : Bytes) : Nil + until slice.empty? + slice += system_write(slice) + end + end + private def unbuffered_rewind : Nil self.pos = 0 end diff --git a/src/socket.cr b/src/socket.cr index eba19a939cba..6ec7a0551aca 100644 --- a/src/socket.cr +++ b/src/socket.cr @@ -424,6 +424,16 @@ class Socket < IO system_tty? end + private def unbuffered_read(slice : Bytes) : Int32 + system_read(slice) + end + + private def unbuffered_write(slice : Bytes) : Nil + until slice.empty? + slice += system_write(slice) + end + end + private def unbuffered_rewind : Nil raise Socket::Error.new("Can't rewind") end