diff --git a/src/crystal/event_loop/file_descriptor.cr b/src/crystal/event_loop/file_descriptor.cr index a83924b3986e..54840fe138be 100644 --- a/src/crystal/event_loop/file_descriptor.cr +++ b/src/crystal/event_loop/file_descriptor.cr @@ -46,7 +46,15 @@ abstract class Crystal::EventLoop # file descriptor. abstract def reopened(file_descriptor : Crystal::System::FileDescriptor) : Nil - # Closes the file descriptor resource. + # Internal shutdown of the file descriptor. Called after the + # `IO::FileDescriptor` has been marked closed but before calling `#close` to + # actually close the system fd or handle. + # + # Implementations shall resume all pending waiters and let them fail because + # the IO has been closed. + abstract def shutdown(file_descriptor : Crystal::System::FileDescriptor) : Nil + + # Closes the system fd or handle. abstract def close(file_descriptor : Crystal::System::FileDescriptor) : Nil end diff --git a/src/crystal/event_loop/iocp.cr b/src/crystal/event_loop/iocp.cr index e6885ed9ac82..a8c329d0cf8f 100644 --- a/src/crystal/event_loop/iocp.cr +++ b/src/crystal/event_loop/iocp.cr @@ -307,6 +307,9 @@ class Crystal::EventLoop::IOCP < Crystal::EventLoop raise NotImplementedError.new("Crystal::System::IOCP#reopened(FileDescriptor)") end + def shutdown(file_descriptor : Crystal::System::FileDescriptor) : Nil + end + def close(file_descriptor : Crystal::System::FileDescriptor) : Nil LibC.CancelIoEx(file_descriptor.windows_handle, nil) unless file_descriptor.system_blocking? file_descriptor.file_descriptor_close @@ -445,6 +448,9 @@ class Crystal::EventLoop::IOCP < Crystal::EventLoop end end + def shutdown(socket : ::Socket) : Nil + end + def close(socket : ::Socket) : Nil raise NotImplementedError.new("Crystal::System::IOCP#close(Socket)") end diff --git a/src/crystal/event_loop/libevent.cr b/src/crystal/event_loop/libevent.cr index d0eef0f88425..a3bd0f957ab4 100644 --- a/src/crystal/event_loop/libevent.cr +++ b/src/crystal/event_loop/libevent.cr @@ -178,10 +178,13 @@ class Crystal::EventLoop::LibEvent < Crystal::EventLoop file_descriptor.evented_close end - def close(file_descriptor : Crystal::System::FileDescriptor) : Nil + def shutdown(file_descriptor : Crystal::System::FileDescriptor) : Nil # perform cleanup before LibC.close. Using a file descriptor after it has # been closed is never defined and can always lead to undefined results file_descriptor.evented_close + end + + def close(file_descriptor : Crystal::System::FileDescriptor) : Nil file_descriptor.file_descriptor_close end @@ -299,10 +302,13 @@ class Crystal::EventLoop::LibEvent < Crystal::EventLoop end end - def close(socket : ::Socket) : Nil + def shutdown(socket : ::Socket) : Nil # perform cleanup before LibC.close. Using a file descriptor after it has # been closed is never defined and can always lead to undefined results socket.evented_close + end + + def close(socket : ::Socket) : Nil socket.socket_close end diff --git a/src/crystal/event_loop/polling.cr b/src/crystal/event_loop/polling.cr index 61c10fe85567..1c2bf76742b1 100644 --- a/src/crystal/event_loop/polling.cr +++ b/src/crystal/event_loop/polling.cr @@ -232,10 +232,13 @@ abstract class Crystal::EventLoop::Polling < Crystal::EventLoop resume_all(file_descriptor) end - def close(file_descriptor : System::FileDescriptor) : Nil + def shutdown(file_descriptor : System::FileDescriptor) : Nil # perform cleanup before LibC.close. Using a file descriptor after it has # been closed is never defined and can always lead to undefined results resume_all(file_descriptor) + end + + def close(file_descriptor : System::FileDescriptor) : Nil file_descriptor.file_descriptor_close end @@ -363,10 +366,13 @@ abstract class Crystal::EventLoop::Polling < Crystal::EventLoop end end - def close(socket : ::Socket) : Nil + def shutdown(socket : ::Socket) : Nil # perform cleanup before LibC.close. Using a file descriptor after it has # been closed is never defined and can always lead to undefined results resume_all(socket) + end + + def close(socket : ::Socket) : Nil socket.socket_close end diff --git a/src/crystal/event_loop/socket.cr b/src/crystal/event_loop/socket.cr index f31a1d6cdd70..ed7ac7adeda0 100644 --- a/src/crystal/event_loop/socket.cr +++ b/src/crystal/event_loop/socket.cr @@ -74,7 +74,15 @@ abstract class Crystal::EventLoop # and the source address. abstract def receive_from(socket : ::Socket, slice : Bytes) : Tuple(Int32, ::Socket::Address) - # Closes the socket. + # Internal shutdown of the socket. Called after the `Socket` has been marked + # closed but before calling `#close` to actually close the system socket fd + # or handle. + # + # Implementations shall resume all pending waiters and let them fail because + # the IO has been closed. They don't have to call the `shutdown` syscall. + abstract def shutdown(socket : ::Socket) : Nil + + # Closes the system socket fd or handle. abstract def close(socket : ::Socket) : Nil end diff --git a/src/crystal/event_loop/wasi.cr b/src/crystal/event_loop/wasi.cr index 19b2f5e65868..2eac2f6adc57 100644 --- a/src/crystal/event_loop/wasi.cr +++ b/src/crystal/event_loop/wasi.cr @@ -80,8 +80,14 @@ class Crystal::EventLoop::Wasi < Crystal::EventLoop raise NotImplementedError.new("Crystal::EventLoop#reopened(FileDescriptor)") end - def close(file_descriptor : Crystal::System::FileDescriptor) : Nil + def shutdown(file_descriptor : Crystal::System::FileDescriptor) : Nil file_descriptor.evented_close + end + + def shutdown(file_descriptor : Crystal::System::FileDescriptor) : Nil + end + + def close(file_descriptor : Crystal::System::FileDescriptor) : Nil file_descriptor.file_descriptor_close end @@ -133,8 +139,14 @@ class Crystal::EventLoop::Wasi < Crystal::EventLoop raise NotImplementedError.new "Crystal::Wasi::EventLoop#accept" end - def close(socket : ::Socket) : Nil + def shutdown(socket : ::Socket) : Nil socket.evented_close + end + + def shutdown(socket : ::Socket) : Nil + end + + def close(socket : ::Socket) : Nil socket.socket_close end diff --git a/src/crystal/system/unix/file_descriptor.cr b/src/crystal/system/unix/file_descriptor.cr index 1cb083cfe9cc..003d036985e6 100644 --- a/src/crystal/system/unix/file_descriptor.cr +++ b/src/crystal/system/unix/file_descriptor.cr @@ -134,6 +134,7 @@ module Crystal::System::FileDescriptor end private def system_close + event_loop.shutdown(self) event_loop.close(self) end diff --git a/src/crystal/system/unix/socket.cr b/src/crystal/system/unix/socket.cr index 2ef8e58272c2..f0205930b1c1 100644 --- a/src/crystal/system/unix/socket.cr +++ b/src/crystal/system/unix/socket.cr @@ -224,6 +224,7 @@ module Crystal::System::Socket end private def system_close + event_loop.shutdown(self) event_loop.close(self) end diff --git a/src/crystal/system/wasi/socket.cr b/src/crystal/system/wasi/socket.cr index 4d29cb373868..baf5cbfb5414 100644 --- a/src/crystal/system/wasi/socket.cr +++ b/src/crystal/system/wasi/socket.cr @@ -152,6 +152,7 @@ module Crystal::System::Socket end private def system_close + event_loop.shutdown(self) event_loop.close(self) end diff --git a/src/crystal/system/win32/file_descriptor.cr b/src/crystal/system/win32/file_descriptor.cr index 0d841db510fd..91eb0b99ab27 100644 --- a/src/crystal/system/win32/file_descriptor.cr +++ b/src/crystal/system/win32/file_descriptor.cr @@ -216,6 +216,7 @@ module Crystal::System::FileDescriptor end private def system_close + event_loop.shutdown(self) event_loop.close(self) end