SerialPort - initial async implementation on Linux and bugfixes#33027
SerialPort - initial async implementation on Linux and bugfixes#33027krwq merged 10 commits intodotnet:masterfrom
Conversation
| // I.e: Let _receivedBytesThreshold be 8 - when we get an event when 7 bytes are available | ||
| // BytesToRead can change while we run this event and thus | ||
| // we virtually can get 2 events when 8th byte arrives | ||
| // I.e. we might want to add total bytes available as internal field in the args event |
There was a problem hiding this comment.
Is there an issue number associated with this? Do we plan to fix it?
There was a problem hiding this comment.
I'm currently tracking all of the issues in the PR description, once this will be stable enough I'll file them so that I don't do much churn with creating issues.
| } | ||
|
|
||
| public override bool CanRead | ||
| static void CheckBaudRate(int baudRate) |
There was a problem hiding this comment.
Nit: private. Also, is this something that can be shared with Windows, and thus moved into the shared file?
There was a problem hiding this comment.
Unfortunatelly this can't be shared as it depends on the driver - Windows currently supports more baud rates. I'm currently tracking expanding the range of baud rates on Linux by trying to emulate non supported ranges (I saw an article somewhere on how to do that)
There was a problem hiding this comment.
the rates also depend on Driver and kernel version.
There was a problem hiding this comment.
I think I'll explore this subject separately - I wanted to mimic the behavior as much as possible and throw only when I'm sure the baud rates are out of range.
| private enum ThrowAt { Set, Open }; | ||
|
|
||
| #region Test Cases | ||
| [KnownFailure] // either hanging or really slow |
There was a problem hiding this comment.
What is the KnownFailure attribute? How does that differ from ActiveIssue?
There was a problem hiding this comment.
this doesn't disable anything by default, it's more like a temporary thing which helps to manage test cases while I still work on them and gives hints what can still be broken and what should already work - I'd think of it as adding a xunit trait at this point. I can technically remove it since I don't believe any of those test cases run in the CI but I think it is still useful as long as still issues are being polished up
There was a problem hiding this comment.
note: those test cases were failing before (assuming you got null modem connected)
| throw new IOException(); | ||
| } | ||
| if ((_handshake == Handshake.RequestToSend || _handshake == Handshake.RequestToSendXOnXOff)) | ||
| throw new InvalidOperationException(SR.CantSetRtsWithHandshaking); |
There was a problem hiding this comment.
throw new InvalidOperationException(SR.CantSetRtsWithHandshaking); [](start = 20, length = 66)
why we throw in the getter?
There was a problem hiding this comment.
Bad design from the past - matching Windows behavior :(
| // returns number of bytes read/written | ||
| private static int DoIORequest(ConcurrentQueue<SerialStreamIORequest> q, RequestProcessor op) | ||
| { | ||
| // assumes dequeue-ing happens on a single thread |
There was a problem hiding this comment.
assumes dequeue-ing happens on a single threa [](start = 15, length = 45)
why this assumption?
There was a problem hiding this comment.
This is only called in the IOLoop which is a single thread. If that wasn't true then TryDequeue could dequeue wrong item than we peeked
|
I added minor comments. modulo @stephentoub comments it LGTM |
| SerialStreamIORequest result = new SerialStreamIORequest(cancellationToken, buffer); | ||
| _writeQueue.Enqueue(result); | ||
| return result.Task; | ||
| } |
There was a problem hiding this comment.
We should override the Read/WriteAsync methods that take a {ReadOnly}Memory<byte> as well.
There was a problem hiding this comment.
@stephentoub this currently targets netstandard so those are not present there yet
| SafeFileHandle handle = Interop.Serial.SerialPortOpen(portName); | ||
| if (handle.IsInvalid) | ||
| { | ||
| throw new UnauthorizedAccessException(string.Format(SR.UnauthorizedAccess_IODenied_Port, portName)); |
There was a problem hiding this comment.
The only reason this might fail is because of unauthorized access? Is that the only exception we might throw on Windows?
There was a problem hiding this comment.
Good question. Windows does GetExceptionForLastWin32Error which in the most common case throws UnauthorizedAccessException. On Linux equivalent function (Interop.GetIOException(Interop.Sys.GetLastErrorInfo())) throws:
System.IO.IOException: Device or resource busy. The tests and users I think will expect UnauthorizedAccessException (even though IOException probably makes would make more sense if we rewrote it from scratch).
Is there any specific error you have in mind? I think always throwing UnauthorizedAccessException makes sense as it is the most common case but perhaps we could fix that in Interop.GetIOException.
thoughts?
| } | ||
| remove | ||
| { | ||
| _dataReceived -= value; |
There was a problem hiding this comment.
Can you stop the loop if _dataReceived becomes null?
There was a problem hiding this comment.
it does stop after 2s if there are no new read/write requests
| bool hasPendingReads = !_readQueue.IsEmpty; | ||
| bool hasPendingWrites = !_writeQueue.IsEmpty; | ||
|
|
||
| bool hasPendingIO = hasPendingReads || hasPendingWrites; |
There was a problem hiding this comment.
Is there a reason to store these into locals rather than just making this be:
bool hasPendingIO = !_readQueue.IsEmpty || !_writeQueue.IsEmpty;? From my perspective, that makes the code easier to read, but there's also a (small) perf benefit, in that we don't have to check whether there are any writes if there are reads.
There was a problem hiding this comment.
will create follow up PR with this change
There was a problem hiding this comment.
actually no, I use them later when calling poll
…et/corefx#33027) * SerialPort - initial async implementation on Linux and bugfixes * Apply review feedback * Fix dequeueing on Release builds * Remove InternalResources.Windows.cs (use Win32Marshal.cs from Common folder) * Fix build errors on Windows * fix build errors on uap * Apply review feedback (+ IOLoop pausing when no activity) * Fix comment * apply feedback * Remove code duplication Commit migrated from dotnet/corefx@d69f113
Most interesting file is SerialStream.Unix.cs
There are still lots of failures, all of them are marked with custom
[KnownFailure]- most of the tests won't run on CI because it doesn't have physical port.Things known to still be broken on Linux:
Things which might need improvement: