Improve the affinity system calls

This commit is contained in:
Justine Tunney 2022-10-06 15:08:29 -07:00
parent 60b68d7152
commit 59ac141e49
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
19 changed files with 231 additions and 123 deletions

View file

@ -1,13 +1,19 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_SCHED_SYSV_INTERNAL_H_ #ifndef COSMOPOLITAN_LIBC_CALLS_SCHED_SYSV_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_SCHED_SYSV_INTERNAL_H_ #define COSMOPOLITAN_LIBC_CALLS_SCHED_SYSV_INTERNAL_H_
#include "libc/calls/struct/sched_param.h" #include "libc/calls/struct/sched_param.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define MAXCPUS_NETBSD 256 #define MAXCPUS_NETBSD 256
#define MAXCPUS_FREEBSD 256
#define MAXCPUS_OPENBSD 64 #define MAXCPUS_OPENBSD 64
#define P_ALL_LWPS 0 /* for effect on all threads in pid */ #define P_ALL_LWPS 0 /* for effect on all threads in pid */
#define CPU_LEVEL_WHICH 3
#define CPU_WHICH_TID 1
#define CPU_WHICH_PID 2
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
int sys_sched_get_priority_max(int); int sys_sched_get_priority_max(int);
int sys_sched_get_priority_min(int); int sys_sched_get_priority_min(int);
int sys_sched_getparam(int, struct sched_param *); int sys_sched_getparam(int, struct sched_param *);
@ -28,6 +34,12 @@ int sys_sched_setaffinity_netbsd(int, int, size_t, const void *) //
int sys_sched_getaffinity_netbsd(int, int, size_t, void *) // int sys_sched_getaffinity_netbsd(int, int, size_t, void *) //
asm("sys_sched_setaffinity"); asm("sys_sched_setaffinity");
int sys_sched_setaffinity_freebsd(
int level, int which, int id, size_t setsize,
const void *mask) asm("sys_sched_setaffinity");
int sys_sched_getaffinity_freebsd(int level, int which, int id, size_t setsize,
void *mask) asm("sys_sched_getaffinity");
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_SCHED_SYSV_INTERNAL_H_ */ #endif /* COSMOPOLITAN_LIBC_CALLS_SCHED_SYSV_INTERNAL_H_ */

View file

