diff --git a/libc/calls/calls.h b/libc/calls/calls.h index b9aaa5e3f..eab5592f4 100644 --- a/libc/calls/calls.h +++ b/libc/calls/calls.h @@ -208,6 +208,7 @@ int execvpe(const char *, char *const[], char *const[]) libcesque; int euidaccess(const char *, int) libcesque; int eaccess(const char *, int) libcesque; int madvise(void *, uint64_t, int) libcesque; +int getcpu(unsigned *, unsigned *) libcesque; #endif #ifdef _COSMO_SOURCE diff --git a/libc/calls/getcpu.c b/libc/calls/getcpu.c new file mode 100644 index 000000000..c25c52bad --- /dev/null +++ b/libc/calls/getcpu.c @@ -0,0 +1,76 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2024 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.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/nexgen32e/rdtscp.h" +#include "libc/nexgen32e/x86feature.h" +#include "libc/nt/struct/processornumber.h" +#include "libc/nt/synchronization.h" +#include "libc/runtime/syslib.internal.h" +#include "libc/sysv/errfuns.h" + +int sys_getcpu(unsigned *opt_cpu, unsigned *opt_node, void *tcache); + +int getcpu(unsigned *out_opt_cpu, unsigned *out_opt_node) { + unsigned cpu; + unsigned node; + if (X86_HAVE(RDTSCP)) { + unsigned tsc_aux; + rdtscp(&tsc_aux); + cpu = TSC_AUX_CORE(tsc_aux); + node = TSC_AUX_NODE(tsc_aux); + } else if (IsWindows()) { + struct NtProcessorNumber pn; + GetCurrentProcessorNumberEx(&pn); + cpu = 64 * pn.Group + pn.Number; + unsigned short node16; + if (GetNumaProcessorNodeEx(&pn, &node16)) { + node = node16; + } else { + return __winerr(); + } + } else if (IsXnuSilicon()) { + if (__syslib->__version >= 9) { + size_t cpu64; + errno_t err = __syslib->__pthread_cpu_number_np(&cpu64); + if (!err) { + cpu = cpu64; + node = 0; + } else { + errno = err; + return -1; + } + } else { + return enosys(); + } + } else { + int rc = sys_getcpu(&cpu, &node, 0); + if (rc == -1) return -1; + } + if (out_opt_cpu) { + *out_opt_cpu = cpu; + } + if (out_opt_node) { + *out_opt_node = node; + } + return 0; +} diff --git a/libc/nt/kernel32/GetNumaProcessorNodeEx.S b/libc/nt/kernel32/GetNumaProcessorNodeEx.S new file mode 100644 index 000000000..3d3a952a2 --- /dev/null +++ b/libc/nt/kernel32/GetNumaProcessorNodeEx.S @@ -0,0 +1,18 @@ +#include "libc/nt/codegen.h" +.imp kernel32,__imp_GetNumaProcessorNodeEx,GetNumaProcessorNodeEx + + .text.windows + .ftrace1 +GetNumaProcessorNodeEx: + .ftrace2 +#ifdef __x86_64__ + push %rbp + mov %rsp,%rbp + mov __imp_GetNumaProcessorNodeEx(%rip),%rax + jmp __sysv2nt +#elif defined(__aarch64__) + mov x0,#0 + ret +#endif + .endfn GetNumaProcessorNodeEx,globl + .previous diff --git a/libc/nt/master.sh b/libc/nt/master.sh index ff5ce813e..5529622ea 100755 --- a/libc/nt/master.sh +++ b/libc/nt/master.sh @@ -135,6 +135,7 @@ imp 'GetModuleHandle' GetModuleHandleA kernel32 1 imp 'GetModuleHandleEx' GetModuleHandleExW kernel32 3 imp 'GetModuleHandleW' GetModuleHandleW kernel32 1 imp 'GetNamedPipeInfo' GetNamedPipeInfo kernel32 5 +imp 'GetNumaProcessorNodeEx' GetNumaProcessorNodeEx kernel32 2 imp 'GetNumberOfConsoleInputEvents' GetNumberOfConsoleInputEvents kernel32 2 imp 'GetNumberOfConsoleMouseButtons' GetNumberOfConsoleMouseButtons kernel32 1 imp 'GetOverlappedResult' GetOverlappedResult kernel32 4 diff --git a/libc/nt/synchronization.h b/libc/nt/synchronization.h index d4cbef44f..dd365b33c 100644 --- a/libc/nt/synchronization.h +++ b/libc/nt/synchronization.h @@ -118,6 +118,9 @@ bool32 GetSystemTimeAdjustment(uint32_t *lpTimeAdjustment, void GetCurrentProcessorNumberEx(struct NtProcessorNumber *out_ProcNumber); +bool32 GetNumaProcessorNodeEx(const struct NtProcessorNumber *Processor, + unsigned short *out_NodeNumber); + #if ShouldUseMsabiAttribute() #include "libc/nt/thunk/synchronization.inc" #endif /* ShouldUseMsabiAttribute() */ diff --git a/libc/stdio/syscall.c b/libc/stdio/syscall.c index 66113d2e7..b66b575e5 100644 --- a/libc/stdio/syscall.c +++ b/libc/stdio/syscall.c @@ -43,8 +43,15 @@ long syscall(long number, ...) { size_t buflen = va_arg(va, size_t); unsigned flags = va_arg(va, unsigned); va_end(va); - ssize_t rc = getrandom(buf, buflen, flags); - return rc; + return getrandom(buf, buflen, flags); + } + case SYS_getcpu: { + va_list va; + va_start(va, number); + unsigned *cpu = va_arg(va, unsigned *); + unsigned *node = va_arg(va, unsigned *); + va_end(va); + return getcpu(cpu, node); } } } diff --git a/libc/stdio/syscall.h b/libc/stdio/syscall.h index afd3d67ef..5cbb2802b 100644 --- a/libc/stdio/syscall.h +++ b/libc/stdio/syscall.h @@ -2,8 +2,9 @@ #define COSMOPOLITAN_LIBC_STDIO_SYSCALL_H_ COSMOPOLITAN_C_START_ -#define SYS_gettid 186 -#define SYS_getrandom 318 +#define SYS_gettid 1 +#define SYS_getrandom 2 +#define SYS_getcpu 3 long syscall(long, ...) libcesque;