diff --git a/unix/affinity_linux.go b/unix/affinity_linux.go index 3c7a6d6e2..3ea470387 100644 --- a/unix/affinity_linux.go +++ b/unix/affinity_linux.go @@ -41,6 +41,15 @@ func (s *CPUSet) Zero() { clear(s[:]) } +// Fill adds all possible CPU bits to the set s. On Linux, [SchedSetaffinity] +// will silently ignore any invalid CPU bits in [CPUSet] so this is an +// efficient way of resetting the CPU affinity of a process. +func (s *CPUSet) Fill() { + for i := range s { + s[i] = ^cpuMask(0) + } +} + func cpuBitsIndex(cpu int) int { return cpu / _NCPUBITS } diff --git a/unix/dirent_test.go b/unix/dirent_test.go index f209fa1fc..ce8048884 100644 --- a/unix/dirent_test.go +++ b/unix/dirent_test.go @@ -12,7 +12,7 @@ import ( "os" "path/filepath" "runtime" - "sort" + "slices" "strconv" "strings" "testing" @@ -72,7 +72,7 @@ func TestDirent(t *testing.T) { } } - sort.Strings(names) + slices.Sort(names) t.Logf("names: %q", names) if len(names) != 10 { @@ -145,9 +145,9 @@ func TestDirentRepeat(t *testing.T) { } // Check results - sort.Strings(files) - sort.Strings(files2) - if strings.Join(files, "|") != strings.Join(files2, "|") { + slices.Sort(files) + slices.Sort(files2) + if !slices.Equal(files, files2) { t.Errorf("bad file list: want\n%q\ngot\n%q", files, files2) } } diff --git a/unix/fdset.go b/unix/fdset.go index 9e83d18cd..62ed12645 100644 --- a/unix/fdset.go +++ b/unix/fdset.go @@ -23,7 +23,5 @@ func (fds *FdSet) IsSet(fd int) bool { // Zero clears the set fds. func (fds *FdSet) Zero() { - for i := range fds.Bits { - fds.Bits[i] = 0 - } + clear(fds.Bits[:]) } diff --git a/unix/getdirentries_test.go b/unix/getdirentries_test.go index ca94a4cf8..c8a184b54 100644 --- a/unix/getdirentries_test.go +++ b/unix/getdirentries_test.go @@ -10,8 +10,7 @@ import ( "fmt" "os" "path/filepath" - "sort" - "strings" + "slices" "testing" "golang.org/x/sys/unix" @@ -71,9 +70,9 @@ func testGetdirentries(t *testing.T, count int) { } } - sort.Strings(names) - sort.Strings(names2) - if strings.Join(names, ":") != strings.Join(names2, ":") { + slices.Sort(names) + slices.Sort(names2) + if !slices.Equal(names, names2) { t.Errorf("names don't match\n names: %q\nnames2: %q", names, names2) } } diff --git a/unix/getvfsstat_test.go b/unix/getvfsstat_test.go new file mode 100644 index 000000000..30c963a10 --- /dev/null +++ b/unix/getvfsstat_test.go @@ -0,0 +1,47 @@ +// Copyright 2023 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. + +//go:build netbsd + +package unix_test + +import ( + "os/exec" + "testing" + + "golang.org/x/sys/unix" +) + +func TestGetvfsstat(t *testing.T) { + n, err := unix.Getvfsstat(nil, unix.MNT_NOWAIT) + if err != nil { + t.Fatal(err) + } + + data := make([]unix.Statvfs_t, n) + n2, err := unix.Getvfsstat(data, unix.MNT_NOWAIT) + if err != nil { + t.Fatal(err) + } + if n != n2 { + t.Errorf("Getvfsstat(nil) = %d, but subsequent Getvfsstat(slice) = %d", n, n2) + } + for i, stat := range data { + if stat == (unix.Statvfs_t{}) { + t.Errorf("index %v is an empty Statvfs_t struct", i) + } + t.Logf("%s on %s", unix.ByteSliceToString(stat.Mntfromname[:]), unix.ByteSliceToString(stat.Mntonname[:])) + } + if t.Failed() { + for i, stat := range data[:n2] { + t.Logf("data[%v] = %+v", i, stat) + } + mount, err := exec.Command("mount").CombinedOutput() + if err != nil { + t.Logf("mount: %v\n%s", err, mount) + } else { + t.Logf("mount: %s", mount) + } + } +} diff --git a/unix/ifreq_linux.go b/unix/ifreq_linux.go index 848840ae4..309f5a2b0 100644 --- a/unix/ifreq_linux.go +++ b/unix/ifreq_linux.go @@ -111,9 +111,7 @@ func (ifr *Ifreq) SetUint32(v uint32) { // clear zeroes the ifreq's union field to prevent trailing garbage data from // being sent to the kernel if an ifreq is reused. func (ifr *Ifreq) clear() { - for i := range ifr.raw.Ifru { - ifr.raw.Ifru[i] = 0 - } + clear(ifr.raw.Ifru[:]) } // TODO(mdlayher): export as IfreqData? For now we can provide helpers such as diff --git a/unix/mkall.sh b/unix/mkall.sh index e6f31d374..d0ed61191 100755 --- a/unix/mkall.sh +++ b/unix/mkall.sh @@ -49,6 +49,7 @@ esac if [[ "$GOOS" = "linux" ]]; then # Use the Docker-based build system # Files generated through docker (use $cmd so you can Ctl-C the build or run) + set -e $cmd docker build --tag generate:$GOOS $GOOS $cmd docker run --interactive --tty --volume $(cd -- "$(dirname -- "$0")/.." && pwd):/build generate:$GOOS exit diff --git a/unix/syscall_linux.go b/unix/syscall_linux.go index 4958a6570..9439af961 100644 --- a/unix/syscall_linux.go +++ b/unix/syscall_linux.go @@ -801,9 +801,7 @@ func (sa *SockaddrPPPoE) sockaddr() (unsafe.Pointer, _Socklen, error) { // one. The kernel expects SID to be in network byte order. binary.BigEndian.PutUint16(sa.raw[6:8], sa.SID) copy(sa.raw[8:14], sa.Remote) - for i := 14; i < 14+IFNAMSIZ; i++ { - sa.raw[i] = 0 - } + clear(sa.raw[14 : 14+IFNAMSIZ]) copy(sa.raw[14:], sa.Dev) return unsafe.Pointer(&sa.raw), SizeofSockaddrPPPoX, nil } diff --git a/unix/syscall_netbsd.go b/unix/syscall_netbsd.go index 88162099a..34a467697 100644 --- a/unix/syscall_netbsd.go +++ b/unix/syscall_netbsd.go @@ -248,6 +248,23 @@ func Statvfs(path string, buf *Statvfs_t) (err error) { return Statvfs1(path, buf, ST_WAIT) } +func Getvfsstat(buf []Statvfs_t, flags int) (n int, err error) { + var ( + _p0 unsafe.Pointer + bufsize uintptr + ) + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + bufsize = unsafe.Sizeof(Statvfs_t{}) * uintptr(len(buf)) + } + r0, _, e1 := Syscall(SYS_GETVFSSTAT, uintptr(_p0), bufsize, uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = e1 + } + return +} + /* * Exposed directly */ diff --git a/windows/syscall_windows.go b/windows/syscall_windows.go index 640f6b153..bd5133730 100644 --- a/windows/syscall_windows.go +++ b/windows/syscall_windows.go @@ -321,6 +321,8 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys SetConsoleOutputCP(cp uint32) (err error) = kernel32.SetConsoleOutputCP //sys WriteConsole(console Handle, buf *uint16, towrite uint32, written *uint32, reserved *byte) (err error) = kernel32.WriteConsoleW //sys ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) (err error) = kernel32.ReadConsoleW +//sys GetNumberOfConsoleInputEvents(console Handle, numevents *uint32) (err error) = kernel32.GetNumberOfConsoleInputEvents +//sys FlushConsoleInputBuffer(console Handle) (err error) = kernel32.FlushConsoleInputBuffer //sys resizePseudoConsole(pconsole Handle, size uint32) (hr error) = kernel32.ResizePseudoConsole //sys CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, err error) [failretval==InvalidHandle] = kernel32.CreateToolhelp32Snapshot //sys Module32First(snapshot Handle, moduleEntry *ModuleEntry32) (err error) = kernel32.Module32FirstW diff --git a/windows/types_windows.go b/windows/types_windows.go index 993a2297d..358be3c7f 100644 --- a/windows/types_windows.go +++ b/windows/types_windows.go @@ -65,6 +65,22 @@ var signals = [...]string{ 15: "terminated", } +// File flags for [os.OpenFile]. The O_ prefix is used to indicate +// that these flags are specific to the OpenFile function. +const ( + O_FILE_FLAG_OPEN_NO_RECALL = FILE_FLAG_OPEN_NO_RECALL + O_FILE_FLAG_OPEN_REPARSE_POINT = FILE_FLAG_OPEN_REPARSE_POINT + O_FILE_FLAG_SESSION_AWARE = FILE_FLAG_SESSION_AWARE + O_FILE_FLAG_POSIX_SEMANTICS = FILE_FLAG_POSIX_SEMANTICS + O_FILE_FLAG_BACKUP_SEMANTICS = FILE_FLAG_BACKUP_SEMANTICS + O_FILE_FLAG_DELETE_ON_CLOSE = FILE_FLAG_DELETE_ON_CLOSE + O_FILE_FLAG_SEQUENTIAL_SCAN = FILE_FLAG_SEQUENTIAL_SCAN + O_FILE_FLAG_RANDOM_ACCESS = FILE_FLAG_RANDOM_ACCESS + O_FILE_FLAG_NO_BUFFERING = FILE_FLAG_NO_BUFFERING + O_FILE_FLAG_OVERLAPPED = FILE_FLAG_OVERLAPPED + O_FILE_FLAG_WRITE_THROUGH = FILE_FLAG_WRITE_THROUGH +) + const ( FILE_READ_DATA = 0x00000001 FILE_READ_ATTRIBUTES = 0x00000080 diff --git a/windows/zsyscall_windows.go b/windows/zsyscall_windows.go index 641a5f4b7..426151a01 100644 --- a/windows/zsyscall_windows.go +++ b/windows/zsyscall_windows.go @@ -238,6 +238,7 @@ var ( procFindResourceW = modkernel32.NewProc("FindResourceW") procFindVolumeClose = modkernel32.NewProc("FindVolumeClose") procFindVolumeMountPointClose = modkernel32.NewProc("FindVolumeMountPointClose") + procFlushConsoleInputBuffer = modkernel32.NewProc("FlushConsoleInputBuffer") procFlushFileBuffers = modkernel32.NewProc("FlushFileBuffers") procFlushViewOfFile = modkernel32.NewProc("FlushViewOfFile") procFormatMessageW = modkernel32.NewProc("FormatMessageW") @@ -284,6 +285,7 @@ var ( procGetNamedPipeHandleStateW = modkernel32.NewProc("GetNamedPipeHandleStateW") procGetNamedPipeInfo = modkernel32.NewProc("GetNamedPipeInfo") procGetNamedPipeServerProcessId = modkernel32.NewProc("GetNamedPipeServerProcessId") + procGetNumberOfConsoleInputEvents = modkernel32.NewProc("GetNumberOfConsoleInputEvents") procGetOverlappedResult = modkernel32.NewProc("GetOverlappedResult") procGetPriorityClass = modkernel32.NewProc("GetPriorityClass") procGetProcAddress = modkernel32.NewProc("GetProcAddress") @@ -2111,6 +2113,14 @@ func FindVolumeMountPointClose(findVolumeMountPoint Handle) (err error) { return } +func FlushConsoleInputBuffer(console Handle) (err error) { + r1, _, e1 := syscall.SyscallN(procFlushConsoleInputBuffer.Addr(), uintptr(console)) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func FlushFileBuffers(handle Handle) (err error) { r1, _, e1 := syscall.SyscallN(procFlushFileBuffers.Addr(), uintptr(handle)) if r1 == 0 { @@ -2481,6 +2491,14 @@ func GetNamedPipeServerProcessId(pipe Handle, serverProcessID *uint32) (err erro return } +func GetNumberOfConsoleInputEvents(console Handle, numevents *uint32) (err error) { + r1, _, e1 := syscall.SyscallN(procGetNumberOfConsoleInputEvents.Addr(), uintptr(console), uintptr(unsafe.Pointer(numevents))) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func GetOverlappedResult(handle Handle, overlapped *Overlapped, done *uint32, wait bool) (err error) { var _p0 uint32 if wait {