@ -17,59 +17,79 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/sched-sysv.internal.h" #include "libc/calls/sched-sysv.internal.h"
#include "libc/calls/struct/cpuset.h" #include "libc/calls/struct/cpuset.h"
#include "libc/calls/syscall_support-nt.internal.h" #include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/strace.internal.h" #include "libc/intrin/strace.internal.h"
#include "libc/macros.internal.h" #include "libc/nt/enum/processaccess.h"
#include "libc/nt/process.h" #include "libc/nt/process.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/nt/thread.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
static textwindows int sys_sched_getaffinity_nt(int tid, size_t size, static dontinline textwindows int sys_sched_getaffinity_nt(int pid, size_t size,
cpu_set_t *bitset) { cpu_set_t *bitset) {
uint64_t ProcessAffinityMask, SystemAffinityMask; int rc;
if (GetProcessAffinityMask(GetCurrentProcess(), &ProcessAffinityMask, int64_t h, closeme = -1;
&SystemAffinityMask)) { uint64_t SystemAffinityMask;
bzero(bitset, size);
bitset->__bits[0] = ProcessAffinityMask; if (!pid || pid == getpid()) {
return 0; h = GetCurrentProcess();
} else if (__isfdkind(pid, kFdProcess)) {
h = g_fds.p[pid].handle;
} else { } else {
return __winerr(); h = OpenProcess(kNtProcessQueryInformation, false, pid);
if (!h) return __winerr();
closeme = h;
} }
if (GetProcessAffinityMask(h, bitset->__bits, &SystemAffinityMask)) {
rc = 8;
} else {
rc = __winerr();
}
if (closeme != -1) {
CloseHandle(closeme);
}
return rc;
} }
/** /**
* Gets CPU affinity for thread. * Gets CPU affinity for process.
* *
* While Windows allows us to change the thread affinity mask, it's only * @param pid is the process id (or 0 for caller)
* possible to read the process affinity mask. Therefore this function * @param size is bytes in bitset, which should be `sizeof(cpuset_t)`
* won't reflect the changes made by sched_setaffinity() on Windows.
*
* @param pid is the process or thread id (or 0 for caller)
* @param size is byte length of bitset, which should 128
* @param bitset receives bitset and should be uint64_t[16] in order to * @param bitset receives bitset and should be uint64_t[16] in order to
* work on older versions of Linux * work on older versions of Linux
* @return 0 on success, or -1 w/ errno * @return 0 on success, or -1 w/ errno
* @raise ENOSYS if not Linux, NetBSD, or Windows * @raise ENOSYS if not Linux, FreeBSD, NetBSD, or Windows
* @see pthread_getaffinity_np() for threads
*/ */
int sched_getaffinity(int tid, size_t size, cpu_set_t *bitset) { int sched_getaffinity(int pid, size_t size, cpu_set_t *bitset) {
int rc; int rc;
if (size != 128) { if (size != sizeof(cpu_set_t)) {
rc = einval(); rc = einval();
} else if (IsWindows()) { } else if (IsWindows()) {
rc = sys_sched_getaffinity_nt(tid, size, bitset); rc = sys_sched_getaffinity_nt(pid, size, bitset);
} else if (IsFreebsd()) {
if (!sys_sched_getaffinity_freebsd(CPU_LEVEL_WHICH, CPU_WHICH_PID, pid, 32,
bitset)) {
rc = 32;
} else {
rc = -1;
}
} else if (IsNetbsd()) { } else if (IsNetbsd()) {
if (!sys_sched_getaffinity_netbsd(0, tid, MIN(size, 32), bitset)) { if (!sys_sched_getaffinity_netbsd(P_ALL_LWPS, pid, 32, bitset)) {
rc = MIN(size, 32); rc = 32;
} else { } else {
rc = -1; rc = -1;
} }
} else { } else {
rc = sys_sched_getaffinity(tid, size, bitset); rc = sys_sched_getaffinity(pid, size, bitset);
} }
if (rc > 0) { if (rc > 0) {
if (rc < size) { if (rc < size) {
@ -77,6 +97,6 @@ int sched_getaffinity(int tid, size_t size, cpu_set_t *bitset) {
} }
rc = 0; rc = 0;
} }
STRACE("sched_getaffinity(%d, %'zu, %p) → %d% m", tid, size, bitset, rc); STRACE("sched_getaffinity(%d, %'zu, %p) → %d% m", pid, size, bitset, rc);
return rc; return rc;
} }

View file

@ -16,75 +16,69 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/calls.h" #include "libc/calls/internal.h"
#include "libc/calls/sched-sysv.internal.h" #include "libc/calls/sched-sysv.internal.h"
#include "libc/calls/struct/cpuset.h" #include "libc/calls/struct/cpuset.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-nt.internal.h" #include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/intrin/strace.internal.h" #include "libc/intrin/strace.internal.h"
#include "libc/limits.h"
#include "libc/macros.internal.h"
#include "libc/nt/enum/processaccess.h" #include "libc/nt/enum/processaccess.h"
#include "libc/nt/enum/threadaccess.h"
#include "libc/nt/process.h" #include "libc/nt/process.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/nt/thread.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
static textwindows dontinline int sys_sched_setaffinity_nt(int pid, static dontinline textwindows int sys_sched_setaffinity_nt(
uint64_t size, int pid, uint64_t size, const cpu_set_t *bitset) {
const void *bitset) {
int rc; int rc;
int64_t handle; int64_t h, closeme = -1;
uintptr_t mask;
typeof(SetThreadAffinityMask) *SetAffinityMask = SetThreadAffinityMask; if (!pid /* || pid == getpid() */) {
mask = 0; h = GetCurrentProcess();
memcpy(&mask, bitset, min(size, sizeof(uintptr_t))); } else if (__isfdkind(pid, kFdProcess)) {
handle = 0; h = g_fds.p[pid].handle;
if (!pid) pid = GetCurrentThreadId(); } else {
if (0 < pid && pid <= UINT32_MAX) { h = OpenProcess(kNtProcessSetInformation | kNtProcessQueryInformation,
if (pid == GetCurrentProcessId()) { false, pid);
pid = GetCurrentProcess(); if (!h) return __winerr();
SetAffinityMask = SetProcessAffinityMask; closeme = h;
} else if (pid == GetCurrentThreadId()) {
pid = GetCurrentThread();
} else {
handle = OpenThread(kNtThreadSetInformation | kNtThreadQueryInformation,
false, pid);
if (!handle) {
handle = OpenProcess(
kNtProcessSetInformation | kNtProcessQueryInformation, false, pid);
SetAffinityMask = SetProcessAffinityMask;
}
}
} }
rc = SetAffinityMask(handle ? handle : pid, mask) ? 0 : __winerr();
if (handle) CloseHandle(handle); if (SetProcessAffinityMask(h, bitset->__bits[0])) {
rc = 0;
} else {
rc = __winerr();
}
if (closeme != -1) {
CloseHandle(closeme);
}
return rc; return rc;
} }
/** /**
* Asks kernel to only schedule thread on particular CPUs. * Asks kernel to only schedule process on particular CPUs.
* *
* @param tid is the process or thread id (or 0 for caller) * @param pid is the process or process id (or 0 for caller)
* @param size is byte length of bitset, which should be 128 * @param size is bytes in bitset, which should be `sizeof(cpuset_t)`
* @return 0 on success, or -1 w/ errno * @return 0 on success, or -1 w/ errno
* @raise ENOSYS if not Linux, NetBSD, or Windows * @raise ENOSYS if not Linux, FreeBSD, NetBSD, or Windows
* @see pthread_getaffinity_np() for threads
*/ */
int sched_setaffinity(int tid, size_t size, const cpu_set_t *bitset) { int sched_setaffinity(int pid, size_t size, const cpu_set_t *bitset) {
int rc; int rc;
if (size != 128) { if (size != sizeof(cpu_set_t)) {
rc = einval(); rc = einval();
} else if (IsWindows()) { } else if (IsWindows()) {
rc = sys_sched_setaffinity_nt(tid, size, bitset); rc = sys_sched_setaffinity_nt(pid, size, bitset);
} else if (IsFreebsd()) {
rc = sys_sched_setaffinity_freebsd(CPU_LEVEL_WHICH, CPU_WHICH_PID, pid, 32,
bitset);
} else if (IsNetbsd()) { } else if (IsNetbsd()) {
rc = sys_sched_setaffinity_netbsd(0, tid, MIN(size, 32), bitset); rc = sys_sched_setaffinity_netbsd(P_ALL_LWPS, pid, 32, bitset);
} else { } else {
rc = sys_sched_setaffinity(tid, size, bitset); rc = sys_sched_setaffinity(pid, size, bitset);
} }
STRACE("sched_setaffinity(%d, %'zu, %p) → %d% m", tid, size, bitset, rc); STRACE("sched_setaffinity(%d, %'zu, %p) → %d% m", pid, size, bitset, rc);
return rc; return rc;
} }

View file

@ -20,7 +20,7 @@
#include "libc/intrin/describeflags.internal.h" #include "libc/intrin/describeflags.internal.h"
#include "libc/str/str.h" #include "libc/str/str.h"
const char *(DescribeFutexResult)(char buf[12], int ax) { const char *(DescribeErrnoResult)(char buf[12], int ax) {
const char *s; const char *s;
if (ax > -4095u && (s = _strerrno(-ax))) { if (ax > -4095u && (s = _strerrno(-ax))) {
return s; return s;

View file

@ -16,9 +16,9 @@ const char *DescribeArchPrctlCode(char[12], int);
const char *DescribeCapability(char[20], int); const char *DescribeCapability(char[20], int);
const char *DescribeClockName(char[32], int); const char *DescribeClockName(char[32], int);
const char *DescribeDirfd(char[12], int); const char *DescribeDirfd(char[12], int);
const char *DescribeErrnoResult(char[12], int);
const char *DescribeFrame(char[32], int); const char *DescribeFrame(char[32], int);
const char *DescribeFutexOp(char[64], int); const char *DescribeFutexOp(char[64], int);
const char *DescribeFutexResult(char[12], int);
const char *DescribeHow(char[12], int); const char *DescribeHow(char[12], int);
const char *DescribeInOutInt64(char[23], ssize_t, int64_t *); const char *DescribeInOutInt64(char[23], ssize_t, int64_t *);
const char *DescribeMapFlags(char[64], int); const char *DescribeMapFlags(char[64], int);
@ -62,9 +62,9 @@ const char *DescribeWhence(char[12], int);
#define DescribeCapability(x) DescribeCapability(alloca(20), x) #define DescribeCapability(x) DescribeCapability(alloca(20), x)
#define DescribeClockName(x) DescribeClockName(alloca(32), x) #define DescribeClockName(x) DescribeClockName(alloca(32), x)
#define DescribeDirfd(x) DescribeDirfd(alloca(12), x) #define DescribeDirfd(x) DescribeDirfd(alloca(12), x)
#define DescribeErrnoResult(x) DescribeErrnoResult(alloca(12), x)
#define DescribeFrame(x) DescribeFrame(alloca(32), x) #define DescribeFrame(x) DescribeFrame(alloca(32), x)
#define DescribeFutexOp(x) DescribeFutexOp(alloca(64), x) #define DescribeFutexOp(x) DescribeFutexOp(alloca(64), x)
#define DescribeFutexResult(x) DescribeFutexResult(alloca(12), x)
#define DescribeHow(x) DescribeHow(alloca(12), x) #define DescribeHow(x) DescribeHow(alloca(12), x)
#define DescribeInOutInt64(rc, x) DescribeInOutInt64(alloca(23), rc, x) #define DescribeInOutInt64(rc, x) DescribeInOutInt64(alloca(23), rc, x)
#define DescribeMapFlags(x) DescribeMapFlags(alloca(64), x) #define DescribeMapFlags(x) DescribeMapFlags(alloca(64), x)

View file

@ -61,7 +61,7 @@ int32_t SetEnvironmentStrings(char16_t *NewEnvironment);
bool32 GetProcessAffinityMask(int64_t hProcess, uint64_t *lpProcessAffinityMask, bool32 GetProcessAffinityMask(int64_t hProcess, uint64_t *lpProcessAffinityMask,
uint64_t *lpSystemAffinityMask); uint64_t *lpSystemAffinityMask);
uint64_t /*bool32*/ SetProcessAffinityMask(int64_t hProcess, uint64_t /*bool32*/ SetProcessAffinityMask(int64_t hProcess,
uintptr_t dwProcessAffinityMask); uint64_t dwProcessAffinityMask);
/* e.g. kNtAboveNormalPriorityClass, kNtHighPriorityClass */ /* e.g. kNtAboveNormalPriorityClass, kNtHighPriorityClass */
uint32_t GetPriorityClass(int64_t hProcess); uint32_t GetPriorityClass(int64_t hProcess);

View file

@ -18,6 +18,7 @@
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/struct/sigset.h" #include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/syscall-nt.internal.h" #include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
@ -39,9 +40,9 @@ int fork(void) {
axdx_t ad; axdx_t ad;
sigset_t old, all; sigset_t old, all;
int ax, dx, parent; int ax, dx, parent;
sigfillset(&all);
sigprocmask(SIG_BLOCK, &all, &old);
if (!IsWindows()) { if (!IsWindows()) {
sigfillset(&all);
sys_sigprocmask(SIG_BLOCK, &all, &old);
ad = sys_fork(); ad = sys_fork();
ax = ad.ax; ax = ad.ax;
dx = ad.dx; dx = ad.dx;
@ -64,10 +65,10 @@ int fork(void) {
if (__tls_enabled) { if (__tls_enabled) {
__get_tls()->tib_tid = IsLinux() ? dx : sys_gettid(); __get_tls()->tib_tid = IsLinux() ? dx : sys_gettid();
} }
sigprocmask(SIG_SETMASK, &old, 0); if (!IsWindows()) sys_sigprocmask(SIG_SETMASK, &old, 0);
STRACE("fork() → 0 (child of %d)", parent); STRACE("fork() → 0 (child of %d)", parent);
} else { } else {
sigprocmask(SIG_SETMASK, &old, 0); if (!IsWindows()) sys_sigprocmask(SIG_SETMASK, &old, 0);
STRACE("fork() → %d% m", ax); STRACE("fork() → %d% m", ax);
} }
return ax; return ax;

View file

@ -1,2 +0,0 @@
.include "o/libc/sysv/macros.internal.inc"
.scall sys_cpuset_getaffinity,0xffffff1e7fffffff,globl

View file

@ -1,2 +0,0 @@
.include "o/libc/sysv/macros.internal.inc"
.scall sys_cpuset_setaffinity,0xffffff1e8fffffff,globl

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/macros.internal.inc" .include "o/libc/sysv/macros.internal.inc"
.scall sys_sched_getaffinity,0x15dffffffffff0cc,globl,hidden .scall sys_sched_getaffinity,0x15dfff1e7ffff0cc,globl,hidden

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/macros.internal.inc" .include "o/libc/sysv/macros.internal.inc"
.scall sys_sched_setaffinity,0x15cffffffffff0cb,globl,hidden .scall sys_sched_setaffinity,0x15cfff1e8ffff0cb,globl,hidden

View file

@ -202,12 +202,10 @@ scall sys_sched_setparam 0x15afff147ffff08e globl hidden
scall sys_sched_getparam 0x15bfff148ffff08f globl hidden scall sys_sched_getparam 0x15bfff148ffff08f globl hidden
scall sys_sched_setscheduler 0xffffff149ffff090 globl hidden scall sys_sched_setscheduler 0xffffff149ffff090 globl hidden
scall sys_sched_getscheduler 0xffffff14affff091 globl hidden scall sys_sched_getscheduler 0xffffff14affff091 globl hidden
scall sys_sched_setaffinity 0x15cffffffffff0cb globl hidden scall sys_sched_setaffinity 0x15cfff1e8ffff0cb globl hidden # hairy; cpuset_setaffinity on FreeBSD
scall sys_sched_getaffinity 0x15dffffffffff0cc globl hidden # returns bytes written on success. we polyfill bad posix designs like nice() returning 0, but we won't polyfill a bad unilateral redesign that's just glibc scall sys_sched_getaffinity 0x15dfff1e7ffff0cc globl hidden # hairy; cpuset_getaffinity on FreeBSD
scall sys_sched_get_priority_max 0xffffff14cffff092 globl hidden scall sys_sched_get_priority_max 0xffffff14cffff092 globl hidden
scall sys_sched_get_priority_min 0xffffff14dffff093 globl hidden scall sys_sched_get_priority_min 0xffffff14dffff093 globl hidden
scall sys_cpuset_getaffinity 0xffffff1e7fffffff globl # no wrapper
scall sys_cpuset_setaffinity 0xffffff1e8fffffff globl # no wrapper
scall sys_sched_rr_get_interval 0xffffff14effff094 globl hidden scall sys_sched_rr_get_interval 0xffffff14effff094 globl hidden
scall sys_vhangup 0xfffffffffffff099 globl # no wrapper scall sys_vhangup 0xfffffffffffff099 globl # no wrapper
scall sys_modify_ldt 0xfffffffffffff09a globl # no wrapper scall sys_modify_ldt 0xfffffffffffff09a globl # no wrapper

View file

@ -16,30 +16,57 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/sched-sysv.internal.h"
#include "libc/calls/struct/cpuset.h" #include "libc/calls/struct/cpuset.h"
#include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/posixthread.internal.h" #include "libc/thread/posixthread.internal.h"
/** /**
* Gets CPU affinity for thread. * Gets CPU affinity for thread.
* *
* While Windows allows us to change the thread affinity mask, it's only * @param size is bytes in bitset, which should be `sizeof(cpu_set_t)`
* possible to read the process affinity mask. Therefore this function
* won't reflect the changes made by psched_setaffinity_np() on Windows.
*
* @param bitsetsize is byte length of bitset, which should be 128
* @return 0 on success, or errno on error * @return 0 on success, or errno on error
* @raise ENOSYS if not Linux or Windows * @raise EINVAL if `size` or `bitset` is invalid
* @raise ENOSYS if not Linux, FreeBSD, or NetBSD
*/ */
errno_t pthread_getaffinity_np(pthread_t thread, size_t bitsetsize, errno_t pthread_getaffinity_np(pthread_t thread, size_t size,
cpu_set_t *bitset) { cpu_set_t *bitset) {
int rc, e = errno; int tid, rc, e = errno;
struct PosixThread *pt = (struct PosixThread *)thread; tid = ((struct PosixThread *)thread)->tid;
if (!sched_getaffinity(pt->tid, bitsetsize, bitset)) {
return 0; if (size != sizeof(cpu_set_t)) {
rc = einval();
} else if (IsWindows() || IsMetal() || IsOpenbsd()) {
rc = enosys();
} else if (IsFreebsd()) {
if (!sys_sched_getaffinity_freebsd(CPU_LEVEL_WHICH, CPU_WHICH_TID, tid, 32,
bitset)) {
rc = 32;
} else {
rc = -1;
}
} else if (IsNetbsd()) {
if (!sys_sched_getaffinity_netbsd(tid, 0, 32, bitset)) {
rc = 32;
} else {
rc = -1;
}
} else { } else {
rc = errno; rc = sys_sched_getaffinity(tid, size, bitset);
errno = e;
return rc;
} }
if (rc > 0) {
if (rc < size) {
bzero((char *)bitset + rc, size - rc);
}
rc = 0;
}
STRACE("pthread_getaffinity_np(%d, %'zu, %p) → %s", tid, size, bitset,
DescribeErrnoResult(rc));
return rc;
} }

View file

@ -16,26 +16,61 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/sched-sysv.internal.h"
#include "libc/calls/struct/cpuset.h" #include "libc/calls/struct/cpuset.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/nt/enum/threadaccess.h"
#include "libc/nt/runtime.h"
#include "libc/nt/thread.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/posixthread.internal.h" #include "libc/thread/posixthread.internal.h"
static dontinline textwindows int sys_pthread_setaffinity_nt(
int tid, uint64_t size, const cpu_set_t *bitset) {
int rc;
int64_t h;
h = OpenThread(kNtThreadSetInformation | kNtThreadQueryInformation, false,
tid);
if (!h) return __winerr();
rc = SetThreadAffinityMask(h, bitset->__bits[0]) ? 0 : __winerr();
CloseHandle(h);
return rc;
}
/** /**
* Asks kernel to only schedule thread on particular CPUs. * Asks kernel to only schedule thread on particular CPUs.
* *
* @param bitsetsize is byte length of bitset, which should be 128 * @param size is bytes in bitset, which should be `sizeof(cpu_set_t)`
* @return 0 on success, or errno on error * @return 0 on success, or errno on error
* @raise ENOSYS if not Linux or Windows * @raise EINVAL if `size` or `bitset` is invalid
* @raise ENOSYS if not Linux, FreeBSD, NetBSD, or Windows
* @see sched_setaffinity() for processes
*/ */
errno_t pthread_setaffinity_np(pthread_t thread, size_t bitsetsize, errno_t pthread_setaffinity_np(pthread_t thread, size_t size,
const cpu_set_t *bitset) { const cpu_set_t *bitset) {
int rc, e = errno; int tid, rc, e = errno;
struct PosixThread *pt = (struct PosixThread *)thread; tid = ((struct PosixThread *)thread)->tid;
if (!sched_setaffinity(pt->tid, bitsetsize, bitset)) { if (size != sizeof(cpu_set_t)) {
return 0; rc = einval();
} else if (IsWindows()) {
rc = sys_pthread_setaffinity_nt(tid, size, bitset);
} else if (IsFreebsd()) {
rc = sys_sched_setaffinity_freebsd(CPU_LEVEL_WHICH, CPU_WHICH_TID, tid, 32,
bitset);
} else if (IsNetbsd()) {
rc = sys_sched_setaffinity_netbsd(tid, 0, 32, bitset);
} else { } else {
rc = sys_sched_setaffinity(tid, size, bitset);
}
if (rc == -1) {
rc = errno; rc = errno;
errno = e; errno = e;
return rc;
} }
STRACE("pthread_setaffinity_np(%d, %'zu, %p) → %s", tid, size, bitset,
DescribeErrnoResult(rc));
return rc;
} }

View file

@ -74,7 +74,7 @@ static void _wait0_futex(const atomic_int *a, int e) {
} }
} }
STRACE("futex(%t, %s, %d, %s) → %s", a, DescribeFutexOp(op), e, "NULL", STRACE("futex(%t, %s, %d, %s) → %s", a, DescribeFutexOp(op), e, "NULL",
DescribeFutexResult(rc)); DescribeErrnoResult(rc));
_npassert(rc == 0 || // _npassert(rc == 0 || //
rc == -EINTR || // rc == -EINTR || //
rc == -ETIMEDOUT || // rc == -ETIMEDOUT || //

View file

@ -23,9 +23,11 @@
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/runtime/sysconf.h" #include "libc/runtime/sysconf.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
#include "libc/thread/thread.h"
#include "libc/thread/thread2.h"
void SetUp(void) { void SetUp(void) {
if (!IsLinux()) { if (!IsLinux() && !IsFreebsd() && !IsWindows()) {
exit(0); exit(0);
} }
} }
@ -52,3 +54,26 @@ TEST(sched_getaffinity, secondOnly) {
EXPECT_FALSE(CPU_ISSET(0, &y)); EXPECT_FALSE(CPU_ISSET(0, &y));
EXPECT_TRUE(CPU_ISSET(1, &y)); EXPECT_TRUE(CPU_ISSET(1, &y));
} }
TEST(sched_getaffinity, getpid) {
cpu_set_t x, y;
CPU_ZERO(&x);
CPU_SET(0, &x);
ASSERT_SYS(0, 0, sched_setaffinity(getpid(), sizeof(x), &x));
ASSERT_SYS(0, 0, sched_getaffinity(getpid(), sizeof(y), &y));
EXPECT_EQ(1, CPU_COUNT(&y));
EXPECT_TRUE(CPU_ISSET(0, &y));
EXPECT_FALSE(CPU_ISSET(1, &y));
}
TEST(pthread_getaffinity, getpid) {
cpu_set_t x, y;
CPU_ZERO(&x);
CPU_SET(0, &x);
ASSERT_SYS(0, 0, pthread_setaffinity_np(pthread_self(), sizeof(x), &x));
if (IsWindows()) return; // win32 doesn't define GetThreadAffinityMask ;_;
ASSERT_SYS(0, 0, pthread_getaffinity_np(pthread_self(), sizeof(y), &y));
EXPECT_EQ(1, CPU_COUNT(&y));
EXPECT_TRUE(CPU_ISSET(0, &y));
EXPECT_FALSE(CPU_ISSET(1, &y));
}

View file

@ -160,7 +160,7 @@ int nsync_futex_wait_ (int *p, int expect, char pshare, struct timespec *timeout
STRACE("futex(%t, %s, %d, %s) → %s", STRACE("futex(%t, %s, %d, %s) → %s",
p, DescribeFutexOp (op), expect, p, DescribeFutexOp (op), expect,
DescribeTimespec (0, timeout), DescribeTimespec (0, timeout),
DescribeFutexResult (rc)); DescribeErrnoResult (rc));
return rc; return rc;
} }
@ -201,7 +201,7 @@ int nsync_futex_wake_ (int *p, int count, char pshare) {
STRACE("futex(%t, %s, %d) → %s", p, STRACE("futex(%t, %s, %d) → %s", p,
DescribeFutexOp(op), DescribeFutexOp(op),
count, DescribeFutexResult(rc)); count, DescribeErrnoResult(rc));
return rc; return rc;
} }

View file

@ -5,7 +5,7 @@
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
typedef struct nsync_semaphore_s_ { typedef struct nsync_semaphore_s_ {
void *sem_space[1]; /* [jart] reduced to 8 bytes */ void *sem_space[32]; /* internal storage */
} nsync_semaphore; } nsync_semaphore;
/* Initialize *s; the initial value is 0. */ /* Initialize *s; the initial value is 0. */

View file

@ -4602,7 +4602,7 @@ UNIX MODULE
Exchanges value. Exchanges value.
This sets word at `word_index` to `value` and returns the value This sets word at `word_index` to `value` and returns the value
previously held in by the word. previously held within that word.
This operation is atomic and provides the same memory barrier This operation is atomic and provides the same memory barrier
semantics as the aligned x86 LOCK XCHG instruction. semantics as the aligned x86 LOCK XCHG instruction.
@ -4614,8 +4614,8 @@ UNIX MODULE
This inspects the word at `word_index` and if its value is the same This inspects the word at `word_index` and if its value is the same
as `old` then it'll be replaced by the value `new`, in which case as `old` then it'll be replaced by the value `new`, in which case
`true, old` shall be returned. If a different value was held at true shall be returned alongside `old`. If a different value was
word, then `false` shall be returned along with the word. held at word, then `false` shall be returned along with its value.
This operation happens atomically and provides the same memory This operation happens atomically and provides the same memory
barrier semantics as the aligned x86 LOCK CMPXCHG instruction. barrier semantics as the aligned x86 LOCK CMPXCHG instruction.
@ -4626,8 +4626,8 @@ UNIX MODULE
Fetches then adds value. Fetches then adds value.
This method modifies the word at `word_index` to contain the sum of This method modifies the word at `word_index` to contain the sum of
value and the `value` paremeter. This method then returns the value its value and the `value` paremeter. This method then returns the
as it existed before the addition was performed. value as it existed before the addition was performed.
This operation is atomic and provides the same memory barrier This operation is atomic and provides the same memory barrier
semantics as the aligned x86 LOCK XADD instruction. semantics as the aligned x86 LOCK XADD instruction.