From d50de5cbafa06d8f9396fd4507b07be65a786d56 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Mon, 14 Nov 2016 00:31:01 +0100 Subject: [PATCH] unix: Fixed race condition while closing serial port. Added PortClosed error --- serial.go | 4 ++++ serial_unix.go | 11 ++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/serial.go b/serial.go index 6b932d0..eb8a301 100644 --- a/serial.go +++ b/serial.go @@ -100,6 +100,8 @@ const ( InvalidStopBits // ErrorEnumeratingPorts an error occurred while listing serial port ErrorEnumeratingPorts + // PortClosed the port has been closed while the operation is in progress + PortClosed ) // 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" case ErrorEnumeratingPorts: return "Could not enumerate serial ports" + case PortClosed: + return "Port has been closed" default: return "Other error" } diff --git a/serial_unix.go b/serial_unix.go index 696b3b5..49f5903 100644 --- a/serial_unix.go +++ b/serial_unix.go @@ -24,6 +24,7 @@ type unixPort struct { closeLock sync.RWMutex closeSignal *unixutils.Pipe + opened bool } func (port *unixPort) Close() error { @@ -32,6 +33,7 @@ func (port *unixPort) Close() error { if err := syscall.Close(port.handle); err != nil { return err } + port.opened = false if port.closeSignal != nil { // 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) { port.closeLock.RLock() defer port.closeLock.RUnlock() + if !port.opened { + return 0, &PortError{code: PortClosed} + } fds := unixutils.NewFDSet(port.handle, port.closeSignal.ReadFD()) res, err := unixutils.Select(fds, nil, fds, -1) if err != nil { return 0, err } + if res.IsReadable(port.closeSignal.ReadFD()) { + return 0, &PortError{code: PortClosed} + } return syscall.Read(port.handle, p) } @@ -98,6 +106,7 @@ func nativeOpen(portName string, mode *Mode) (*unixPort, error) { } port := &unixPort{ handle: h, + opened: true, } // Setup serial port @@ -127,7 +136,7 @@ func nativeOpen(portName string, mode *Mode) (*unixPort, error) { 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{} if err := pipe.Open(); err != nil { port.Close()