Skip to content

Commit

Permalink
unix: fix last argument of pselect6 on linux
Browse files Browse the repository at this point in the history
On Linux, the last argument of pselect6 system call is **not** a
sigseg_t * pointer, but instead it is a structure of the form:

    struct {
        const sigset_t *ss;     /* Pointer to signal set */
        size_t          ss_len; /* Size (in bytes) of object pointed
    };

See man 2 pselect6.

Fixes #61251

Change-Id: Id0aa122a77796713bc6d624dc395d396fbc0c5e2
GitHub-Last-Rev: cb3c6d7
GitHub-Pull-Request: #167
Reviewed-on: https://go-review.googlesource.com/c/sys/+/510195
Reviewed-by: Bryan Mills <bcmills@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
  • Loading branch information
mauri870 authored and gopherbot committed Jul 19, 2023
1 parent 706fa98 commit 25d0004
Show file tree
Hide file tree
Showing 10 changed files with 67 additions and 7 deletions.
4 changes: 4 additions & 0 deletions unix/linux/types.go
Expand Up @@ -968,6 +968,10 @@ const (
)

type Sigset_t C.sigset_t
type sigset_argpack struct {
ss *Sigset_t
ssLen uintptr // Size (in bytes) of object pointed to by ss.
}

const _C__NSIG = C._NSIG

Expand Down
35 changes: 34 additions & 1 deletion unix/syscall_linux.go
Expand Up @@ -1885,7 +1885,7 @@ func Getpgrp() (pid int) {
//sys PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error)
//sys PivotRoot(newroot string, putold string) (err error) = SYS_PIVOT_ROOT
//sys Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (err error)
//sys Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) = SYS_PSELECT6
//sys pselect6(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *sigset_argpack) (n int, err error)
//sys read(fd int, p []byte) (n int, err error)
//sys Removexattr(path string, attr string) (err error)
//sys Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) (err error)
Expand Down Expand Up @@ -2438,6 +2438,39 @@ func Getresgid() (rgid, egid, sgid int) {
return int(r), int(e), int(s)
}

// Pselect is a wrapper around the Linux pselect6 system call.
// This version does not modify the timeout argument.
func Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) {
// Per https://man7.org/linux/man-pages/man2/select.2.html#NOTES,
// The Linux pselect6() system call modifies its timeout argument.
// [Not modifying the argument] is the behavior required by POSIX.1-2001.
var mutableTimeout *Timespec
if timeout != nil {
mutableTimeout = new(Timespec)
*mutableTimeout = *timeout
}

// The final argument of the pselect6() system call is not a
// sigset_t * pointer, but is instead a structure
var kernelMask *sigset_argpack
if sigmask != nil {
wordBits := 32 << (^uintptr(0) >> 63) // see math.intSize

// A sigset stores one bit per signal,
// offset by 1 (because signal 0 does not exist).
// So the number of words needed is ⌈__C_NSIG - 1 / wordBits⌉.
sigsetWords := (_C__NSIG - 1 + wordBits - 1) / (wordBits)

sigsetBytes := uintptr(sigsetWords * (wordBits / 8))
kernelMask = &sigset_argpack{
ss: sigmask,
ssLen: sigsetBytes,
}
}

return pselect6(nfd, r, w, e, mutableTimeout, kernelMask)
}

/*
* Unimplemented
*/
Expand Down
2 changes: 1 addition & 1 deletion unix/syscall_linux_amd64.go
Expand Up @@ -40,7 +40,7 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err
if timeout != nil {
ts = &Timespec{Sec: timeout.Sec, Nsec: timeout.Usec * 1000}
}
return Pselect(nfd, r, w, e, ts, nil)
return pselect6(nfd, r, w, e, ts, nil)
}

//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
Expand Down
2 changes: 1 addition & 1 deletion unix/syscall_linux_arm64.go
Expand Up @@ -33,7 +33,7 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err
if timeout != nil {
ts = &Timespec{Sec: timeout.Sec, Nsec: timeout.Usec * 1000}
}
return Pselect(nfd, r, w, e, ts, nil)
return pselect6(nfd, r, w, e, ts, nil)
}

//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
Expand Down
2 changes: 1 addition & 1 deletion unix/syscall_linux_loong64.go
Expand Up @@ -28,7 +28,7 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err
if timeout != nil {
ts = &Timespec{Sec: timeout.Sec, Nsec: timeout.Usec * 1000}
}
return Pselect(nfd, r, w, e, ts, nil)
return pselect6(nfd, r, w, e, ts, nil)
}

//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
Expand Down
2 changes: 1 addition & 1 deletion unix/syscall_linux_mips64x.go
Expand Up @@ -31,7 +31,7 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err
if timeout != nil {
ts = &Timespec{Sec: timeout.Sec, Nsec: timeout.Usec * 1000}
}
return Pselect(nfd, r, w, e, ts, nil)
return pselect6(nfd, r, w, e, ts, nil)
}

//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
Expand Down
2 changes: 1 addition & 1 deletion unix/syscall_linux_riscv64.go
Expand Up @@ -32,7 +32,7 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err
if timeout != nil {
ts = &Timespec{Sec: timeout.Sec, Nsec: timeout.Usec * 1000}
}
return Pselect(nfd, r, w, e, ts, nil)
return pselect6(nfd, r, w, e, ts, nil)
}

//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
Expand Down
18 changes: 18 additions & 0 deletions unix/syscall_linux_test.go
Expand Up @@ -444,6 +444,24 @@ func TestPselect(t *testing.T) {
}
}

func TestPselectWithSigmask(t *testing.T) {
var sigmask unix.Sigset_t
sigmask.Val[0] |= 1 << (uint(unix.SIGUSR1) - 1)
for {
n, err := unix.Pselect(0, nil, nil, nil, &unix.Timespec{Sec: 0, Nsec: 0}, &sigmask)
if err == unix.EINTR {
t.Logf("Pselect interrupted")
continue
} else if err != nil {
t.Fatalf("Pselect: %v", err)
}
if n != 0 {
t.Fatalf("Pselect: got %v ready file descriptors, expected 0", n)
}
break
}
}

func TestSchedSetaffinity(t *testing.T) {
var newMask unix.CPUSet
newMask.Zero()
Expand Down
2 changes: 1 addition & 1 deletion unix/zsyscall_linux.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions unix/ztypes_linux.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 25d0004

Please sign in to comment.