|
| 1 | +#include "stdafx.h" |
| 2 | +#include "ThreadHelper.h" |
| 3 | + |
| 4 | +#include "BuildConfig.h" |
| 5 | + |
| 6 | +#ifdef DISRUPTOR_OS_FAMILY_MACOS |
| 7 | + |
| 8 | +#include <string> |
| 9 | + |
| 10 | +#include <pthread.h> |
| 11 | +#include <unistd.h> |
| 12 | +#include <sched.h> |
| 13 | +#include <cpuid.h> |
| 14 | +#include <sys/sysctl.h> |
| 15 | +#include <sys/syscall.h> |
| 16 | +#include <sys/types.h> |
| 17 | +#include <mach/mach_types.h> |
| 18 | +#include <mach/thread_act.h> |
| 19 | + |
| 20 | +#define SYSCTL_CORE_COUNT "machdep.cpu.core_count" |
| 21 | + |
| 22 | +#define CPUID(INFO, LEAF, SUBLEAF) __cpuid_count(LEAF, SUBLEAF, INFO[0], INFO[1], INFO[2], INFO[3]) |
| 23 | + |
| 24 | +#define GETCPU(CPU) { \ |
| 25 | + uint32_t CPUInfo[4]; \ |
| 26 | + CPUID(CPUInfo, 1, 0); \ |
| 27 | + /* CPUInfo[1] is EBX, bits 24-31 are APIC ID */ \ |
| 28 | + if ( (CPUInfo[3] & (1 << 9)) == 0) { \ |
| 29 | + (CPU) = -1; /* no APIC on chip */ \ |
| 30 | + } \ |
| 31 | + else { \ |
| 32 | + (CPU) = (unsigned)CPUInfo[1] >> 24; \ |
| 33 | + } \ |
| 34 | + if ((CPU) < 0) (CPU) = 0; \ |
| 35 | + } |
| 36 | + |
| 37 | +namespace Disruptor |
| 38 | +{ |
| 39 | +namespace ThreadHelper |
| 40 | +{ |
| 41 | + typedef struct cpu_set { |
| 42 | + uint32_t count; |
| 43 | + } cpu_set_t; |
| 44 | + |
| 45 | + static inline void CPU_ZERO(cpu_set_t *cs) { cs->count = 0; } |
| 46 | + |
| 47 | + static inline void CPU_SET(int num, cpu_set_t *cs) { cs->count |= (1 << num); } |
| 48 | + |
| 49 | + static inline int CPU_ISSET(int num, cpu_set_t *cs) { return (cs->count & (1 << num)); } |
| 50 | + |
| 51 | + int sched_getaffinity(pid_t pid, size_t cpu_size, cpu_set_t *cpu_set) |
| 52 | + { |
| 53 | + (void) pid; |
| 54 | + (void) cpu_size; |
| 55 | + |
| 56 | + int32_t core_count = 0; |
| 57 | + size_t len = sizeof(core_count); |
| 58 | + int ret = sysctlbyname(SYSCTL_CORE_COUNT, &core_count, &len, 0, 0); |
| 59 | + if (ret) { |
| 60 | + return -1; |
| 61 | + } |
| 62 | + cpu_set->count = 0; |
| 63 | + for (int i = 0; i < core_count; i++) { |
| 64 | + cpu_set->count |= (1 << i); |
| 65 | + } |
| 66 | + |
| 67 | + return 0; |
| 68 | + } |
| 69 | + |
| 70 | + int pthread_setaffinity_np(pthread_t thread, size_t cpu_size, |
| 71 | + cpu_set_t *cpu_set) |
| 72 | + { |
| 73 | + thread_port_t mach_thread; |
| 74 | + int core = 0; |
| 75 | + |
| 76 | + for (core = 0; core < 8 * (int)cpu_size; core++) { |
| 77 | + if (CPU_ISSET(core, cpu_set)) break; |
| 78 | + } |
| 79 | + |
| 80 | + thread_affinity_policy_data_t policy = { core }; |
| 81 | + mach_thread = pthread_mach_thread_np(thread); |
| 82 | + thread_policy_set(mach_thread, THREAD_AFFINITY_POLICY, |
| 83 | + (thread_policy_t)&policy, 1); |
| 84 | + return 0; |
| 85 | + } |
| 86 | + |
| 87 | + |
| 88 | + size_t getProcessorCount() |
| 89 | + { |
| 90 | + return static_cast<size_t>(sysconf(_SC_NPROCESSORS_CONF)); |
| 91 | + } |
| 92 | + |
| 93 | + uint32_t getCurrentProcessor() |
| 94 | + { |
| 95 | + uint32_t cpu_id; |
| 96 | + |
| 97 | + GETCPU(cpu_id); |
| 98 | + |
| 99 | + return cpu_id; |
| 100 | + } |
| 101 | + |
| 102 | + bool setThreadAffinity(const AffinityMask& mask) |
| 103 | + { |
| 104 | + cpu_set_t cpuSet; |
| 105 | + CPU_ZERO(&cpuSet); |
| 106 | + |
| 107 | + for (size_t i = 0; i < mask.size(); ++i) |
| 108 | + { |
| 109 | + if (mask.test(i)) |
| 110 | + CPU_SET(i, &cpuSet); |
| 111 | + } |
| 112 | + |
| 113 | + return pthread_setaffinity_np(pthread_self(), sizeof(cpuSet), &cpuSet) == 0; |
| 114 | + } |
| 115 | + |
| 116 | + AffinityMask getThreadAffinity() |
| 117 | + { |
| 118 | + AffinityMask mask; |
| 119 | + |
| 120 | + cpu_set_t cpuSet; |
| 121 | + CPU_ZERO(&cpuSet); |
| 122 | + if (sched_getaffinity(0, sizeof(cpuSet), &cpuSet) == 0) |
| 123 | + { |
| 124 | + int processorCount = getProcessorCount(); |
| 125 | + int maskSize = (int) mask.size(); |
| 126 | + for (int i = 0; i < processorCount && i < maskSize; ++i) |
| 127 | + { |
| 128 | + if (CPU_ISSET(i, &cpuSet)) |
| 129 | + mask.set(i); |
| 130 | + } |
| 131 | + } |
| 132 | + |
| 133 | + return mask; |
| 134 | + } |
| 135 | + |
| 136 | + uint32_t getCurrentThreadId() |
| 137 | + { |
| 138 | + uint64_t result; |
| 139 | + pthread_threadid_np(NULL, &result); |
| 140 | + return (uint32_t) result; |
| 141 | + } |
| 142 | + |
| 143 | + void setThreadName(const std::string& name) |
| 144 | + { |
| 145 | + pthread_setname_np(name.c_str()); |
| 146 | + } |
| 147 | + |
| 148 | +} // namespace ThreadHelper |
| 149 | +} // namespace Disruptor |
| 150 | + |
| 151 | +#endif // DISRUPTOR_OS_FAMILY_UNIX |
0 commit comments