Fix reporting of an async IO timeout error on Windows (`SerialPort`) (#81744)
authorKoundinya Veluri <kouvel@users.noreply.github.com>
Wed, 15 Feb 2023 18:57:45 +0000 (10:57 -0800)
committerGitHub <noreply@github.com>
Wed, 15 Feb 2023 18:57:45 +0000 (10:57 -0800)
- When an async `SerialPort` IO operation times out, it reports the timeout in the IO completion with an `NTSTATUS` value of `WAIT_TIMEOUT` (258)
- In the thread pool when using `GetQueuedCompletionStatusEx`, the `NTSTATUS` value was being checked against `STATUS_SUCCESS` to determine success, so the `WAIT_TIMEOUT` was reported as an error. This leads to a different exception being thrown, compared to before when `GetQueuedCompletionStatus` was used.
- Fixed to use similar logic to the SDK's `NT_SUCCESS` macro, which treats the `WAIT_TIMEOUT` value as a success, which is similar to what `GetQueuedCompletionStatus` does
- There are already tests that verify this behavior in `System.IO.Ports` tests, though [they are currently disabled](https://github.com/dotnet/runtime/blob/b39d6a6eb44860746e91e5ce4f585beff33d1f63/src/libraries/System.IO.Ports/tests/Support/TCSupport.cs#L108-L118) due to instabilities. I have verified locally that the relevant failures are fixed and that there are no new failures in those tests.

Fixes https://github.com/dotnet/runtime/issues/80079

src/libraries/Common/src/Interop/Windows/NtDll/Interop.NtStatus.cs
src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.IO.Windows.cs

index 4350898..ad48e8e 100644 (file)
@@ -5,6 +5,10 @@ internal static partial class Interop
 {
     internal static class StatusOptions
     {
+        // See the NT_SUCCESS macro in the Windows SDK, and
+        // https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values
+        internal static bool NT_SUCCESS(uint ntStatus) => (int)ntStatus >= 0;
+
         // Error codes from ntstatus.h
         internal const uint STATUS_SUCCESS                = 0x00000000;
         internal const uint STATUS_SOME_NOT_MAPPED        = 0x00000107;
index a8bc033..bb71f82 100644 (file)
@@ -257,7 +257,7 @@ namespace System.Threading
                     // The NtStatus code for the operation is in the InternalLow field
                     uint ntStatus = (uint)(nint)e.nativeOverlapped->InternalLow;
                     uint errorCode = Interop.Errors.ERROR_SUCCESS;
-                    if (ntStatus != Interop.StatusOptions.STATUS_SUCCESS)
+                    if (!Interop.StatusOptions.NT_SUCCESS(ntStatus))
                     {
                         errorCode = Interop.NtDll.RtlNtStatusToDosError((int)ntStatus);
                     }