linux: fix last argument of pselect6

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
This commit is contained in:
Mauri de Souza Meneguzzo
2023-07-16 13:58:05 -03:00
parent 3fead03e7d
commit 3c1041b1cf
5 changed files with 75 additions and 2 deletions

View File

@@ -968,6 +968,10 @@ const (
)
type Sigset_t C.sigset_t
type pselect6Sigset_t struct {
ss *Sigset_t
ssLen uintptr // Size (in bytes) of object pointed to by ss.
}
const _C__NSIG = C._NSIG

View File

@@ -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 *pselect6Sigset_t) (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)
@@ -2438,6 +2438,36 @@ func Getresgid() (rgid, egid, sgid int) {
return int(r), int(e), int(s)
}
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 *pselect6Sigset_t
if sigmask != nil {
wordBits := 32 << (^uintptr(0) >> 63)
sigsetWords := (_C__NSIG - 1 + wordBits - 1) / (wordBits)
// 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⌉.
sigsetBytes := sigsetWords * (wordBits / 8)
kernelMask = &pselect6Sigset_t{
ss: sigmask,
ssLen: uintptr(sigsetBytes),
}
}
return pselect6(nfd, r, w, e, mutableTimeout, kernelMask)
}
/*
* Unimplemented
*/

View File

@@ -444,6 +444,40 @@ 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
}
for {
var sigmask unix.Sigset_t
sigmask.Val[0] |= 1 << (uint(unix.SIGUSR1) - 1)
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()

View File

@@ -1356,7 +1356,7 @@ func Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) {
func pselect6(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *pselect6Sigset_t) (n int, err error) {
r0, _, e1 := Syscall6(SYS_PSELECT6, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)))
n = int(r0)
if e1 != 0 {

View File

@@ -866,6 +866,11 @@ const (
POLLNVAL = 0x20
)
type pselect6Sigset_t struct {
ss *Sigset_t
ssLen uintptr
}
type SignalfdSiginfo struct {
Signo uint32
Errno int32