Description
In .NET 6 and earlier, when System.IO.Ports.SerialPort.Read times out, it will throw a TimeoutException. In .NET 7, it will throw an IOException with an HResult of 0x800705B4 (1460: ERROR_TIMEOUT)
Reproduction Steps
Use the following code (substitute your own valid serial port values)
- VS2022 or .NET 7 SDK on Windows.
- Nuget Reference to
System.IO.Ports version 7.0.0 (OK with eariler versions too)
- Target
net7.0 to see it fail, or net6.0 to see it work.
using System;
using System.IO;
using System.IO.Ports;
class Program
{
static void Main()
{
var serialPort = new SerialPort("COM42", 115200, Parity.None, 8, StopBits.One)
{
DtrEnable = false,
WriteTimeout = 500,
ReadTimeout = 500,
};
serialPort.Open();
var data = new byte[100];
try
{
var numRead = serialPort.Read(data, 0, data.Length);
Console.WriteLine("Read {0}", numRead);
}
catch (TimeoutException)
{
Console.WriteLine(".NET <=6 Timed out");
}
catch (IOException e)
{
Console.WriteLine(".NET 7: IO {0} HR:0x{1:X}", e.HResult & 0xFFFF, e.HResult);
}
}
}
Expected behavior
Output of .NET <=6 Timed out
Actual behavior
Output of .NET 7: IO 1460 HR:0x800705B4
Regression?
Yes. Worked for .NET 6 and 5.
You can easily test this but switching target framework. If you switch to .NET 6 you get the TimeoutException, if you switch to .NET 7 you get the IOException
Known Workarounds
Code catching the TimeoutException would have to catch the IOException check the HResult and handle it the same way.
Configuration
.net 7.0.101 Windows 11, Target X64 or x86 has the problem.
Debug or release doesn't seem to matter.
Ubuntu WSL2 with 7.0.101 does not have the problem.
Other information
This seems to be caused by changed in overlapped IO introduced in .net7
The difference can be observed here:
|
SerialStreamAsyncResult asyncResult = |
On .net6, the errorCode is 0, on .net7 it's 1460
The call stack invoking this function is very different on .net 6 and 7.
On .net7, AsyncFSCallback is getttiong called from PortableThreadPool and the error is set here:
|
errorCode = Interop.NtDll.RtlNtStatusToDosError((int)ntStatus); |
On .net6, it's getting called from _IOCompletionCallback.PerformIOCompletionCallback The stack stops there, and I didn't dig any deeper to see where it's getting its parameters from.
Description
In .NET 6 and earlier, when
System.IO.Ports.SerialPort.Readtimes out, it will throw aTimeoutException. In .NET 7, it will throw anIOExceptionwith an HResult of 0x800705B4 (1460: ERROR_TIMEOUT)Reproduction Steps
Use the following code (substitute your own valid serial port values)
System.IO.Portsversion 7.0.0 (OK with eariler versions too)net7.0to see it fail, ornet6.0to see it work.Expected behavior
Output of
.NET <=6 Timed outActual behavior
Output of
.NET 7: IO 1460 HR:0x800705B4Regression?
Yes. Worked for .NET 6 and 5.
You can easily test this but switching target framework. If you switch to .NET 6 you get the
TimeoutException, if you switch to .NET 7 you get theIOExceptionKnown Workarounds
Code catching the
TimeoutExceptionwould have to catch theIOExceptioncheck the HResult and handle it the same way.Configuration
.net 7.0.101 Windows 11, Target X64 or x86 has the problem.
Debug or release doesn't seem to matter.
Ubuntu WSL2 with 7.0.101 does not have the problem.
Other information
This seems to be caused by changed in overlapped IO introduced in .net7
The difference can be observed here:
runtime/src/libraries/System.IO.Ports/src/System/IO/Ports/SerialStream.Windows.cs
Line 1505 in d099f07
On .net6, the errorCode is 0, on .net7 it's 1460
The call stack invoking this function is very different on .net 6 and 7.
On .net7,
AsyncFSCallbackis getttiong called fromPortableThreadPooland the error is set here:runtime/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.IO.Windows.cs
Line 262 in d099f07
On .net6, it's getting called from
_IOCompletionCallback.PerformIOCompletionCallbackThe stack stops there, and I didn't dig any deeper to see where it's getting its parameters from.