diff --git a/src/crystal/event_loop/file_descriptor.cr b/src/crystal/event_loop/file_descriptor.cr index a83924b3986e..b15bdae77356 100644 --- a/src/crystal/event_loop/file_descriptor.cr +++ b/src/crystal/event_loop/file_descriptor.cr @@ -41,10 +41,12 @@ abstract class Crystal::EventLoop # Blocks the current fiber until the file descriptor is ready for write. abstract def wait_writable(file_descriptor : Crystal::System::FileDescriptor) : Nil - # Hook to react on the file descriptor after it has been reopened. For - # example we might want to resume all pending operations to act on the new - # file descriptor. - abstract def reopened(file_descriptor : Crystal::System::FileDescriptor) : Nil + # Resumes fibers waiting on the file descriptor. + # + # Optional. Only called on UNIX targets. + def resume_all(file_descriptor : Crystal::System::FileDescriptor) : Nil + raise NotImplementedError.new("#{self.class.name}#resume_all(Crystal::System::FileDescriptor)") + end # Closes the file descriptor resource. abstract def close(file_descriptor : Crystal::System::FileDescriptor) : Nil diff --git a/src/crystal/event_loop/iocp.cr b/src/crystal/event_loop/iocp.cr index a78721ba4372..19e01e48c6ef 100644 --- a/src/crystal/event_loop/iocp.cr +++ b/src/crystal/event_loop/iocp.cr @@ -303,10 +303,6 @@ class Crystal::EventLoop::IOCP < Crystal::EventLoop raise NotImplementedError.new("Crystal::System::IOCP#wait_writable(FileDescriptor)") end - def reopened(file_descriptor : Crystal::System::FileDescriptor) : Nil - raise NotImplementedError.new("Crystal::System::IOCP#reopened(FileDescriptor)") - 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 diff --git a/src/crystal/event_loop/libevent.cr b/src/crystal/event_loop/libevent.cr index d0eef0f88425..a315215790df 100644 --- a/src/crystal/event_loop/libevent.cr +++ b/src/crystal/event_loop/libevent.cr @@ -174,14 +174,11 @@ class Crystal::EventLoop::LibEvent < Crystal::EventLoop end end - def reopened(file_descriptor : Crystal::System::FileDescriptor) : Nil + def resume_all(file_descriptor : Crystal::System::FileDescriptor) : Nil file_descriptor.evented_close end def close(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 file_descriptor.file_descriptor_close end @@ -299,10 +296,11 @@ class Crystal::EventLoop::LibEvent < Crystal::EventLoop end end - def close(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 + def resume_all(socket : ::Socket) : Nil 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..088cbc33db57 100644 --- a/src/crystal/event_loop/polling.cr +++ b/src/crystal/event_loop/polling.cr @@ -228,14 +228,11 @@ abstract class Crystal::EventLoop::Polling < Crystal::EventLoop end end - def reopened(file_descriptor : System::FileDescriptor) : Nil - resume_all(file_descriptor) + def resume_all(file_descriptor : System::FileDescriptor) : Nil + resume_all_impl(file_descriptor) end def close(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) file_descriptor.file_descriptor_close end @@ -363,10 +360,11 @@ abstract class Crystal::EventLoop::Polling < Crystal::EventLoop end end + def resume_all(socket : ::Socket) : Nil + resume_all_impl(socket) + end + def close(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) socket.socket_close end @@ -400,7 +398,7 @@ abstract class Crystal::EventLoop::Polling < Crystal::EventLoop end end - private def resume_all(io) + private def resume_all_impl(io) return unless (index = io.__evloop_data).valid? Polling.arena.free(index) do |pd| diff --git a/src/crystal/event_loop/socket.cr b/src/crystal/event_loop/socket.cr index f31a1d6cdd70..27f59c1fb9db 100644 --- a/src/crystal/event_loop/socket.cr +++ b/src/crystal/event_loop/socket.cr @@ -74,6 +74,13 @@ abstract class Crystal::EventLoop # and the source address. abstract def receive_from(socket : ::Socket, slice : Bytes) : Tuple(Int32, ::Socket::Address) + # Resumes fibers waiting on the socket. + # + # Optional. Only called on UNIX targets. + def resume_all(file_descriptor : Crystal::System::FileDescriptor) : Nil + raise NotImplementedError.new("#{self.class.name}#resume_all(Crystal::System::FileDescriptor)") + end + # Closes the socket. 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..71f63fcb628e 100644 --- a/src/crystal/event_loop/wasi.cr +++ b/src/crystal/event_loop/wasi.cr @@ -76,10 +76,6 @@ class Crystal::EventLoop::Wasi < Crystal::EventLoop end end - def reopened(file_descriptor : Crystal::System::FileDescriptor) : Nil - raise NotImplementedError.new("Crystal::EventLoop#reopened(FileDescriptor)") - end - def close(file_descriptor : Crystal::System::FileDescriptor) : Nil file_descriptor.evented_close file_descriptor.file_descriptor_close diff --git a/src/crystal/system/unix/file_descriptor.cr b/src/crystal/system/unix/file_descriptor.cr index 1afe22b08ca7..49ac0601200a 100644 --- a/src/crystal/system/unix/file_descriptor.cr +++ b/src/crystal/system/unix/file_descriptor.cr @@ -126,10 +126,13 @@ module Crystal::System::FileDescriptor # Mark the handle open, since we had to have dup'd a live handle. @closed = false - event_loop.reopened(self) + # resume all pending waiters so they can start waiting on the new fd + event_loop.resume_all(self) end private def system_close + # resume pending fibers before closing the fd + event_loop.resume_all(self) event_loop.close(self) end diff --git a/src/crystal/system/unix/socket.cr b/src/crystal/system/unix/socket.cr index 05379b48ae9f..af01c6e7f1cc 100644 --- a/src/crystal/system/unix/socket.cr +++ b/src/crystal/system/unix/socket.cr @@ -224,6 +224,8 @@ module Crystal::System::Socket end private def system_close + # resume pending fibers before closing the fd + event_loop.resume_all(self) event_loop.close(self) end