pax_global_header00006660000000000000000000000064140134722740014516gustar00rootroot0000000000000052 comment=f0c0d6863fbc64e624a609fafff94db2281647cd goselect-0.1.2/000077500000000000000000000000001401347227400133235ustar00rootroot00000000000000goselect-0.1.2/.gitignore000066400000000000000000000004721401347227400153160ustar00rootroot00000000000000# Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe *.test *.prof go-select* goselect* example-* example/example goselect-0.1.2/Dockerfile000066400000000000000000000002301401347227400153100ustar00rootroot00000000000000FROM google/golang:stable MAINTAINER Guillaume J. Charmes CMD /tmp/a.out ADD . /src RUN cd /src && go build -o /tmp/a.out goselect-0.1.2/LICENSE000066400000000000000000000021001401347227400143210ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2014 Guillaume J. Charmes Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. goselect-0.1.2/README.md000066400000000000000000000066721401347227400146150ustar00rootroot00000000000000# go-select select(2) implementation in Go ## Supported platforms | | 386 | amd64 | arm | arm64 | mips | mipsle | mips64 | mips64le | ppc64le | s390x | |---------------|-----|-------|-----|-------|------|--------|--------|----------|---------|-------| | **linux** | yes | yes | yes | yes | yes | yes | yes | yes | yes | yes | | **darwin** | yes | yes | ?? | ?? | n/a | n/a | n/a | n/a | n/a | n/a | | **freebsd** | yes | yes | yes | n/a | n/a | n/a | n/a | n/a | n/a | n/a | | **openbsd** | yes | yes | yes | n/a | n/a | n/a | n/a | n/a | n/a | n/a | | **netbsd** | yes | yes | yes | n/a | n/a | n/a | n/a | n/a | n/a | n/a | | **dragonfly** | n/a | yes | n/a | n/a | n/a | n/a | n/a | n/a | n/a | n/a | | **solaris** | n/a | no | n/a | n/a | n/a | n/a | n/a | n/a | n/a | n/a | | **plan9** | no | no | no | n/a | n/a | n/a | n/a | n/a | n/a | n/a | | **windows** | yes | yes | n/a | n/a | n/a | n/a | n/a | n/a | n/a | n/a | | **android** | ?? | ?? | ?? | ?? | n/a | n/a | n/a | n/a | n/a | n/a | *n/a: platform not supported by Go *??: not tested Go on `plan9` and `solaris` do not implement `syscall.Select` nor `syscall.SYS_SELECT`. ## Cross compile test Note that this only tests the compilation, not the functionality. ```sh $> ./test_crosscompile.sh > /dev/null | sort [OK] android/386 [OK] android/amd64 [OK] android/arm [OK] android/arm64 [OK] darwin/386 [OK] darwin/amd64 [OK] darwin/arm [OK] darwin/arm64 [OK] dragonfly/amd64 [OK] freebsd/386 [OK] freebsd/amd64 [OK] freebsd/arm [OK] linux/386 [OK] linux/amd64 [OK] linux/arm [OK] linux/arm64 [OK] linux/mips [OK] linux/mips64 [OK] linux/mips64le [OK] linux/mipsle [OK] linux/ppc64le [OK] linux/s390x [OK] netbsd/386 [OK] netbsd/amd64 [OK] netbsd/arm [OK] openbsd/386 [OK] openbsd/amd64 [OK] openbsd/arm [OK] plan9/386 [OK] plan9/amd64 [OK] plan9/arm [OK] solaris/amd64 [OK] windows/386 [OK] windows/amd64 [OK] windows/arm # Expected failures. [KO] android/mips [KO] android/mips64 [KO] android/mips64le [KO] android/mipsle [KO] android/ppc64le [KO] android/s390x [KO] darwin/mips [KO] darwin/mips64 [KO] darwin/mips64le [KO] darwin/mipsle [KO] darwin/ppc64le [KO] darwin/s390x [KO] dragonfly/386 [KO] dragonfly/arm [KO] dragonfly/arm64 [KO] dragonfly/mips [KO] dragonfly/mips64 [KO] dragonfly/mips64le [KO] dragonfly/mipsle [KO] dragonfly/ppc64le [KO] dragonfly/s390x [KO] freebsd/arm64 [KO] freebsd/mips [KO] freebsd/mips64 [KO] freebsd/mips64le [KO] freebsd/mipsle [KO] freebsd/ppc64le [KO] freebsd/s390x [KO] netbsd/arm64 [KO] netbsd/mips [KO] netbsd/mips64 [KO] netbsd/mips64le [KO] netbsd/mipsle [KO] netbsd/ppc64le [KO] netbsd/s390x [KO] openbsd/arm64 [KO] openbsd/mips [KO] openbsd/mips64 [KO] openbsd/mips64le [KO] openbsd/mipsle [KO] openbsd/ppc64le [KO] openbsd/s390x [KO] plan9/arm64 [KO] plan9/mips [KO] plan9/mips64 [KO] plan9/mips64le [KO] plan9/mipsle [KO] plan9/ppc64le [KO] plan9/s390x [KO] solaris/386 [KO] solaris/arm [KO] solaris/arm64 [KO] solaris/mips [KO] solaris/mips64 [KO] solaris/mips64le [KO] solaris/mipsle [KO] solaris/ppc64le [KO] solaris/s390x [KO] windows/arm64 [KO] windows/mips [KO] windows/mips64 [KO] windows/mips64le [KO] windows/mipsle [KO] windows/ppc64le [KO] windows/s390x ``` ## License Released under the [MIT license](LICENSE). goselect-0.1.2/example/000077500000000000000000000000001401347227400147565ustar00rootroot00000000000000goselect-0.1.2/example/main.go000066400000000000000000000144571401347227400162440ustar00rootroot00000000000000package main import ( "fmt" "io" "log" "net" "os" "sync" "time" "github.com/creack/goselect" ) type fder interface { Fd() uintptr } // ErrNotFder . var ErrNotFder = fmt.Errorf("Not a fder") type readFder interface { io.Reader fder } type writeFder interface { io.Reader fder } // SelectReader . type selectReader struct { readFder ready chan struct{} stop chan struct{} } func (r *selectReader) Read(buf []byte) (int, error) { select { case <-r.stop: return 0, io.EOF case <-r.ready: return r.readFder.Read(buf) } } // Select . type Select struct { readers []*selectReader writers []writeFder controlPipeR *os.File controlPipeW *os.File } // NewSelect . func NewSelect() (*Select, error) { r, w, err := os.Pipe() if err != nil { return nil, err } s := &Select{ readers: []*selectReader{}, writers: []writeFder{}, controlPipeR: r, controlPipeW: w, } return s, nil } func (s *Select) run() { rFDSet := &goselect.FDSet{} var max uintptr var fd uintptr for { // TODO: this can be cached and changed only upon controlePipe event. rFDSet.Zero() fd = s.controlPipeR.Fd() max = fd rFDSet.Set(fd) for _, r := range s.readers { fd = r.Fd() if max < fd { max = fd } rFDSet.Set(fd) } println("-------> preselect") if err := goselect.Select(int(max)+1, rFDSet, nil, nil, -1); err != nil { log.Fatal(err) } for i := uintptr(0); i < goselect.FD_SETSIZE; i++ { if rFDSet.IsSet(i) { println(i, "is ready") } } println("<-------- postselect") for _, r := range s.readers { if rFDSet.IsSet(r.Fd()) { func(r *selectReader) { r.ready <- struct{}{} }(r) } } if rFDSet.IsSet(s.controlPipeR.Fd()) { buf := make([]byte, 1024) n, err := s.controlPipeR.Read(buf) if err != nil { if err == io.EOF { break } log.Fatal(err) } fmt.Printf("----> control: %s\n", buf[:n]) } } } // NewReader . func (s *Select) NewReader(r io.Reader) (io.Reader, error) { rr, ok := r.(readFder) if !ok { return nil, ErrNotFder } ret := &selectReader{ readFder: rr, ready: make(chan struct{}), stop: make(chan struct{}), } s.readers = append(s.readers, ret) if _, err := s.controlPipeW.Write([]byte("newreader")); err != nil { return nil, err } return ret, nil } func test6() error { s, err := NewSelect() if err != nil { return err } _ = s fmt.Printf("%d\n", os.Getpid()) const MAX = 4 rs := []io.Reader{} ws := []io.Writer{} for i := 0; i < MAX; i++ { r, w, _ := os.Pipe() println(i, "--->", r.Fd(), w.Fd()) rs = append(rs, r) ws = append(ws, w) } c := make(chan struct{}) wg := sync.WaitGroup{} for i := 0; i < MAX; i++ { wg.Add(1) go func() { time.Sleep(2 * time.Second) <-c wg.Done() }() } time.Sleep(4 * time.Second) close(c) wg.Wait() for i := 0; i < MAX; i++ { time.Sleep(5 * time.Second) wg.Add(1) go func(r io.Reader, i int) { rr, _ := s.NewReader(r) r = rr buf := make([]byte, 1024) for { n, err := r.Read(buf) if err != nil { log.Printf("[%d] error read: %s\n", i, err) break } _ = n fmt.Printf("[%d] %s\n", i, buf[:n]) } wg.Done() }(rs[i], i) } for i := 0; i < 1; i++ { for i := 0; i < MAX; i++ { fmt.Fprintf(ws[i], "{%d} hello", i) } time.Sleep(5 * time.Second) } wg.Wait() return nil } func test4() error { rFDSet := &goselect.FDSet{} buf := make([]byte, 1024) for { // TODO: this can be cached and changed only upon controlePipe event. rFDSet.Zero() rFDSet.Set(os.Stdin.Fd()) if err := goselect.Select(int(os.Stdin.Fd())+1, rFDSet, nil, nil, -1); err != nil { return err } for i := uintptr(0); i < goselect.FD_SETSIZE; i++ { if rFDSet.IsSet(i) { println(i, "is ready") } } if rFDSet.IsSet(os.Stdin.Fd()) { n, err := os.Stdin.Read(buf) if err != nil { if err == io.EOF { break } return err } fmt.Printf("---->: %s\n", buf[:n]) } } return nil } type Client struct { f *os.File queue [][]byte } func (c *Client) Push(msg []byte) { c.queue = append(c.queue, msg) println(len(c.queue)) } func (c *Client) Pop() []byte { if len(c.queue) == 0 { return nil } tmp := c.queue[0] c.queue = c.queue[1:] return tmp } func testServer() error { l, err := net.Listen("tcp", "0.0.0.0:8080") if err != nil { return err } ll, ok := l.(*net.TCPListener) if !ok { return fmt.Errorf("wrong listener type") } llf, err := ll.File() if err != nil { return err } rFDSet := &goselect.FDSet{} wFDSet := &goselect.FDSet{} buf := make([]byte, 1024) var max, fd uintptr clients := []*Client{} for { // TODO: this can be cached and changed only upon controlePipe event. rFDSet.Zero() wFDSet.Zero() fd = llf.Fd() max = fd rFDSet.Set(fd) for _, c := range clients { fd = c.f.Fd() rFDSet.Set(fd) if len(c.queue) > 0 { wFDSet.Set(fd) } if max < fd { max = fd } } if err := goselect.Select(int(max)+1, rFDSet, wFDSet, nil, -1); err != nil { return err } println("-->") // Watch for new clients if rFDSet.IsSet(llf.Fd()) { c, err := ll.AcceptTCP() if err != nil { return err } f, err := c.File() if err != nil { return err } fd = f.Fd() println("New client:", fd) clients = append(clients, &Client{f: f}) } // Watch for client activity for _, c := range clients { fd = c.f.Fd() if rFDSet.IsSet(fd) { n, err := c.f.Read(buf) if err != nil { return err } fmt.Printf("%s", buf[:n]) for _, cc := range clients { if c != cc { cc.Push(buf[:n]) } } } } // Send message to clients for _, c := range clients { fd = c.f.Fd() if wFDSet.IsSet(fd) { msg := c.Pop() fmt.Printf("%d write ready: %v\n", fd, msg) if msg != nil { _, err := c.f.Write(msg) if err != nil { return err } } } } } } func main() { if err := testServer(); err != nil { log.Fatal(err) } } func test5() error { wg := sync.WaitGroup{} fmt.Printf("%d\n", os.Getpid()) for i := 0; i < 200; i++ { r, w, _ := os.Pipe() go func(w io.Writer) { for { w.Write([]byte("hello")) time.Sleep(time.Second) } }(w) wg.Add(1) go func(r io.Reader) { buf := make([]byte, 1024) for { _, err := r.Read(buf) if err != nil { log.Fatal(err) } } }(r) } wg.Wait() return nil } goselect-0.1.2/fdset.go000066400000000000000000000013321401347227400147560ustar00rootroot00000000000000// +build !freebsd,!windows,!plan9 package goselect import "syscall" const FD_SETSIZE = syscall.FD_SETSIZE // FDSet wraps syscall.FdSet with convenience methods type FDSet syscall.FdSet // Set adds the fd to the set func (fds *FDSet) Set(fd uintptr) { fds.Bits[fd/NFDBITS] |= (1 << (fd % NFDBITS)) } // Clear remove the fd from the set func (fds *FDSet) Clear(fd uintptr) { fds.Bits[fd/NFDBITS] &^= (1 << (fd % NFDBITS)) } // IsSet check if the given fd is set func (fds *FDSet) IsSet(fd uintptr) bool { return fds.Bits[fd/NFDBITS]&(1<<(fd%NFDBITS)) != 0 } // Keep a null set to avoid reinstatiation var nullFdSet = &FDSet{} // Zero empties the Set func (fds *FDSet) Zero() { copy(fds.Bits[:], (nullFdSet).Bits[:]) } goselect-0.1.2/fdset_32.go000066400000000000000000000003261401347227400152640ustar00rootroot00000000000000// +build darwin openbsd netbsd 386 arm mips mipsle riscv32 package goselect // darwin, netbsd and openbsd uses uint32 on both amd64 and 386 const ( // NFDBITS is the amount of bits per mask NFDBITS = 4 * 8 ) goselect-0.1.2/fdset_64.go000066400000000000000000000003711401347227400152710ustar00rootroot00000000000000// +build !darwin,!netbsd,!openbsd // +build amd64 arm64 ppc64le mips64 mips64le s390x riscv64 package goselect // darwin, netbsd and openbsd uses uint32 on both amd64 and 386 const ( // NFDBITS is the amount of bits per mask NFDBITS = 8 * 8 ) goselect-0.1.2/fdset_doc.go000066400000000000000000000050271401347227400156100ustar00rootroot00000000000000package goselect /** From: XCode's MacOSX10.10.sdk/System/Library/Frameworks/Kernel.framework/Versions/A/Headers/sys/select.h -- // darwin/amd64 / 386 sizeof(__int32_t) == 4 -- typedef __int32_t __fd_mask; #define FD_SETSIZE 1024 #define __NFDBITS (sizeof(__fd_mask) * 8) #define __howmany(x, y) ((((x) % (y)) == 0) ? ((x) / (y)) : (((x) / (y)) + 1)) typedef struct fd_set { __fd_mask fds_bits[__howmany(__FD_SETSIZE, __NFDBITS)]; } fd_set; #define __FD_MASK(n) ((__fd_mask)1 << ((n) % __NFDBITS)) #define FD_SET(n, p) ((p)->fds_bits[(n)/__NFDBITS] |= __FD_MASK(n)) #define FD_CLR(n, p) ((p)->fds_bits[(n)/__NFDBITS] &= ~__FD_MASK(n)) #define FD_ISSET(n, p) (((p)->fds_bits[(n)/__NFDBITS] & __FD_MASK(n)) != 0) */ /** From: /usr/include/i386-linux-gnu/sys/select.h -- // linux/i686 sizeof(long int) == 4 -- typedef long int __fd_mask; #define FD_SETSIZE 1024 #define __NFDBITS (sizeof(__fd_mask) * 8) typedef struct fd_set { __fd_mask fds_bits[__FD_SETSIZE / __NFDBITS]; } fd_set; #define __FD_MASK(n) ((__fd_mask)1 << ((n) % __NFDBITS)) #define FD_SET(n, p) ((p)->fds_bits[(n)/__NFDBITS] |= __FD_MASK(n)) #define FD_CLR(n, p) ((p)->fds_bits[(n)/__NFDBITS] &= ~__FD_MASK(n)) #define FD_ISSET(n, p) (((p)->fds_bits[(n)/__NFDBITS] & __FD_MASK(n)) != 0) */ /** From: /usr/include/x86_64-linux-gnu/sys/select.h -- // linux/amd64 sizeof(long int) == 8 -- typedef long int __fd_mask; #define FD_SETSIZE 1024 #define __NFDBITS (sizeof(__fd_mask) * 8) typedef struct fd_set { __fd_mask fds_bits[__FD_SETSIZE / __NFDBITS]; } fd_set; #define __FD_MASK(n) ((__fd_mask)1 << ((n) % __NFDBITS)) #define FD_SET(n, p) ((p)->fds_bits[(n)/__NFDBITS] |= __FD_MASK(n)) #define FD_CLR(n, p) ((p)->fds_bits[(n)/__NFDBITS] &= ~__FD_MASK(n)) #define FD_ISSET(n, p) (((p)->fds_bits[(n)/__NFDBITS] & __FD_MASK(n)) != 0) */ /** From: /usr/include/sys/select.h -- // freebsd/amd64 sizeof(unsigned long) == 8 -- typedef unsigned long __fd_mask; #define FD_SETSIZE 1024U #define __NFDBITS (sizeof(__fd_mask) * 8) #define _howmany(x, y) (((x) + ((y) - 1)) / (y)) typedef struct fd_set { __fd_mask fds_bits[_howmany(FD_SETSIZE, __NFDBITS)]; } fd_set; #define __FD_MASK(n) ((__fd_mask)1 << ((n) % __NFDBITS)) #define FD_SET(n, p) ((p)->fds_bits[(n)/__NFDBITS] |= __FD_MASK(n)) #define FD_CLR(n, p) ((p)->fds_bits[(n)/__NFDBITS] &= ~__FD_MASK(n)) #define FD_ISSET(n, p) (((p)->fds_bits[(n)/__NFDBITS] & __FD_MASK(n)) != 0) */ goselect-0.1.2/fdset_freebsd.go000066400000000000000000000013541401347227400164540ustar00rootroot00000000000000// +build freebsd package goselect import "syscall" const FD_SETSIZE = syscall.FD_SETSIZE // FDSet wraps syscall.FdSet with convenience methods type FDSet syscall.FdSet // Set adds the fd to the set func (fds *FDSet) Set(fd uintptr) { fds.X__fds_bits[fd/NFDBITS] |= (1 << (fd % NFDBITS)) } // Clear remove the fd from the set func (fds *FDSet) Clear(fd uintptr) { fds.X__fds_bits[fd/NFDBITS] &^= (1 << (fd % NFDBITS)) } // IsSet check if the given fd is set func (fds *FDSet) IsSet(fd uintptr) bool { return fds.X__fds_bits[fd/NFDBITS]&(1<<(fd%NFDBITS)) != 0 } // Keep a null set to avoid reinstatiation var nullFdSet = &FDSet{} // Zero empties the Set func (fds *FDSet) Zero() { copy(fds.X__fds_bits[:], (nullFdSet).X__fds_bits[:]) } goselect-0.1.2/fdset_unsupported.go000066400000000000000000000006511401347227400174310ustar00rootroot00000000000000// +build plan9 package goselect const FD_SETSIZE = 0 // FDSet wraps syscall.FdSet with convenience methods type FDSet struct{} // Set adds the fd to the set func (fds *FDSet) Set(fd uintptr) {} // Clear remove the fd from the set func (fds *FDSet) Clear(fd uintptr) {} // IsSet check if the given fd is set func (fds *FDSet) IsSet(fd uintptr) bool { return false } // Zero empties the Set func (fds *FDSet) Zero() {} goselect-0.1.2/fdset_windows.go000066400000000000000000000017501401347227400165340ustar00rootroot00000000000000// +build windows package goselect import "syscall" const FD_SETSIZE = 64 // FDSet extracted from mingw libs source code type FDSet struct { fd_count uint fd_array [FD_SETSIZE]uintptr } // Set adds the fd to the set func (fds *FDSet) Set(fd uintptr) { var i uint for i = 0; i < fds.fd_count; i++ { if fds.fd_array[i] == fd { break } } if i == fds.fd_count { if fds.fd_count < FD_SETSIZE { fds.fd_array[i] = fd fds.fd_count++ } } } // Clear remove the fd from the set func (fds *FDSet) Clear(fd uintptr) { var i uint for i = 0; i < fds.fd_count; i++ { if fds.fd_array[i] == fd { for i < fds.fd_count-1 { fds.fd_array[i] = fds.fd_array[i+1] i++ } fds.fd_count-- break } } } // IsSet check if the given fd is set func (fds *FDSet) IsSet(fd uintptr) bool { if isset, err := __WSAFDIsSet(syscall.Handle(fd), fds); err == nil && isset != 0 { return true } return false } // Zero empties the Set func (fds *FDSet) Zero() { fds.fd_count = 0 } goselect-0.1.2/go.mod000066400000000000000000000000531401347227400144270ustar00rootroot00000000000000module github.com/creack/goselect go 1.13 goselect-0.1.2/select.go000066400000000000000000000012741401347227400151350ustar00rootroot00000000000000package goselect import ( "syscall" "time" ) // Select wraps syscall.Select with Go types func Select(n int, r, w, e *FDSet, timeout time.Duration) error { var timeval *syscall.Timeval if timeout >= 0 { t := syscall.NsecToTimeval(timeout.Nanoseconds()) timeval = &t } return sysSelect(n, r, w, e, timeval) } // RetrySelect wraps syscall.Select with Go types, and retries a number of times, with a given retryDelay. func RetrySelect(n int, r, w, e *FDSet, timeout time.Duration, retries int, retryDelay time.Duration) (err error) { for i := 0; i < retries; i++ { if err = Select(n, r, w, e, timeout); err != syscall.EINTR { return err } time.Sleep(retryDelay) } return err } goselect-0.1.2/select_linux.go000066400000000000000000000003601401347227400163470ustar00rootroot00000000000000// +build linux package goselect import "syscall" func sysSelect(n int, r, w, e *FDSet, timeout *syscall.Timeval) error { _, err := syscall.Select(n, (*syscall.FdSet)(r), (*syscall.FdSet)(w), (*syscall.FdSet)(e), timeout) return err } goselect-0.1.2/select_other.go000066400000000000000000000003731401347227400163350ustar00rootroot00000000000000// +build !linux,!windows,!plan9,!solaris package goselect import "syscall" func sysSelect(n int, r, w, e *FDSet, timeout *syscall.Timeval) error { return syscall.Select(n, (*syscall.FdSet)(r), (*syscall.FdSet)(w), (*syscall.FdSet)(e), timeout) } goselect-0.1.2/select_test.go000066400000000000000000000021121401347227400161640ustar00rootroot00000000000000package goselect import ( "fmt" "io" "os" "testing" "time" ) type fder interface { Fd() uintptr } func TestReadWriteSync(t *testing.T) { const count = 50 rrs := []io.Reader{} wws := []io.Writer{} rFDSet := &FDSet{} for i := 0; i < count; i++ { rr, ww, err := os.Pipe() if err != nil { t.Fatal(err) } rrs = append(rrs, rr) wws = append(wws, ww) } go func() { time.Sleep(time.Second) for i := 0; i < count; i++ { fmt.Fprintf(wws[i], "hello %d", i) time.Sleep(time.Millisecond) } }() buf := make([]byte, 1024) for i := 0; i < count; i++ { rFDSet.Zero() for i := 0; i < count; i++ { rFDSet.Set(rrs[i].(fder).Fd()) } if err := RetrySelect(1024, rFDSet, nil, nil, -1, 10, 10*time.Millisecond); err != nil { t.Fatalf("select call failed: %s", err) } for j := 0; j < count; j++ { if rFDSet.IsSet(rrs[j].(fder).Fd()) { // println(i, j) if i != j { t.Fatalf("unexpected fd ready: %d,expected: %d", j, i) } _, err := rrs[j].Read(buf) if err != nil { t.Fatalf("read call failed: %s", err) } } } } } goselect-0.1.2/select_unsupported.go000066400000000000000000000004461401347227400176050ustar00rootroot00000000000000// +build plan9 solaris package goselect import ( "fmt" "runtime" "syscall" ) // ErrUnsupported . var ErrUnsupported = fmt.Errorf("Platofrm %s/%s unsupported", runtime.GOOS, runtime.GOARCH) func sysSelect(n int, r, w, e *FDSet, timeout *syscall.Timeval) error { return ErrUnsupported } goselect-0.1.2/select_windows.go000066400000000000000000000006471401347227400167120ustar00rootroot00000000000000// +build windows package goselect import "syscall" //sys _select(nfds int, readfds *FDSet, writefds *FDSet, exceptfds *FDSet, timeout *syscall.Timeval) (total int, err error) = ws2_32.select //sys __WSAFDIsSet(handle syscall.Handle, fdset *FDSet) (isset int, err error) = ws2_32.__WSAFDIsSet func sysSelect(n int, r, w, e *FDSet, timeout *syscall.Timeval) error { _, err := _select(n, r, w, e, timeout) return err } goselect-0.1.2/test_crosscompile.sh000077500000000000000000000335641401347227400174360ustar00rootroot00000000000000rm -rf crosstest mkdir -p crosstest export GOOS=linux; export GOARCH=arm; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=linux; export GOARCH=arm64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=linux; export GOARCH=amd64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=linux; export GOARCH=386; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=linux; export GOARCH=mips; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=linux; export GOARCH=mipsle; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=linux; export GOARCH=mips64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=linux; export GOARCH=mips64le; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=linux; export GOARCH=ppc64le; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=linux; export GOARCH=s390x; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=darwin; export GOARCH=arm; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=darwin; export GOARCH=arm64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=darwin; export GOARCH=amd64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=darwin; export GOARCH=386; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=darwin; export GOARCH=mips; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=darwin; export GOARCH=mipsle; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=darwin; export GOARCH=mips64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=darwin; export GOARCH=mips64le; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=darwin; export GOARCH=ppc64le; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=darwin; export GOARCH=s390x; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=freebsd; export GOARCH=arm; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=freebsd; export GOARCH=arm64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=freebsd; export GOARCH=amd64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=freebsd; export GOARCH=386; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=freebsd; export GOARCH=mips; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=freebsd; export GOARCH=mipsle; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=freebsd; export GOARCH=mips64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=freebsd; export GOARCH=mips64le; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=freebsd; export GOARCH=ppc64le; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=freebsd; export GOARCH=s390x; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=openbsd; export GOARCH=arm; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=openbsd; export GOARCH=arm64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=openbsd; export GOARCH=amd64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=openbsd; export GOARCH=386; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=openbsd; export GOARCH=mips; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=openbsd; export GOARCH=mipsle; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=openbsd; export GOARCH=mips64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=openbsd; export GOARCH=mips64le; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=openbsd; export GOARCH=ppc64le; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=openbsd; export GOARCH=s390x; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=netbsd; export GOARCH=arm; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=netbsd; export GOARCH=arm64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=netbsd; export GOARCH=amd64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=netbsd; export GOARCH=386; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=netbsd; export GOARCH=mips; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=netbsd; export GOARCH=mipsle; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=netbsd; export GOARCH=mips64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=netbsd; export GOARCH=mips64le; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=netbsd; export GOARCH=ppc64le; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=netbsd; export GOARCH=s390x; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=dragonfly; export GOARCH=arm; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=dragonfly; export GOARCH=arm64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=dragonfly; export GOARCH=amd64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=dragonfly; export GOARCH=386; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=dragonfly; export GOARCH=mips; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=dragonfly; export GOARCH=mipsle; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=dragonfly; export GOARCH=mips64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=dragonfly; export GOARCH=mips64le; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=dragonfly; export GOARCH=ppc64le; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=dragonfly; export GOARCH=s390x; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=solaris; export GOARCH=arm; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=solaris; export GOARCH=arm64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=solaris; export GOARCH=amd64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=solaris; export GOARCH=386; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=solaris; export GOARCH=mips; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=solaris; export GOARCH=mipsle; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=solaris; export GOARCH=mips64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=solaris; export GOARCH=mips64le; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=solaris; export GOARCH=ppc64le; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=solaris; export GOARCH=s390x; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=plan9; export GOARCH=arm; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=plan9; export GOARCH=arm64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=plan9; export GOARCH=amd64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=plan9; export GOARCH=386; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=plan9; export GOARCH=mips; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=plan9; export GOARCH=mipsle; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=plan9; export GOARCH=mips64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=plan9; export GOARCH=mips64le; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=plan9; export GOARCH=ppc64le; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=plan9; export GOARCH=s390x; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=windows; export GOARCH=arm; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=windows; export GOARCH=arm64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=windows; export GOARCH=amd64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=windows; export GOARCH=386; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=windows; export GOARCH=mips; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=windows; export GOARCH=mipsle; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=windows; export GOARCH=mips64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=windows; export GOARCH=mips64le; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=windows; export GOARCH=ppc64le; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=windows; export GOARCH=s390x; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=android; export GOARCH=arm; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=android; export GOARCH=arm64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=android; export GOARCH=amd64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=android; export GOARCH=386; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=android; export GOARCH=mips; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=android; export GOARCH=mipsle; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=android; export GOARCH=mips64; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=android; export GOARCH=mips64le; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=android; export GOARCH=ppc64le; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; export GOOS=android; export GOARCH=s390x; echo "$(go build -o crosstest/${GOOS}_${GOARCH} && echo '[OK]' || echo '[KO]') $GOOS/$GOARCH"; goselect-0.1.2/zselect_windows.go000066400000000000000000000017771401347227400171110ustar00rootroot00000000000000// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT package goselect import "unsafe" import "syscall" var _ unsafe.Pointer var ( modws2_32 = syscall.NewLazyDLL("ws2_32.dll") procselect = modws2_32.NewProc("select") proc__WSAFDIsSet = modws2_32.NewProc("__WSAFDIsSet") ) func _select(nfds int, readfds *FDSet, writefds *FDSet, exceptfds *FDSet, timeout *syscall.Timeval) (total int, err error) { r0, _, e1 := syscall.Syscall6(procselect.Addr(), 5, uintptr(nfds), uintptr(unsafe.Pointer(readfds)), uintptr(unsafe.Pointer(writefds)), uintptr(unsafe.Pointer(exceptfds)), uintptr(unsafe.Pointer(timeout)), 0) total = int(r0) if total == 0 { if e1 != 0 { err = error(e1) } } return } func __WSAFDIsSet(handle syscall.Handle, fdset *FDSet) (isset int, err error) { r0, _, e1 := syscall.Syscall(proc__WSAFDIsSet.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(fdset)), 0) isset = int(r0) if isset == 0 { if e1 != 0 { err = error(e1) } else { err = syscall.EINVAL } } return }