@@ -75,12 +75,19 @@ module Crystal::IOCP
7575 property previous : OverlappedOperation ?
7676 @@canceled = Thread ::LinkedList (OverlappedOperation ).new
7777
78+ def initialize (@handle : LibC ::HANDLE )
79+ end
80+
81+ def initialize (handle : LibC ::SOCKET )
82+ @handle = LibC ::HANDLE .new(handle)
83+ end
84+
7885 def self.run (handle, & )
79- operation = OverlappedOperation .new
86+ operation = OverlappedOperation .new(handle)
8087 begin
8188 yield operation
8289 ensure
83- operation.done(handle)
90+ operation.done
8491 end
8592 end
8693
@@ -93,9 +100,12 @@ module Crystal::IOCP
93100 pointerof (@overlapped )
94101 end
95102
96- def result (handle, & )
103+ def wait_for_result (timeout, & )
104+ wait_for_completion(timeout)
105+
97106 raise Exception .new(" Invalid state #{ @state } " ) unless @state .done? || @state .started?
98- result = LibC .GetOverlappedResult (handle, self , out bytes, 0 )
107+
108+ result = LibC .GetOverlappedResult (@handle , self , out bytes, 0 )
99109 if result.zero?
100110 error = WinError .value
101111 yield error
@@ -106,10 +116,15 @@ module Crystal::IOCP
106116 bytes
107117 end
108118
109- def wsa_result (socket, & )
119+ def wait_for_wsa_result (timeout, & )
120+ wait_for_completion(timeout)
121+ wsa_result { |error | yield error }
122+ end
123+
124+ def wsa_result (& )
110125 raise Exception .new(" Invalid state #{ @state } " ) unless @state .done? || @state .started?
111126 flags = 0 _u32
112- result = LibC .WSAGetOverlappedResult (socket , self , out bytes, false , pointerof (flags))
127+ result = LibC .WSAGetOverlappedResult (LibC :: SOCKET .new( @handle .address) , self , out bytes, false , pointerof (flags))
113128 if result.zero?
114129 error = WinError .wsa_value
115130 yield error
@@ -132,15 +147,13 @@ module Crystal::IOCP
132147 end
133148 end
134149
135- protected def done ( handle )
150+ protected def done
136151 case @state
137152 when .started?
138- handle = LibC ::HANDLE .new(handle) if handle.is_a?(LibC ::SOCKET )
139-
140153 # https://learn.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-cancelioex
141154 # > The application must not free or reuse the OVERLAPPED structure
142155 # associated with the canceled I/O operations until they have completed
143- if LibC .CancelIoEx (handle, self ) != 0
156+ if LibC .CancelIoEx (@ handle , self ) != 0
144157 @state = :cancelled
145158 @@canceled .push(self ) # to increase lifetime
146159 end
@@ -150,24 +163,23 @@ module Crystal::IOCP
150163 def done !
151164 @state = :done
152165 end
153- end
154166
155- # Returns `false` if the operation timed out.
156- def self.schedule_overlapped (timeout : Time ::Span ?, line = __LINE__ ) : Bool
157- if timeout
158- timeout_event = Crystal ::IOCP ::Event .new(Fiber .current)
159- timeout_event.add(timeout)
160- else
161- timeout_event = Crystal ::IOCP ::Event .new(Fiber .current, Time ::Span ::MAX )
162- end
163- # memoize event loop to make sure that we still target the same instance
164- # after wakeup (guaranteed by current MT model but let's be future proof)
165- event_loop = Crystal ::EventLoop .current
166- event_loop.enqueue(timeout_event)
167+ def wait_for_completion (timeout )
168+ if timeout
169+ timeout_event = Crystal ::IOCP ::Event .new(Fiber .current)
170+ timeout_event.add(timeout)
171+ else
172+ timeout_event = Crystal ::IOCP ::Event .new(Fiber .current, Time ::Span ::MAX )
173+ end
174+ # memoize event loop to make sure that we still target the same instance
175+ # after wakeup (guaranteed by current MT model but let's be future proof)
176+ event_loop = Crystal ::EventLoop .current
177+ event_loop.enqueue(timeout_event)
167178
168- Fiber .suspend
179+ Fiber .suspend
169180
170- event_loop.dequeue(timeout_event)
181+ event_loop.dequeue(timeout_event)
182+ end
171183 end
172184
173185 def self.overlapped_operation (target, handle, method, timeout, * , writing = false , & )
@@ -192,9 +204,7 @@ module Crystal::IOCP
192204 return value
193205 end
194206
195- schedule_overlapped(timeout)
196-
197- operation.result(handle) do |error |
207+ operation.wait_for_result(timeout) do |error |
198208 case error
199209 when .error_io_incomplete?
200210 raise IO ::TimeoutError .new(" #{ method } timed out" )
@@ -224,9 +234,7 @@ module Crystal::IOCP
224234 return value
225235 end
226236
227- schedule_overlapped(timeout)
228-
229- operation.wsa_result(socket) do |error |
237+ operation.wait_for_wsa_result(timeout) do |error |
230238 case error
231239 when .wsa_io_incomplete?
232240 raise IO ::TimeoutError .new(" #{ method } timed out" )
0 commit comments