{
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_Shutdown")]
internal static extern Error Shutdown(SafeHandle socket, SocketShutdown how);
+
+ [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_Shutdown")]
+ internal static extern Error Shutdown(IntPtr socket, SocketShutdown how);
}
}
// See the LICENSE file in the project root for more information.
#include "pal_types.h"
+#include "pal_utilities.h"
#include <fcntl.h>
#include <errno.h>
#include <pal_serial.h>
return fd;
}
+
+int SystemIoPortsNative_SerialPortClose(intptr_t handle)
+{
+ int fd = ToFileDescriptor(handle);
+ // some devices don't unlock handles from exclusive access
+ // preventing reopening after closing the handle
+
+ // ignoring the error - best effort
+ ioctl(fd, TIOCNXCL);
+ return close(fd);
+}
#include "pal_compiler.h"
DLLEXPORT intptr_t SystemIoPortsNative_SerialPortOpen(const char * name);
-
+DLLEXPORT int SystemIoPortsNative_SerialPortClose(intptr_t fd);
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System;
using System.IO.Ports;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
internal static partial class Serial
{
[DllImport(Libraries.IOPortsNative, EntryPoint = "SystemIoPortsNative_SerialPortOpen", SetLastError = true)]
- internal static extern SafeFileHandle SerialPortOpen(string name);
+ internal static extern SafeSerialDeviceHandle SerialPortOpen(string name);
+
+ [DllImport(Libraries.IOPortsNative, EntryPoint = "SystemIoPortsNative_SerialPortClose", SetLastError = true)]
+ internal static extern int SerialPortClose(IntPtr handle);
}
}
}
[DllImport(Libraries.IOPortsNative, EntryPoint = "SystemIoPortsNative_TermiosReset", SetLastError = true)]
- internal static extern int TermiosReset(SafeFileHandle handle, int speed, int data, StopBits stop, Parity parity, Handshake flow);
+ internal static extern int TermiosReset(SafeSerialDeviceHandle handle, int speed, int data, StopBits stop, Parity parity, Handshake flow);
[DllImport(Libraries.IOPortsNative, EntryPoint = "SystemIoPortsNative_TermiosGetSignal", SetLastError = true)]
- internal static extern int TermiosGetSignal(SafeFileHandle handle, Signals signal);
+ internal static extern int TermiosGetSignal(SafeSerialDeviceHandle handle, Signals signal);
[DllImport(Libraries.IOPortsNative, EntryPoint = "SystemIoPortsNative_TermiosSetSignal", SetLastError = true)]
- internal static extern int TermiosGetSignal(SafeFileHandle handle, Signals signal, int set);
+ internal static extern int TermiosGetSignal(SafeSerialDeviceHandle handle, Signals signal, int set);
[DllImport(Libraries.IOPortsNative, EntryPoint = "SystemIoPortsNative_TermiosSetSpeed", SetLastError = true)]
- internal static extern int TermiosSetSpeed(SafeFileHandle handle, int speed);
+ internal static extern int TermiosSetSpeed(SafeSerialDeviceHandle handle, int speed);
[DllImport(Libraries.IOPortsNative, EntryPoint = "SystemIoPortsNative_TermiosGetSpeed", SetLastError = true)]
- internal static extern int TermiosGetSpeed(SafeFileHandle handle);
+ internal static extern int TermiosGetSpeed(SafeSerialDeviceHandle handle);
[DllImport(Libraries.IOPortsNative, EntryPoint = "SystemIoPortsNative_TermiosAvailableBytes", SetLastError = true)]
- internal static extern int TermiosGetAvailableBytes(SafeFileHandle handle, Queue input);
+ internal static extern int TermiosGetAvailableBytes(SafeSerialDeviceHandle handle, Queue input);
[DllImport(Libraries.IOPortsNative, EntryPoint = "SystemIoPortsNative_TermiosDiscard", SetLastError = true)]
- internal static extern int TermiosDiscard(SafeFileHandle handle, Queue input);
+ internal static extern int TermiosDiscard(SafeSerialDeviceHandle handle, Queue input);
[DllImport(Libraries.IOPortsNative, EntryPoint = "SystemIoPortsNative_TermiosDrain", SetLastError = true)]
- internal static extern int TermiosDrain(SafeFileHandle handle);
+ internal static extern int TermiosDrain(SafeSerialDeviceHandle handle);
[DllImport(Libraries.IOPortsNative, EntryPoint = "SystemIoPortsNative_TermiosSendBreak", SetLastError = true)]
- internal static extern int TermiosSendBreak(SafeFileHandle handle, int duration);
+ internal static extern int TermiosSendBreak(SafeSerialDeviceHandle handle, int duration);
}
}
<Compile Include="System\IO\Ports\SerialStream.Win32.cs" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetsLinux)' == 'true' ">
+ <Compile Include="System\IO\Ports\SafeSerialDeviceHandle.Unix.cs" />
<Compile Include="System\IO\Ports\SerialPort.Linux.cs" />
<Compile Include="System\IO\Ports\SerialStream.Unix.cs" />
<Compile Include="Interop\Unix\Interop.Termios.cs" />
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Net.Sockets;
+using System.Runtime.InteropServices;
+using Microsoft.Win32.SafeHandles;
+
+namespace System.IO.Ports
+{
+ internal sealed class SafeSerialDeviceHandle : SafeHandleMinusOneIsInvalid
+ {
+ private SafeSerialDeviceHandle() : base(ownsHandle: true)
+ {
+ }
+
+ internal static SafeSerialDeviceHandle Open(string portName)
+ {
+ Debug.Assert(portName != null);
+ SafeSerialDeviceHandle handle = Interop.Serial.SerialPortOpen(portName);
+
+ if (handle.IsInvalid)
+ {
+ // exception type is matching Windows
+ throw new UnauthorizedAccessException(
+ SR.Format(SR.UnauthorizedAccess_IODenied_Port, portName),
+ Interop.GetIOException(Interop.Sys.GetLastErrorInfo()));
+ }
+
+ return handle;
+ }
+
+ protected override bool ReleaseHandle()
+ {
+ Interop.Sys.Shutdown(handle, SocketShutdown.Both);
+ int result = Interop.Serial.SerialPortClose(handle);
+
+ Debug.Assert(result == 0, string.Format(
+ "Close failed with result {0} and error {1}",
+ result, Interop.Sys.GetLastErrorInfo()));
+
+ return result == 0;
+ }
+ }
+}
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using Microsoft.Win32.SafeHandles;
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.IO.Ports;
using System.Threading;
using System.Threading.Tasks;
-using System.Net.Sockets;
namespace System.IO.Ports
{
private const int IOLoopIdleTimeout = 2000;
private bool _ioLoopFinished = false;
+ private SafeSerialDeviceHandle _handle = null;
private int _baudRate;
private StopBits _stopBits;
private Parity _parity;
}
}
- internal SafeFileHandle OpenPort(string portName)
- {
- SafeFileHandle handle = Interop.Serial.SerialPortOpen(portName);
- if (handle.IsInvalid)
- {
- throw new UnauthorizedAccessException(string.Format(SR.UnauthorizedAccess_IODenied_Port, portName));
- }
-
- return handle;
- }
-
// this method is used by SerialPort upon SerialStream's creation
internal SerialStream(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits, int readTimeout, int writeTimeout, Handshake handshake,
bool dtrEnable, bool rtsEnable, bool discardNull, byte parityReplace)
// Error checking done in SerialPort.
- SafeFileHandle tempHandle = OpenPort(portName);
+ SafeSerialDeviceHandle tempHandle = SafeSerialDeviceHandle.Open(portName);
try
{
{
// if there are any exceptions after the call to CreateFile, we need to be sure to close the
// handle before we let them continue up.
- tempHandle.Close();
+ tempHandle.Dispose();
_handle = null;
throw;
}
FinishPendingIORequests();
- // Signal the other side that we're closing. Should do regardless of whether we've called
- // Close() or not Dispose()
- if (_handle != null && !_handle.IsInvalid)
+ if (_handle != null)
{
- Interop.Sys.Shutdown(_handle, SocketShutdown.Both);
- _handle.Close();
+ _handle.Dispose();
_handle = null;
}
}
// called when one character is received.
internal event SerialDataReceivedEventHandler DataReceived;
+ private SafeFileHandle _handle = null;
+
// members supporting properties exposed to SerialPort
private byte _parityReplace = (byte)'?';
private bool _isAsync = true;
private bool _inBreak = false;
private Handshake _handshake;
- private SafeFileHandle _handle = null;
-
#pragma warning disable CS0067 // Events shared by Windows and Linux, on Linux we currently never call them
// called when any of the pin/ring-related triggers occurs
internal event SerialPinChangedEventHandler PinChanged;