diff --git a/src/crystal/event_loop.cr b/src/crystal/event_loop.cr index 45fc9e4f8558..00bcb86040b6 100644 --- a/src/crystal/event_loop.cr +++ b/src/crystal/event_loop.cr @@ -1,26 +1,30 @@ abstract class Crystal::EventLoop - # Creates an event loop instance - def self.create : self + def self.backend_class {% if flag?(:wasi) %} - Crystal::EventLoop::Wasi.new + Crystal::EventLoop::Wasi {% elsif flag?(:unix) %} # TODO: enable more targets by default (need manual tests or fixes) {% if flag?("evloop=libevent") %} - Crystal::EventLoop::LibEvent.new + Crystal::EventLoop::LibEvent {% elsif flag?("evloop=epoll") || flag?(:android) || flag?(:linux) %} - Crystal::EventLoop::Epoll.new + Crystal::EventLoop::Epoll {% elsif flag?("evloop=kqueue") || flag?(:darwin) || flag?(:freebsd) %} - Crystal::EventLoop::Kqueue.new + Crystal::EventLoop::Kqueue {% else %} - Crystal::EventLoop::LibEvent.new + Crystal::EventLoop::LibEvent {% end %} {% elsif flag?(:win32) %} - Crystal::EventLoop::IOCP.new + Crystal::EventLoop::IOCP {% else %} {% raise "Event loop not supported" %} {% end %} end + # Creates an event loop instance + def self.create : self + backend_class.new + end + @[AlwaysInline] def self.current : self Crystal::Scheduler.event_loop diff --git a/src/crystal/event_loop/file_descriptor.cr b/src/crystal/event_loop/file_descriptor.cr index 5fb6cbb95cb0..0304f7d9b969 100644 --- a/src/crystal/event_loop/file_descriptor.cr +++ b/src/crystal/event_loop/file_descriptor.cr @@ -19,13 +19,20 @@ abstract class Crystal::EventLoop # Closes the file descriptor resource. abstract def close(file_descriptor : Crystal::System::FileDescriptor) : Nil + end - # Removes the file descriptor from the event loop. Can be used to free up - # memory resources associated with the file descriptor, as well as removing - # the file descriptor from kernel data structures. - # - # Called by `::IO::FileDescriptor#finalize` before closing the file - # descriptor. Errors shall be silently ignored. - abstract def remove(file_descriptor : Crystal::System::FileDescriptor) : Nil + # Removes the file descriptor from the event loop. Can be used to free up + # memory resources associated with the file descriptor, as well as removing + # the file descriptor from kernel data structures. + # + # Called by `::IO::FileDescriptor#finalize` before closing the file + # descriptor. Errors shall be silently ignored. + def self.remove(file_descriptor : Crystal::System::FileDescriptor) : Nil + backend_class.remove_impl(file_descriptor) + end + + # Actual implementation for `.remove`. Must be implemented on a subclass of + # `Crystal::EventLoop` when needed. + protected def self.remove_impl(file_descriptor : Crystal::System::FileDescriptor) : Nil end end diff --git a/src/crystal/event_loop/iocp.cr b/src/crystal/event_loop/iocp.cr index 5628e99121b1..6e4175e3daee 100644 --- a/src/crystal/event_loop/iocp.cr +++ b/src/crystal/event_loop/iocp.cr @@ -201,9 +201,6 @@ class Crystal::EventLoop::IOCP < Crystal::EventLoop LibC.CancelIoEx(file_descriptor.windows_handle, nil) unless file_descriptor.system_blocking? end - def remove(file_descriptor : Crystal::System::FileDescriptor) : Nil - end - private def wsa_buffer(bytes) wsabuf = LibC::WSABUF.new wsabuf.len = bytes.size @@ -314,7 +311,4 @@ class Crystal::EventLoop::IOCP < Crystal::EventLoop def close(socket : ::Socket) : Nil end - - def remove(socket : ::Socket) : Nil - end end diff --git a/src/crystal/event_loop/libevent.cr b/src/crystal/event_loop/libevent.cr index 7b45939bd537..9c0b3d33b15c 100644 --- a/src/crystal/event_loop/libevent.cr +++ b/src/crystal/event_loop/libevent.cr @@ -98,9 +98,6 @@ class Crystal::EventLoop::LibEvent < Crystal::EventLoop file_descriptor.evented_close end - def remove(file_descriptor : Crystal::System::FileDescriptor) : Nil - end - def read(socket : ::Socket, slice : Bytes) : Int32 evented_read(socket, "Error reading socket") do LibC.recv(socket.fd, slice, slice.size, 0).to_i32 @@ -194,9 +191,6 @@ class Crystal::EventLoop::LibEvent < Crystal::EventLoop socket.evented_close end - def remove(socket : ::Socket) : Nil - end - def evented_read(target, errno_msg : String, &) : Int32 loop do bytes_read = yield diff --git a/src/crystal/event_loop/polling.cr b/src/crystal/event_loop/polling.cr index 774cc7060715..acb38f89deea 100644 --- a/src/crystal/event_loop/polling.cr +++ b/src/crystal/event_loop/polling.cr @@ -164,7 +164,7 @@ abstract class Crystal::EventLoop::Polling < Crystal::EventLoop evented_close(file_descriptor) end - def remove(file_descriptor : System::FileDescriptor) : Nil + protected def self.remove_impl(file_descriptor : System::FileDescriptor) : Nil internal_remove(file_descriptor) end @@ -267,7 +267,7 @@ abstract class Crystal::EventLoop::Polling < Crystal::EventLoop evented_close(socket) end - def remove(socket : ::Socket) : Nil + protected def self.remove_impl(socket : ::Socket) : Nil internal_remove(socket) end @@ -317,7 +317,7 @@ abstract class Crystal::EventLoop::Polling < Crystal::EventLoop end end - private def internal_remove(io) + private def self.internal_remove(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 03b556b3be96..1f4fc629d8ca 100644 --- a/src/crystal/event_loop/socket.cr +++ b/src/crystal/event_loop/socket.cr @@ -62,13 +62,20 @@ abstract class Crystal::EventLoop # Closes the socket. abstract def close(socket : ::Socket) : Nil + end - # Removes the socket from the event loop. Can be used to free up memory - # resources associated with the socket, as well as removing the socket from - # kernel data structures. - # - # Called by `::Socket#finalize` before closing the socket. Errors shall be - # silently ignored. - abstract def remove(socket : ::Socket) : Nil + # Removes the socket from the event loop. Can be used to free up memory + # resources associated with the socket, as well as removing the socket from + # kernel data structures. + # + # Called by `::Socket#finalize` before closing the socket. Errors shall be + # silently ignored. + def self.remove(socket : ::Socket) : Nil + backend_class.remove_impl(socket) + end + + # Actual implementation for `.remove`. Must be implemented on a subclass of + # `Crystal::EventLoop` when needed. + protected def self.remove_impl(socket : ::Socket) : Nil end end diff --git a/src/crystal/event_loop/wasi.cr b/src/crystal/event_loop/wasi.cr index a91c469f406c..08781b4fb950 100644 --- a/src/crystal/event_loop/wasi.cr +++ b/src/crystal/event_loop/wasi.cr @@ -53,9 +53,6 @@ class Crystal::EventLoop::Wasi < Crystal::EventLoop file_descriptor.evented_close end - def remove(file_descriptor : Crystal::System::FileDescriptor) : Nil - end - def read(socket : ::Socket, slice : Bytes) : Int32 evented_read(socket, "Error reading socket") do LibC.recv(socket.fd, slice, slice.size, 0).to_i32 @@ -88,9 +85,6 @@ class Crystal::EventLoop::Wasi < Crystal::EventLoop socket.evented_close end - def remove(socket : ::Socket) : Nil - end - def evented_read(target, errno_msg : String, &) : Int32 loop do bytes_read = yield diff --git a/src/crystal/system/unix/process.cr b/src/crystal/system/unix/process.cr index 875d834bb266..a4b5ff45c0cc 100644 --- a/src/crystal/system/unix/process.cr +++ b/src/crystal/system/unix/process.cr @@ -352,7 +352,7 @@ struct Crystal::System::Process private def self.reopen_io(src_io : IO::FileDescriptor, dst_io : IO::FileDescriptor) if src_io.closed? - Crystal::EventLoop.current.remove(dst_io) + Crystal::EventLoop.remove(dst_io) dst_io.file_descriptor_close else src_io = to_real_fd(src_io) diff --git a/src/crystal/system/unix/signal.cr b/src/crystal/system/unix/signal.cr index 802cb418db15..4b1604c766ee 100644 --- a/src/crystal/system/unix/signal.cr +++ b/src/crystal/system/unix/signal.cr @@ -111,7 +111,7 @@ module Crystal::System::Signal # descriptors of the parent process and send it received signals. def self.after_fork @@pipe.each do |pipe_io| - Crystal::EventLoop.current.remove(pipe_io) + Crystal::EventLoop.remove(pipe_io) pipe_io.file_descriptor_close { } end ensure diff --git a/src/io/file_descriptor.cr b/src/io/file_descriptor.cr index a9b303b4b58c..82c2b8ac232f 100644 --- a/src/io/file_descriptor.cr +++ b/src/io/file_descriptor.cr @@ -255,7 +255,7 @@ class IO::FileDescriptor < IO def finalize return if closed? || !close_on_finalize? - event_loop?.try(&.remove(self)) + Crystal::EventLoop.remove(self) file_descriptor_close { } # ignore error end diff --git a/src/socket.cr b/src/socket.cr index e97deea9eb04..b862c30e2f9e 100644 --- a/src/socket.cr +++ b/src/socket.cr @@ -430,7 +430,7 @@ class Socket < IO def finalize return if closed? - event_loop?.try(&.remove(self)) + Crystal::EventLoop.remove(self) socket_close { } # ignore error end