1 /*
2 * Copyright 2023, Jérôme Duval, jerome.duval@gmail.com. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7 #include <sched.h>
8
9 #include <syscalls.h>
10
11 #ifdef __x86_64__
12
13 #include <pthread.h>
14
15 #include <x86intrin.h>
16
17 #define IA32_FEATURE_RDPID (1 << 22) // RDPID Instruction
18 #define IA32_FEATURE_AMD_EXT_RDTSCP (1 << 27) // rdtscp instruction
19
20
21 typedef int (*sched_cpu_func)();
22 static pthread_once_t sSchedCpuInitOnce = PTHREAD_ONCE_INIT;
23 static sched_cpu_func sSchedCpuFunc = NULL;
24
25
26 static int
__sched_cpu_syscall()27 __sched_cpu_syscall()
28 {
29 return _kern_get_cpu();
30 }
31
32
33 static int
__sched_cpu_rdtscp()34 __sched_cpu_rdtscp()
35 {
36 uint32_t aux;
37 __rdtscp(&aux);
38 return aux;
39 }
40
41
42 static int
__sched_cpu_rdpid()43 __sched_cpu_rdpid()
44 {
45 return _rdpid_u32();
46 }
47
48
49 static void
initSchedCpuFunc()50 initSchedCpuFunc()
51 {
52 cpuid_info cpuInfo;
53 get_cpuid(&cpuInfo, 0, 0);
54 if (cpuInfo.eax_0.max_eax >= 0x7) {
55 get_cpuid(&cpuInfo, 0x7, 0);
56 if ((cpuInfo.regs.ecx & IA32_FEATURE_RDPID) != 0) {
57 sSchedCpuFunc = __sched_cpu_rdpid;
58 return;
59 }
60 }
61 get_cpuid(&cpuInfo, 0x80000000, 0);
62 if (cpuInfo.eax_0.max_eax >= 0x80000001) {
63 get_cpuid(&cpuInfo, 0x80000001, 0);
64 if ((cpuInfo.regs.edx & IA32_FEATURE_AMD_EXT_RDTSCP)!= 0) {
65 sSchedCpuFunc = __sched_cpu_rdtscp;
66 return;
67 }
68 }
69 sSchedCpuFunc = __sched_cpu_syscall;
70 }
71
72
73 int
sched_getcpu()74 sched_getcpu()
75 {
76 if (sSchedCpuFunc == NULL) {
77 pthread_once(&sSchedCpuInitOnce, &initSchedCpuFunc);
78 }
79 return sSchedCpuFunc();
80 }
81
82
83 #else
84 int
sched_getcpu()85 sched_getcpu()
86 {
87 return _kern_get_cpu();
88 }
89 #endif
90
91