diff --git a/unix/fdset.go b/unix/fdset.go new file mode 100644 index 00000000..b27be0a0 --- /dev/null +++ b/unix/fdset.go @@ -0,0 +1,29 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris + +package unix + +// Set adds fd to the set fds. +func (fds *FdSet) Set(fd int) { + fds.Bits[fd/NFDBITS] |= (1 << (uintptr(fd) % NFDBITS)) +} + +// Clear removes fd from the set fds. +func (fds *FdSet) Clear(fd int) { + fds.Bits[fd/NFDBITS] &^= (1 << (uintptr(fd) % NFDBITS)) +} + +// IsSet returns whether fd is in the set fds. +func (fds *FdSet) IsSet(fd int) bool { + return fds.Bits[fd/NFDBITS]&(1<<(uintptr(fd)%NFDBITS)) != 0 +} + +// Zero clears the set fds. +func (fds *FdSet) Zero() { + for i := range fds.Bits { + fds.Bits[i] = 0 + } +} diff --git a/unix/fdset_test.go b/unix/fdset_test.go new file mode 100644 index 00000000..e092785c --- /dev/null +++ b/unix/fdset_test.go @@ -0,0 +1,53 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris + +package unix_test + +import ( + "testing" + + "golang.org/x/sys/unix" +) + +func TestFdSet(t *testing.T) { + var fdSet unix.FdSet + fdSet.Zero() + for fd := 0; fd < unix.FD_SETSIZE; fd++ { + if fdSet.IsSet(fd) { + t.Fatalf("Zero did not clear fd %d", fd) + } + fdSet.Set(fd) + } + + for fd := 0; fd < unix.FD_SETSIZE; fd++ { + if !fdSet.IsSet(fd) { + t.Fatalf("IsSet(%d): expected true, got false", fd) + } + } + + fdSet.Zero() + for fd := 0; fd < unix.FD_SETSIZE; fd++ { + if fdSet.IsSet(fd) { + t.Fatalf("Zero did not clear fd %d", fd) + } + } + + for fd := 1; fd < unix.FD_SETSIZE; fd += 2 { + fdSet.Set(fd) + } + + for fd := 0; fd < unix.FD_SETSIZE; fd++ { + if fd&0x1 == 0x1 { + if !fdSet.IsSet(fd) { + t.Fatalf("IsSet(%d): expected true, got false", fd) + } + } else { + if fdSet.IsSet(fd) { + t.Fatalf("IsSet(%d): expected false, got true", fd) + } + } + } +} diff --git a/unix/syscall_bsd_test.go b/unix/syscall_bsd_test.go index 4d5a4103..bee92955 100644 --- a/unix/syscall_bsd_test.go +++ b/unix/syscall_bsd_test.go @@ -87,11 +87,10 @@ func TestSelect(t *testing.T) { } rFdSet := &unix.FdSet{} - fd := rr.Fd() - // FD_SET(fd, rFdSet) - rFdSet.Bits[fd/unix.NFDBITS] |= (1 << (fd % unix.NFDBITS)) + fd := int(rr.Fd()) + rFdSet.Set(fd) - n, err = unix.Select(int(fd+1), rFdSet, nil, nil, nil) + n, err = unix.Select(fd+1, rFdSet, nil, nil, nil) if err != nil { t.Fatalf("Select: %v", err) } diff --git a/unix/syscall_linux_test.go b/unix/syscall_linux_test.go index 27531914..791ba85b 100644 --- a/unix/syscall_linux_test.go +++ b/unix/syscall_linux_test.go @@ -274,11 +274,10 @@ func TestSelect(t *testing.T) { } rFdSet := &unix.FdSet{} - fd := rr.Fd() - // FD_SET(fd, rFdSet) - rFdSet.Bits[fd/unix.NFDBITS] |= (1 << (fd % unix.NFDBITS)) + fd := int(rr.Fd()) + rFdSet.Set(fd) - n, err = unix.Select(int(fd+1), rFdSet, nil, nil, nil) + n, err = unix.Select(fd+1, rFdSet, nil, nil, nil) if err != nil { t.Fatalf("Select: %v", err) } diff --git a/unix/syscall_solaris_test.go b/unix/syscall_solaris_test.go index 21a57133..9598c22e 100644 --- a/unix/syscall_solaris_test.go +++ b/unix/syscall_solaris_test.go @@ -52,11 +52,10 @@ func TestSelect(t *testing.T) { } rFdSet := &unix.FdSet{} - fd := rr.Fd() - // FD_SET(fd, rFdSet) - rFdSet.Bits[fd/unix.NFDBITS] |= (1 << (fd % unix.NFDBITS)) + fd := int(rr.Fd()) + rFdSet.Set(fd) - n, err = unix.Select(int(fd+1), rFdSet, nil, nil, nil) + n, err = unix.Select(fd+1, rFdSet, nil, nil, nil) if err != nil { t.Fatalf("Select: %v", err) }