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