@@ -221,6 +221,58 @@ namespace lvh::detail {
221221 return OperationStatus::failure (code, message.str ());
222222 }
223223
224+ UniqueHandle &overlapped_device_io_event () {
225+ thread_local UniqueHandle operation_event {nullptr , &::CloseHandle};
226+ if (!operation_event) {
227+ operation_event = make_unique_handle (::CreateEventA (nullptr , TRUE , FALSE , nullptr ));
228+ }
229+
230+ return operation_event;
231+ }
232+
233+ template <typename CancelOperation, typename FinishOperation>
234+ void cancel_and_drain_overlapped_io (
235+ OVERLAPPED &overlapped,
236+ DWORD *bytes_returned,
237+ CancelOperation &&cancel_operation,
238+ FinishOperation &&finish_operation
239+ ) {
240+ static_cast <void >(std::forward<CancelOperation>(cancel_operation)(overlapped));
241+ static_cast <void >(std::forward<FinishOperation>(finish_operation)(overlapped, bytes_returned, TRUE ));
242+ }
243+
244+ template <typename StartOperation, typename FinishOperation>
245+ OperationStatus run_overlapped_device_io (
246+ std::string_view operation,
247+ DWORD *bytes_returned,
248+ StartOperation &&start_operation,
249+ FinishOperation &&finish_operation
250+ ) {
251+ const auto &operation_event = overlapped_device_io_event ();
252+ if (!operation_event) {
253+ return windows_failure (ErrorCode::backend_failure, operation, ::GetLastError ());
254+ }
255+ if (::ResetEvent (operation_event.get ()) == FALSE ) {
256+ return windows_failure (ErrorCode::backend_failure, operation, ::GetLastError ());
257+ }
258+
259+ OVERLAPPED overlapped {};
260+ overlapped.hEvent = operation_event.get ();
261+ if (std::forward<StartOperation>(start_operation)(overlapped, bytes_returned) != FALSE ) {
262+ return OperationStatus::success ();
263+ }
264+
265+ if (const auto start_error = ::GetLastError (); start_error != ERROR_IO_PENDING ) {
266+ return windows_failure (ErrorCode::backend_failure, operation, start_error);
267+ }
268+
269+ if (std::forward<FinishOperation>(finish_operation)(overlapped, bytes_returned, TRUE ) == FALSE ) {
270+ return windows_failure (ErrorCode::backend_failure, operation, ::GetLastError ());
271+ }
272+
273+ return OperationStatus::success ();
274+ }
275+
224276 template <typename Submit>
225277 OperationStatus submit_with_desktop_retry (Submit submit, std::string_view operation) {
226278 using enum ErrorCode;
@@ -621,6 +673,18 @@ namespace lvh::detail {
621673 OVERLAPPED overlapped {};
622674 overlapped.hEvent = operation_event.get ();
623675 DWORD bytes_returned = 0 ;
676+ const auto cancel_and_drain = [this , &overlapped, &bytes_returned] {
677+ cancel_and_drain_overlapped_io (
678+ overlapped,
679+ &bytes_returned,
680+ [this ](OVERLAPPED &pending) {
681+ return ::CancelIoEx (handle_->value .get (), &pending);
682+ },
683+ [this ](OVERLAPPED &pending, DWORD *result_size, BOOL wait) {
684+ return ::GetOverlappedResult (handle_->value .get (), &pending, result_size, wait);
685+ }
686+ );
687+ };
624688
625689 if (const auto started = ::DeviceIoControl (handle_->value .get (), LVH_WINDOWS_IOCTL_READ_OUTPUT_REPORT , nullptr , 0 , &event, sizeof (event), &bytes_returned, &overlapped); started == FALSE ) {
626690 if (const auto error_code = ::GetLastError (); error_code != ERROR_IO_PENDING ) {
@@ -638,11 +702,11 @@ namespace lvh::detail {
638702 INFINITE
639703 );
640704 if (wait_result == WAIT_OBJECT_0 + 1U ) {
641- static_cast < void >(:: CancelIoEx (handle_-> value . get (), &overlapped) );
705+ cancel_and_drain ( );
642706 return std::nullopt ;
643707 }
644708 if (wait_result != WAIT_OBJECT_0 ) {
645- static_cast < void >(:: CancelIoEx (handle_-> value . get (), &overlapped) );
709+ cancel_and_drain ( );
646710 return std::nullopt ;
647711 }
648712 }
@@ -672,13 +736,25 @@ namespace lvh::detail {
672736 DWORD *bytes_returned,
673737 std::string_view operation
674738 ) const {
675- using enum ErrorCode;
676-
677- if (::DeviceIoControl (handle_->value .get (), control_code, &input, sizeof (input), &output, sizeof (output), bytes_returned, nullptr ) == FALSE ) {
678- return windows_failure (backend_failure, operation, ::GetLastError ());
679- }
680-
681- return OperationStatus::success ();
739+ return run_overlapped_device_io (
740+ operation,
741+ bytes_returned,
742+ [this , control_code, &input, &output](OVERLAPPED &overlapped, DWORD *result_size) {
743+ return ::DeviceIoControl (
744+ handle_->value .get (),
745+ control_code,
746+ &input,
747+ sizeof (input),
748+ &output,
749+ sizeof (output),
750+ result_size,
751+ &overlapped
752+ );
753+ },
754+ [this ](OVERLAPPED &overlapped, DWORD *result_size, BOOL wait) {
755+ return ::GetOverlappedResult (handle_->value .get (), &overlapped, result_size, wait);
756+ }
757+ );
682758 }
683759
684760 template <typename Input>
@@ -688,13 +764,25 @@ namespace lvh::detail {
688764 DWORD *bytes_returned,
689765 std::string_view operation
690766 ) const {
691- using enum ErrorCode;
692-
693- if (::DeviceIoControl (handle_->value .get (), control_code, &input, sizeof (input), nullptr , 0 , bytes_returned, nullptr ) == FALSE ) {
694- return windows_failure (backend_failure, operation, ::GetLastError ());
695- }
696-
697- return OperationStatus::success ();
767+ return run_overlapped_device_io (
768+ operation,
769+ bytes_returned,
770+ [this , control_code, &input](OVERLAPPED &overlapped, DWORD *result_size) {
771+ return ::DeviceIoControl (
772+ handle_->value .get (),
773+ control_code,
774+ &input,
775+ sizeof (input),
776+ nullptr ,
777+ 0 ,
778+ result_size,
779+ &overlapped
780+ );
781+ },
782+ [this ](OVERLAPPED &overlapped, DWORD *result_size, BOOL wait) {
783+ return ::GetOverlappedResult (handle_->value .get (), &overlapped, result_size, wait);
784+ }
785+ );
698786 }
699787
700788 std::string path_;
0 commit comments