unix: Fixed race condition while closing serial port. Added PortClosed error
This commit is contained in:
@@ -100,6 +100,8 @@ const (
|
|||||||
InvalidStopBits
|
InvalidStopBits
|
||||||
// ErrorEnumeratingPorts an error occurred while listing serial port
|
// ErrorEnumeratingPorts an error occurred while listing serial port
|
||||||
ErrorEnumeratingPorts
|
ErrorEnumeratingPorts
|
||||||
|
// PortClosed the port has been closed while the operation is in progress
|
||||||
|
PortClosed
|
||||||
)
|
)
|
||||||
|
|
||||||
// EncodedErrorString returns a string explaining the error code
|
// EncodedErrorString returns a string explaining the error code
|
||||||
@@ -123,6 +125,8 @@ func (e PortError) EncodedErrorString() string {
|
|||||||
return "Port stop bits invalid or not supported"
|
return "Port stop bits invalid or not supported"
|
||||||
case ErrorEnumeratingPorts:
|
case ErrorEnumeratingPorts:
|
||||||
return "Could not enumerate serial ports"
|
return "Could not enumerate serial ports"
|
||||||
|
case PortClosed:
|
||||||
|
return "Port has been closed"
|
||||||
default:
|
default:
|
||||||
return "Other error"
|
return "Other error"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ type unixPort struct {
|
|||||||
|
|
||||||
closeLock sync.RWMutex
|
closeLock sync.RWMutex
|
||||||
closeSignal *unixutils.Pipe
|
closeSignal *unixutils.Pipe
|
||||||
|
opened bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (port *unixPort) Close() error {
|
func (port *unixPort) Close() error {
|
||||||
@@ -32,6 +33,7 @@ func (port *unixPort) Close() error {
|
|||||||
if err := syscall.Close(port.handle); err != nil {
|
if err := syscall.Close(port.handle); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
port.opened = false
|
||||||
|
|
||||||
if port.closeSignal != nil {
|
if port.closeSignal != nil {
|
||||||
// Send close signal to all pending reads (if any)
|
// Send close signal to all pending reads (if any)
|
||||||
@@ -52,12 +54,18 @@ func (port *unixPort) Close() error {
|
|||||||
func (port *unixPort) Read(p []byte) (n int, err error) {
|
func (port *unixPort) Read(p []byte) (n int, err error) {
|
||||||
port.closeLock.RLock()
|
port.closeLock.RLock()
|
||||||
defer port.closeLock.RUnlock()
|
defer port.closeLock.RUnlock()
|
||||||
|
if !port.opened {
|
||||||
|
return 0, &PortError{code: PortClosed}
|
||||||
|
}
|
||||||
|
|
||||||
fds := unixutils.NewFDSet(port.handle, port.closeSignal.ReadFD())
|
fds := unixutils.NewFDSet(port.handle, port.closeSignal.ReadFD())
|
||||||
res, err := unixutils.Select(fds, nil, fds, -1)
|
res, err := unixutils.Select(fds, nil, fds, -1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
if res.IsReadable(port.closeSignal.ReadFD()) {
|
||||||
|
return 0, &PortError{code: PortClosed}
|
||||||
|
}
|
||||||
return syscall.Read(port.handle, p)
|
return syscall.Read(port.handle, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,6 +106,7 @@ func nativeOpen(portName string, mode *Mode) (*unixPort, error) {
|
|||||||
}
|
}
|
||||||
port := &unixPort{
|
port := &unixPort{
|
||||||
handle: h,
|
handle: h,
|
||||||
|
opened: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup serial port
|
// Setup serial port
|
||||||
@@ -127,7 +136,7 @@ func nativeOpen(portName string, mode *Mode) (*unixPort, error) {
|
|||||||
|
|
||||||
port.acquireExclusiveAccess()
|
port.acquireExclusiveAccess()
|
||||||
|
|
||||||
// This pipe is used as a signal to cancel blocking Read or Write
|
// This pipe is used as a signal to cancel blocking Read
|
||||||
pipe := &unixutils.Pipe{}
|
pipe := &unixutils.Pipe{}
|
||||||
if err := pipe.Open(); err != nil {
|
if err := pipe.Open(); err != nil {
|
||||||
port.Close()
|
port.Close()
|
||||||
|
|||||||
Reference in New Issue
Block a user