unix: Fixed race condition while closing serial port. Added PortClosed error

This commit is contained in:
Cristian Maglie
2016-11-14 00:31:01 +01:00
parent 6eedab17b4
commit d50de5cbaf
2 changed files with 14 additions and 1 deletions

View File

@@ -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"
}

View File

@@ -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()