Don't sched_setaffinity in ptrace platform.

PiperOrigin-RevId: 330777900
This commit is contained in:
Jamie Liu
2020-09-09 12:48:57 -07:00
committed by gVisor bot
parent fb281eea75
commit f3172c3a11
4 changed files with 4 additions and 72 deletions
-1
View File
@@ -30,7 +30,6 @@ go_library(
"//pkg/safecopy",
"//pkg/seccomp",
"//pkg/sentry/arch",
"//pkg/sentry/hostcpu",
"//pkg/sentry/memmap",
"//pkg/sentry/platform",
"//pkg/sentry/platform/interrupt",
+4 -5
View File
@@ -24,10 +24,9 @@ import (
// SyscallFilters returns syscalls made exclusively by the ptrace platform.
func (*PTrace) SyscallFilters() seccomp.SyscallRules {
return seccomp.SyscallRules{
unix.SYS_GETCPU: {},
unix.SYS_SCHED_SETAFFINITY: {},
syscall.SYS_PTRACE: {},
syscall.SYS_TGKILL: {},
syscall.SYS_WAIT4: {},
unix.SYS_GETCPU: {},
syscall.SYS_PTRACE: {},
syscall.SYS_TGKILL: {},
syscall.SYS_WAIT4: {},
}
}
-5
View File
@@ -518,11 +518,6 @@ func (s *subprocess) switchToApp(c *context, ac arch.Context) bool {
}
defer c.interrupt.Disable()
// Ensure that the CPU set is bound appropriately; this makes the
// emulation below several times faster, presumably by avoiding
// interprocessor wakeups and by simplifying the schedule.
t.bind()
// Set registers.
if err := t.setRegs(regs); err != nil {
panic(fmt.Sprintf("ptrace set regs (%+v) failed: %v", regs, err))
@@ -18,29 +18,12 @@
package ptrace
import (
"sync/atomic"
"syscall"
"unsafe"
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/sentry/hostcpu"
"gvisor.dev/gvisor/pkg/sync"
)
// maskPool contains reusable CPU masks for setting affinity. Unfortunately,
// runtime.NumCPU doesn't actually record the number of CPUs on the system, it
// just records the number of CPUs available in the scheduler affinity set at
// startup. This may a) change over time and b) gives a number far lower than
// the maximum indexable CPU. To prevent lots of allocation in the hot path, we
// use a pool to store large masks that we can reuse during bind.
var maskPool = sync.Pool{
New: func() interface{} {
const maxCPUs = 1024 // Not a hard limit; see below.
return make([]uintptr, maxCPUs/64)
},
}
// unmaskAllSignals unmasks all signals on the current thread.
//
//go:nosplit
@@ -49,47 +32,3 @@ func unmaskAllSignals() syscall.Errno {
_, _, errno := syscall.RawSyscall6(syscall.SYS_RT_SIGPROCMASK, linux.SIG_SETMASK, uintptr(unsafe.Pointer(&set)), 0, linux.SignalSetSize, 0, 0)
return errno
}
// setCPU sets the CPU affinity.
func (t *thread) setCPU(cpu uint32) error {
mask := maskPool.Get().([]uintptr)
n := int(cpu / 64)
v := uintptr(1 << uintptr(cpu%64))
if n >= len(mask) {
// See maskPool note above. We've actually exceeded the number
// of available cores. Grow the mask and return it.
mask = make([]uintptr, n+1)
}
mask[n] |= v
if _, _, errno := syscall.RawSyscall(
unix.SYS_SCHED_SETAFFINITY,
uintptr(t.tid),
uintptr(len(mask)*8),
uintptr(unsafe.Pointer(&mask[0]))); errno != 0 {
return errno
}
mask[n] &^= v
maskPool.Put(mask)
return nil
}
// bind attempts to ensure that the thread is on the same CPU as the current
// thread. This provides no guarantees as it is fundamentally a racy operation:
// CPU sets may change and we may be rescheduled in the middle of this
// operation. As a result, no failures are reported.
//
// Precondition: the current runtime thread should be locked.
func (t *thread) bind() {
currentCPU := hostcpu.GetCPU()
if oldCPU := atomic.SwapUint32(&t.cpu, currentCPU); oldCPU != currentCPU {
// Set the affinity on the thread and save the CPU for next
// round; we don't expect CPUs to bounce around too frequently.
//
// (It's worth noting that we could move CPUs between this point
// and when the tracee finishes executing. But that would be
// roughly the status quo anyways -- we're just maximizing our
// chances of colocation, not guaranteeing it.)
t.setCPU(currentCPU)
}
}