xref: /haiku/src/libs/gnu/sched_getcpu.cpp (revision e1c4049fed1047bdb957b0529e1921e97ef94770)
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
27 __sched_cpu_syscall()
28 {
29 	return _kern_get_cpu();
30 }
31 
32 
33 static int
34 __sched_cpu_rdtscp()
35 {
36 	uint32_t aux;
37 	__rdtscp(&aux);
38 	return aux;
39 }
40 
41 
42 static int
43 __sched_cpu_rdpid()
44 {
45 	return _rdpid_u32();
46 }
47 
48 
49 static void
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
74 sched_getcpu()
75 {
76 	if (sSchedCpuFunc == NULL) {
77 		pthread_once(&sSchedCpuInitOnce, &initSchedCpuFunc);
78 	}
79 	return sSchedCpuFunc();
80 }
81 
82 
83 #else
84 int
85 sched_getcpu()
86 {
87 	return _kern_get_cpu();
88 }
89 #endif
90 
91