diff --git a/headers/compatibility/gnu/sched.h b/headers/compatibility/gnu/sched.h new file mode 100644 index 0000000000..eaa5221071 --- /dev/null +++ b/headers/compatibility/gnu/sched.h @@ -0,0 +1,29 @@ +/* +* Copyright 2023 Haiku, Inc. All Rights Reserved. +* Distributed under the terms of the MIT License. +*/ +#ifndef _GNU_SCHED_H_ +#define _GNU_SCHED_H_ + + +#include_next + + +#ifdef _GNU_SOURCE + + +#ifdef __cplusplus +extern "C" { +#endif + +extern int sched_getcpu(void); + +#ifdef __cplusplus +} +#endif + + +#endif + + +#endif /* _GNU_SCHED_H_ */ diff --git a/headers/private/kernel/thread.h b/headers/private/kernel/thread.h index 771d650d1c..4d5e28a6a8 100644 --- a/headers/private/kernel/thread.h +++ b/headers/private/kernel/thread.h @@ -159,6 +159,7 @@ status_t _user_receive_data(thread_id *_sender, void *buffer, size_t buffer_size thread_id _user_find_thread(const char *name); status_t _user_get_thread_info(thread_id id, thread_info *info); status_t _user_get_next_thread_info(team_id team, int32 *cookie, thread_info *info); +int _user_get_cpu(); status_t _user_block_thread(uint32 flags, bigtime_t timeout); status_t _user_unblock_thread(thread_id thread, status_t status); diff --git a/headers/private/system/syscalls.h b/headers/private/system/syscalls.h index c5ce7e2a71..ad50b84025 100644 --- a/headers/private/system/syscalls.h +++ b/headers/private/system/syscalls.h @@ -196,6 +196,7 @@ extern status_t _kern_get_team_usage_info(team_id team, int32 who, team_usage_info *info, size_t size); extern status_t _kern_get_extended_team_info(team_id teamID, uint32 flags, void* buffer, size_t size, size_t* _sizeNeeded); +extern int _kern_get_cpu(); extern status_t _kern_start_watching_system(int32 object, uint32 flags, port_id port, int32 token); diff --git a/src/libs/gnu/Jamfile b/src/libs/gnu/Jamfile index bb7d90d4dc..8f3f110247 100644 --- a/src/libs/gnu/Jamfile +++ b/src/libs/gnu/Jamfile @@ -10,10 +10,16 @@ SubDirC++Flags [ FDefines _GNU_SOURCE=1 ] ; local architectureObject ; for architectureObject in [ MultiArchSubDirSetup ] { on $(architectureObject) { + UsePrivateSystemHeaders ; + if $(TARGET_ARCH) = x86_64 { + SubDirC++Flags -mrdpid ; + } + SharedLibrary [ MultiArchDefaultGristFiles libgnu.so ] : crypt.cpp memmem.c qsort.c + sched_getcpu.cpp xattr.cpp ; } diff --git a/src/libs/gnu/sched_getcpu.cpp b/src/libs/gnu/sched_getcpu.cpp new file mode 100644 index 0000000000..e3bc4b211e --- /dev/null +++ b/src/libs/gnu/sched_getcpu.cpp @@ -0,0 +1,90 @@ +/* + * Copyright 2023, Jérôme Duval, jerome.duval@gmail.com. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include + +#ifdef __x86_64__ + +#include + +#include + +#define IA32_FEATURE_RDPID (1 << 22) // RDPID Instruction +#define IA32_FEATURE_AMD_EXT_RDTSCP (1 << 27) // rdtscp instruction + + +typedef int (*sched_cpu_func)(); +static pthread_once_t sSchedCpuInitOnce = PTHREAD_ONCE_INIT; +static sched_cpu_func sSchedCpuFunc = NULL; + + +static int +__sched_cpu_syscall() +{ + return _kern_get_cpu(); +} + + +static int +__sched_cpu_rdtscp() +{ + uint32_t aux; + __rdtscp(&aux); + return aux; +} + + +static int +__sched_cpu_rdpid() +{ + return _rdpid_u32(); +} + + +static void +initSchedCpuFunc() +{ + cpuid_info cpuInfo; + get_cpuid(&cpuInfo, 0, 0); + if (cpuInfo.eax_0.max_eax >= 0x7) { + get_cpuid(&cpuInfo, 0x7, 0); + if ((cpuInfo.regs.ecx & IA32_FEATURE_RDPID) != 0) { + sSchedCpuFunc = __sched_cpu_rdpid; + return; + } + } + get_cpuid(&cpuInfo, 0x80000000, 0); + if (cpuInfo.eax_0.max_eax >= 0x80000001) { + get_cpuid(&cpuInfo, 0x80000001, 0); + if ((cpuInfo.regs.edx & IA32_FEATURE_AMD_EXT_RDTSCP)!= 0) { + sSchedCpuFunc = __sched_cpu_rdtscp; + return; + } + } + sSchedCpuFunc = __sched_cpu_syscall; +} + + +int +sched_getcpu() +{ + if (sSchedCpuFunc == NULL) { + pthread_once(&sSchedCpuInitOnce, &initSchedCpuFunc); + } + return sSchedCpuFunc(); +} + + +#else +int +sched_getcpu() +{ + return _kern_get_cpu(); +} +#endif + diff --git a/src/system/kernel/thread.cpp b/src/system/kernel/thread.cpp index 475c2d3bb6..59b87bd0fd 100644 --- a/src/system/kernel/thread.cpp +++ b/src/system/kernel/thread.cpp @@ -3915,3 +3915,11 @@ _user_setrlimit(int resource, const struct rlimit *userResourceLimit) return common_setrlimit(resource, &resourceLimit); } + + +int +_user_get_cpu() +{ + Thread* thread = thread_get_current_thread(); + return thread->cpu->cpu_num; +} diff --git a/src/tests/libs/gnu/Jamfile b/src/tests/libs/gnu/Jamfile new file mode 100644 index 0000000000..9e26cfc3eb --- /dev/null +++ b/src/tests/libs/gnu/Jamfile @@ -0,0 +1,8 @@ +SubDir HAIKU_TOP src tests libs gnu ; + +UseHeaders [ FDirName $(HAIKU_TOP) headers compatibility gnu ] : true ; +SubDirC++Flags [ FDefines _GNU_SOURCE=1 ] ; + +SimpleTest sched_getcpu_test : sched_getcpu_test.cpp : libgnu.so ; + + diff --git a/src/tests/libs/gnu/sched_getcpu_test.cpp b/src/tests/libs/gnu/sched_getcpu_test.cpp new file mode 100644 index 0000000000..f225197d82 --- /dev/null +++ b/src/tests/libs/gnu/sched_getcpu_test.cpp @@ -0,0 +1,18 @@ +/* + * Copyright 2023, Jérôme Duval, jerome.duval@gmail.com. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include +#include + + +int +main(int argc, char** argv) +{ + int cpu = sched_getcpu(); + printf("cpu: %d\n", cpu); + return 0; +} +