From 6eedab17b4eed27850ea899bd122d04b2e800f38 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Mon, 14 Nov 2016 00:33:28 +0100 Subject: [PATCH] Added wrapper around goselect library. This simplifies handling of select syscall. --- serial_unix.go | 17 ++------ unixutils/select.go | 101 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 14 deletions(-) create mode 100644 unixutils/select.go diff --git a/serial_unix.go b/serial_unix.go index a4ca1ee..696b3b5 100644 --- a/serial_unix.go +++ b/serial_unix.go @@ -17,8 +17,6 @@ import ( "unsafe" "go.bug.st/serial.v1/unixutils" - - "github.com/creack/goselect" ) type unixPort struct { @@ -55,18 +53,9 @@ func (port *unixPort) Read(p []byte) (n int, err error) { port.closeLock.RLock() defer port.closeLock.RUnlock() - r := &goselect.FDSet{} - r.Set(uintptr(port.handle)) - r.Set(uintptr(port.closeSignal.ReadFD())) - e := &goselect.FDSet{} - e.Set(uintptr(port.handle)) - e.Set(uintptr(port.closeSignal.ReadFD())) - - max := port.closeSignal.ReadFD() - if port.handle > max { - max = port.handle - } - if err = goselect.Select(max+1, r, nil, e, -1); err != nil { + fds := unixutils.NewFDSet(port.handle, port.closeSignal.ReadFD()) + res, err := unixutils.Select(fds, nil, fds, -1) + if err != nil { return 0, err } return syscall.Read(port.handle, p) diff --git a/unixutils/select.go b/unixutils/select.go new file mode 100644 index 0000000..bb73b1b --- /dev/null +++ b/unixutils/select.go @@ -0,0 +1,101 @@ +// +// Copyright 2014-2016 Cristian Maglie. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// + +// +build linux darwin freebsd + +package unixutils // "go.bug.st/serial.v1/unixutils" + +import ( + "time" + + "github.com/creack/goselect" +) + +// FDSet is a set of file descriptors suitable for a select call +type FDSet struct { + set goselect.FDSet + max uintptr +} + +// NewFDSet creates a set of file descriptors suitable for a Select call. +func NewFDSet(fds ...int) *FDSet { + s := &FDSet{} + s.Add(fds...) + return s +} + +// Add adds the file descriptors passed as parameter to the FDSet. +func (s *FDSet) Add(fds ...int) { + for _, fd := range fds { + f := uintptr(fd) + s.set.Set(f) + if f > s.max { + s.max = f + } + } +} + +// FDResultSets contains the result of a Select operation. +type FDResultSets struct { + readable *goselect.FDSet + writeable *goselect.FDSet + errors *goselect.FDSet +} + +// IsReadable test if a file descriptor is ready to be read. +func (r *FDResultSets) IsReadable(fd int) bool { + return r.readable.IsSet(uintptr(fd)) +} + +// IsWritable test if a file descriptor is ready to be written. +func (r *FDResultSets) IsWritable(fd int) bool { + return r.writeable.IsSet(uintptr(fd)) +} + +// IsError test if a file descriptor is in error state. +func (r *FDResultSets) IsError(fd int) bool { + return r.errors.IsSet(uintptr(fd)) +} + +// Select performs a select system call, +// file descriptors in the rd set are tested for read-events, +// file descriptors in the wd set are tested for write-events and +// file descriptors in the er set are tested for error-events. +// The function will block until an event happens or the timeout expires. +// The function return an FDResultSets that contains all the file descriptor +// that have a pending read/write/error event. +func Select(rd, wr, er *FDSet, timeout time.Duration) (*FDResultSets, error) { + max := uintptr(0) + res := &FDResultSets{} + if rd != nil { + // fdsets are copied so the parameters are left untouched + copyOfRd := rd.set + res.readable = ©OfRd + // Determine max fd. + max = rd.max + } + if wr != nil { + // fdsets are copied so the parameters are left untouched + copyOfWr := wr.set + res.writeable = ©OfWr + // Determine max fd. + if wr.max > max { + max = wr.max + } + } + if er != nil { + // fdsets are copied so the parameters are left untouched + copyOfEr := er.set + res.errors = ©OfEr + // Determine max fd. + if er.max > max { + max = er.max + } + } + + err := goselect.Select(int(max+1), res.readable, res.writeable, res.errors, timeout) + return res, err +}