mirror of
https://github.com/rwinkhart/sys.git
synced 2026-09-02 07:07:33 -04:00
unix: add SchedGetaffinity and SchedSetaffinity on Linux
SchedGetaffinity and SchedSetaffinity are used to get and set a thread's CPU affinity mask. See http://man7.org/linux/man-pages/man2/sched_setaffinity.2.html for details. Also add a manual implementation of CpuSet_t and the corresponding accessor functions (mimicking the CPU_* macros from sched.h). Fixes golang/go#11243 Change-Id: Ia5abc0053cd06810b3b09ab65c27434f5323c1ad Reviewed-on: https://go-review.googlesource.com/85915 Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
committed by
Tobias Klauser
parent
a3f2cbd54c
commit
12d9d5b281
@@ -0,0 +1,86 @@
|
|||||||
|
// Copyright 2018 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.
|
||||||
|
|
||||||
|
// CPU affinity functions
|
||||||
|
|
||||||
|
package unix
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/bits"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const cpuSetSize = _CPU_SETSIZE / _NCPUBITS
|
||||||
|
|
||||||
|
// CPUSet represents a CPU affinity mask.
|
||||||
|
type CPUSet [cpuSetSize]cpuMask
|
||||||
|
|
||||||
|
func schedAffinity(trap uintptr, pid int, set *CPUSet) error {
|
||||||
|
_, _, e := RawSyscall(trap, uintptr(pid), uintptr(unsafe.Sizeof(set)), uintptr(unsafe.Pointer(set)))
|
||||||
|
if e != 0 {
|
||||||
|
return errnoErr(e)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SchedGetaffinity gets the CPU affinity mask of the thread specified by pid.
|
||||||
|
// If pid is 0 the calling thread is used.
|
||||||
|
func SchedGetaffinity(pid int, set *CPUSet) error {
|
||||||
|
return schedAffinity(SYS_SCHED_GETAFFINITY, pid, set)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SchedSetaffinity sets the CPU affinity mask of the thread specified by pid.
|
||||||
|
// If pid is 0 the calling thread is used.
|
||||||
|
func SchedSetaffinity(pid int, set *CPUSet) error {
|
||||||
|
return schedAffinity(SYS_SCHED_SETAFFINITY, pid, set)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zero clears the set s, so that it contains no CPUs.
|
||||||
|
func (s *CPUSet) Zero() {
|
||||||
|
for i := range s {
|
||||||
|
s[i] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func cpuBitsIndex(cpu int) int {
|
||||||
|
return cpu / _NCPUBITS
|
||||||
|
}
|
||||||
|
|
||||||
|
func cpuBitsMask(cpu int) cpuMask {
|
||||||
|
return cpuMask(1 << (uint(cpu) % _NCPUBITS))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set adds cpu to the set s.
|
||||||
|
func (s *CPUSet) Set(cpu int) {
|
||||||
|
i := cpuBitsIndex(cpu)
|
||||||
|
if i < len(s) {
|
||||||
|
s[i] |= cpuBitsMask(cpu)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear removes cpu from the set s.
|
||||||
|
func (s *CPUSet) Clear(cpu int) {
|
||||||
|
i := cpuBitsIndex(cpu)
|
||||||
|
if i < len(s) {
|
||||||
|
s[i] &^= cpuBitsMask(cpu)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSet reports whether cpu is in the set s.
|
||||||
|
func (s *CPUSet) IsSet(cpu int) bool {
|
||||||
|
i := cpuBitsIndex(cpu)
|
||||||
|
if i < len(s) {
|
||||||
|
return s[i]&cpuBitsMask(cpu) != 0
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count returns the number of CPUs in the set s.
|
||||||
|
func (s *CPUSet) Count() int {
|
||||||
|
c := 0
|
||||||
|
for _, b := range s {
|
||||||
|
c += bits.OnesCount64(uint64(b))
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
@@ -24,6 +24,7 @@ package unix
|
|||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
#include <netpacket/packet.h>
|
#include <netpacket/packet.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
|
#include <sched.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/epoll.h>
|
#include <sys/epoll.h>
|
||||||
@@ -594,3 +595,12 @@ const (
|
|||||||
CTRL_ATTR_MCAST_GRP_NAME = C.CTRL_ATTR_MCAST_GRP_NAME
|
CTRL_ATTR_MCAST_GRP_NAME = C.CTRL_ATTR_MCAST_GRP_NAME
|
||||||
CTRL_ATTR_MCAST_GRP_ID = C.CTRL_ATTR_MCAST_GRP_ID
|
CTRL_ATTR_MCAST_GRP_ID = C.CTRL_ATTR_MCAST_GRP_ID
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// CPU affinity
|
||||||
|
|
||||||
|
type cpuMask C.__cpu_mask
|
||||||
|
|
||||||
|
const (
|
||||||
|
_CPU_SETSIZE = C.__CPU_SETSIZE
|
||||||
|
_NCPUBITS = C.__NCPUBITS
|
||||||
|
)
|
||||||
|
|||||||
@@ -1455,11 +1455,9 @@ func Vmsplice(fd int, iovs []Iovec, flags int) (int, error) {
|
|||||||
// RtSigtimedwait
|
// RtSigtimedwait
|
||||||
// SchedGetPriorityMax
|
// SchedGetPriorityMax
|
||||||
// SchedGetPriorityMin
|
// SchedGetPriorityMin
|
||||||
// SchedGetaffinity
|
|
||||||
// SchedGetparam
|
// SchedGetparam
|
||||||
// SchedGetscheduler
|
// SchedGetscheduler
|
||||||
// SchedRrGetInterval
|
// SchedRrGetInterval
|
||||||
// SchedSetaffinity
|
|
||||||
// SchedSetparam
|
// SchedSetparam
|
||||||
// SchedYield
|
// SchedYield
|
||||||
// Security
|
// Security
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ package unix_test
|
|||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -255,6 +256,58 @@ func TestFstatat(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSchedSetaffinity(t *testing.T) {
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
var oldMask unix.CPUSet
|
||||||
|
err := unix.SchedGetaffinity(0, &oldMask)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("SchedGetaffinity: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var newMask unix.CPUSet
|
||||||
|
newMask.Zero()
|
||||||
|
if newMask.Count() != 0 {
|
||||||
|
t.Errorf("CpuZero: didn't zero CPU set: %v", newMask)
|
||||||
|
}
|
||||||
|
cpu := 1
|
||||||
|
newMask.Set(cpu)
|
||||||
|
if newMask.Count() != 1 || !newMask.IsSet(cpu) {
|
||||||
|
t.Errorf("CpuSet: didn't set CPU %d in set: %v", cpu, newMask)
|
||||||
|
}
|
||||||
|
cpu = 5
|
||||||
|
newMask.Set(cpu)
|
||||||
|
if newMask.Count() != 2 || !newMask.IsSet(cpu) {
|
||||||
|
t.Errorf("CpuSet: didn't set CPU %d in set: %v", cpu, newMask)
|
||||||
|
}
|
||||||
|
newMask.Clear(cpu)
|
||||||
|
if newMask.Count() != 1 || newMask.IsSet(cpu) {
|
||||||
|
t.Errorf("CpuClr: didn't clear CPU %d in set: %v", cpu, newMask)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = unix.SchedSetaffinity(0, &newMask)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("SchedSetaffinity: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var gotMask unix.CPUSet
|
||||||
|
err = unix.SchedGetaffinity(0, &gotMask)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("SchedGetaffinity: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if gotMask != newMask {
|
||||||
|
t.Errorf("SchedSetaffinity: returned affinity mask does not match set affinity mask")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore old mask so it doesn't affect successive tests
|
||||||
|
err = unix.SchedSetaffinity(0, &oldMask)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("SchedSetaffinity: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// utilities taken from os/os_test.go
|
// utilities taken from os/os_test.go
|
||||||
|
|
||||||
func touch(t *testing.T, name string) {
|
func touch(t *testing.T, name string) {
|
||||||
|
|||||||
@@ -792,3 +792,10 @@ const (
|
|||||||
CTRL_ATTR_MCAST_GRP_NAME = 0x1
|
CTRL_ATTR_MCAST_GRP_NAME = 0x1
|
||||||
CTRL_ATTR_MCAST_GRP_ID = 0x2
|
CTRL_ATTR_MCAST_GRP_ID = 0x2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type cpuMask uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
_CPU_SETSIZE = 0x400
|
||||||
|
_NCPUBITS = 0x20
|
||||||
|
)
|
||||||
|
|||||||
@@ -810,3 +810,10 @@ const (
|
|||||||
CTRL_ATTR_MCAST_GRP_NAME = 0x1
|
CTRL_ATTR_MCAST_GRP_NAME = 0x1
|
||||||
CTRL_ATTR_MCAST_GRP_ID = 0x2
|
CTRL_ATTR_MCAST_GRP_ID = 0x2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type cpuMask uint64
|
||||||
|
|
||||||
|
const (
|
||||||
|
_CPU_SETSIZE = 0x400
|
||||||
|
_NCPUBITS = 0x40
|
||||||
|
)
|
||||||
|
|||||||
@@ -781,3 +781,10 @@ const (
|
|||||||
CTRL_ATTR_MCAST_GRP_NAME = 0x1
|
CTRL_ATTR_MCAST_GRP_NAME = 0x1
|
||||||
CTRL_ATTR_MCAST_GRP_ID = 0x2
|
CTRL_ATTR_MCAST_GRP_ID = 0x2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type cpuMask uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
_CPU_SETSIZE = 0x400
|
||||||
|
_NCPUBITS = 0x20
|
||||||
|
)
|
||||||
|
|||||||
@@ -789,3 +789,10 @@ const (
|
|||||||
CTRL_ATTR_MCAST_GRP_NAME = 0x1
|
CTRL_ATTR_MCAST_GRP_NAME = 0x1
|
||||||
CTRL_ATTR_MCAST_GRP_ID = 0x2
|
CTRL_ATTR_MCAST_GRP_ID = 0x2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type cpuMask uint64
|
||||||
|
|
||||||
|
const (
|
||||||
|
_CPU_SETSIZE = 0x400
|
||||||
|
_NCPUBITS = 0x40
|
||||||
|
)
|
||||||
|
|||||||
@@ -786,3 +786,10 @@ const (
|
|||||||
CTRL_ATTR_MCAST_GRP_NAME = 0x1
|
CTRL_ATTR_MCAST_GRP_NAME = 0x1
|
||||||
CTRL_ATTR_MCAST_GRP_ID = 0x2
|
CTRL_ATTR_MCAST_GRP_ID = 0x2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type cpuMask uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
_CPU_SETSIZE = 0x400
|
||||||
|
_NCPUBITS = 0x20
|
||||||
|
)
|
||||||
|
|||||||
@@ -791,3 +791,10 @@ const (
|
|||||||
CTRL_ATTR_MCAST_GRP_NAME = 0x1
|
CTRL_ATTR_MCAST_GRP_NAME = 0x1
|
||||||
CTRL_ATTR_MCAST_GRP_ID = 0x2
|
CTRL_ATTR_MCAST_GRP_ID = 0x2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type cpuMask uint64
|
||||||
|
|
||||||
|
const (
|
||||||
|
_CPU_SETSIZE = 0x400
|
||||||
|
_NCPUBITS = 0x40
|
||||||
|
)
|
||||||
|
|||||||
@@ -791,3 +791,10 @@ const (
|
|||||||
CTRL_ATTR_MCAST_GRP_NAME = 0x1
|
CTRL_ATTR_MCAST_GRP_NAME = 0x1
|
||||||
CTRL_ATTR_MCAST_GRP_ID = 0x2
|
CTRL_ATTR_MCAST_GRP_ID = 0x2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type cpuMask uint64
|
||||||
|
|
||||||
|
const (
|
||||||
|
_CPU_SETSIZE = 0x400
|
||||||
|
_NCPUBITS = 0x40
|
||||||
|
)
|
||||||
|
|||||||
@@ -786,3 +786,10 @@ const (
|
|||||||
CTRL_ATTR_MCAST_GRP_NAME = 0x1
|
CTRL_ATTR_MCAST_GRP_NAME = 0x1
|
||||||
CTRL_ATTR_MCAST_GRP_ID = 0x2
|
CTRL_ATTR_MCAST_GRP_ID = 0x2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type cpuMask uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
_CPU_SETSIZE = 0x400
|
||||||
|
_NCPUBITS = 0x20
|
||||||
|
)
|
||||||
|
|||||||
@@ -799,3 +799,10 @@ const (
|
|||||||
CTRL_ATTR_MCAST_GRP_NAME = 0x1
|
CTRL_ATTR_MCAST_GRP_NAME = 0x1
|
||||||
CTRL_ATTR_MCAST_GRP_ID = 0x2
|
CTRL_ATTR_MCAST_GRP_ID = 0x2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type cpuMask uint64
|
||||||
|
|
||||||
|
const (
|
||||||
|
_CPU_SETSIZE = 0x400
|
||||||
|
_NCPUBITS = 0x40
|
||||||
|
)
|
||||||
|
|||||||
@@ -799,3 +799,10 @@ const (
|
|||||||
CTRL_ATTR_MCAST_GRP_NAME = 0x1
|
CTRL_ATTR_MCAST_GRP_NAME = 0x1
|
||||||
CTRL_ATTR_MCAST_GRP_ID = 0x2
|
CTRL_ATTR_MCAST_GRP_ID = 0x2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type cpuMask uint64
|
||||||
|
|
||||||
|
const (
|
||||||
|
_CPU_SETSIZE = 0x400
|
||||||
|
_NCPUBITS = 0x40
|
||||||
|
)
|
||||||
|
|||||||
@@ -816,3 +816,10 @@ const (
|
|||||||
CTRL_ATTR_MCAST_GRP_NAME = 0x1
|
CTRL_ATTR_MCAST_GRP_NAME = 0x1
|
||||||
CTRL_ATTR_MCAST_GRP_ID = 0x2
|
CTRL_ATTR_MCAST_GRP_ID = 0x2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type cpuMask uint64
|
||||||
|
|
||||||
|
const (
|
||||||
|
_CPU_SETSIZE = 0x400
|
||||||
|
_NCPUBITS = 0x40
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user