#pragma once #include #include #include #ifdef _WIN32 #include #endif namespace sync { #ifdef _WIN32 typedef CRITICAL_SECTION Mutex; typedef CONDITION_VARIABLE ConditionVar; typedef HANDLE Semaphore; typedef HANDLE Thread; typedef LARGE_INTEGER TimeSpan; typedef DWORD (WINAPI *ThreadFunc)(_In_ LPVOID lpParameter); typedef LPVOID ThreadArg; const TimeSpan infinite_ts = { .QuadPart = LLONG_MAX }; int get_num_cores() { SYSTEM_INFO sysinfo; GetSystemInfo(&sysinfo); return sysinfo.dwNumberOfProcessors; } const int num_cores = get_num_cores(); LARGE_INTEGER _init_freq() { LARGE_INTEGER freq; QueryPerformanceFrequency(&freq); return freq; } static LARGE_INTEGER freq = _init_freq(); #endif Thread make_thread(ThreadFunc t, ThreadArg a); Thread make_thread(ThreadFunc t, ThreadArg a, int core_affinity); void join(Thread t); void sleep(TimeSpan ts); void allow_all_processors(); void set_affinity(Thread &t, int core); void set_affinity(int core); int get_affinity(); Mutex make_mutex(); void lock(Mutex &m); bool trylock(Mutex &m); void unlock(Mutex &m); void dispose(Mutex &m); ConditionVar make_condition_var(); void wait(ConditionVar &c, Mutex &m, TimeSpan ts); void wake_one(ConditionVar &c); void wake_all(ConditionVar &c); void dispose(ConditionVar &c); Semaphore make_semaphore(int initial, int max); void wait(Semaphore &s); void post(Semaphore &s); void dispose(Semaphore &s); TimeSpan from_ms(double milliseconds); TimeSpan from_s(double seconds); TimeSpan from_min(double minutes); TimeSpan from_hours(double hours); TimeSpan now(); TimeSpan operator-(const TimeSpan &a, const TimeSpan &b); TimeSpan operator+(const TimeSpan &a, const TimeSpan &b); TimeSpan operator*(const TimeSpan &a, const TimeSpan &b); TimeSpan operator/(const TimeSpan &a, const TimeSpan &b); double to_ms(TimeSpan &ts); double to_s(TimeSpan &ts); double to_min(TimeSpan &ts); double to_hours(TimeSpan &ts); #ifdef _WIN32 uint64_t bitmask (unsigned short n) { if (n == 64) return -((uint64_t)1); return (((uint64_t) 1) << n) - 1; } const int tab64[64] = { 63, 0, 58, 1, 59, 47, 53, 2, 60, 39, 48, 27, 54, 33, 42, 3, 61, 51, 37, 40, 49, 18, 28, 20, 55, 30, 34, 11, 43, 14, 22, 4, 62, 57, 46, 52, 38, 26, 32, 41, 50, 36, 17, 19, 29, 10, 13, 21, 56, 45, 25, 31, 35, 16, 9, 12, 44, 24, 15, 8, 23, 7, 6, 5}; int log2_64 (uint64_t value) { value |= value >> 1; value |= value >> 2; value |= value >> 4; value |= value >> 8; value |= value >> 16; value |= value >> 32; return tab64[((uint64_t)((value - (value >> 1))*0x07EDD5E59A4E28C2)) >> 58]; } Thread make_thread(ThreadFunc f, ThreadArg a) { DWORD tid; return CreateThread(NULL, 0, f, a, 0, &tid); } struct DummyThreadArgs { int core_affinity; ThreadFunc f; ThreadArg a; }; DWORD _dummy_thread(LPVOID a) { DummyThreadArgs *wrap = static_cast(a); set_affinity(wrap->core_affinity); return wrap->f(wrap->a); } Thread make_thread(ThreadFunc f, ThreadArg a, int core_affinity) { DWORD tid; DummyThreadArgs *args = (DummyThreadArgs*)malloc(sizeof(DummyThreadArgs)); *args = { .core_affinity=core_affinity, .f=f, .a=a }; return CreateThread(NULL, 0, _dummy_thread, args, 0, &tid); } void join(Thread t) { WaitForSingleObject(t, INFINITE); } void sleep(TimeSpan ts) { Sleep(static_cast(to_ms(ts))); } void allow_all_processors() { Thread t = GetCurrentThread(); DWORD affinity = bitmask(num_cores); SetProcessAffinityMask(t, affinity); } void set_affinity(Thread &t, int core) { DWORD mask = 1 << (core % num_cores); DWORD old = SetThreadAffinityMask(t, mask); DWORD confirm = SetThreadAffinityMask(t, mask); assert(old && GetLastError() != ERROR_INVALID_PARAMETER && mask == confirm); } void set_affinity(int core) { Thread cur = GetCurrentThread(); set_affinity(cur, core); } int get_affinity() { Thread t = GetCurrentThread(); DWORD mask = 1; DWORD affinity = SetThreadAffinityMask(t, (DWORD_PTR)mask); DWORD check = SetThreadAffinityMask(t, (DWORD_PTR)affinity); assert(check == mask); return log2_64(affinity); } Mutex make_mutex() { Mutex m; InitializeCriticalSection(&m); return m; } void lock(Mutex &m) { EnterCriticalSection(&m); } bool trylock(Mutex &m) { return TryEnterCriticalSection(&m); } void unlock(Mutex &m) { LeaveCriticalSection(&m); } void dispose(Mutex &m) { DeleteCriticalSection(&m); } ConditionVar make_condition_var() { ConditionVar c; InitializeConditionVariable(&c); return c; } void wait(ConditionVar &c, Mutex &m, TimeSpan ts) { if (ts.QuadPart == infinite_ts.QuadPart) { SleepConditionVariableCS(&c, &m, INFINITE); } else { SleepConditionVariableCS(&c, &m, static_cast(to_ms(ts))); } } void wake_one(ConditionVar &c) { WakeConditionVariable(&c); } void wake_all(ConditionVar &c) { WakeAllConditionVariable(&c); } void dispose(ConditionVar &c) { return; // Windows doesn't have a delete condition variable func } Semaphore make_semaphore(int initial, int max) { return CreateSemaphoreA(NULL, (long)initial, (long)max, NULL); } void wait(Semaphore &s) { WaitForSingleObject(s, INFINITE); } void post(Semaphore &s) { ReleaseSemaphore(s, 1, NULL); } void dispose(Semaphore &s) { CloseHandle(s); } TimeSpan from_ms(double milliseconds) { TimeSpan ts; ts.QuadPart = static_cast(milliseconds/1000.0)*freq.QuadPart; return ts; } TimeSpan from_s(double seconds) { TimeSpan ts; ts.QuadPart = static_cast(seconds)*freq.QuadPart; return ts; } TimeSpan from_min(double minutes) { TimeSpan ts; ts.QuadPart = static_cast(minutes*60.0)*freq.QuadPart; return ts; } TimeSpan from_hours(double hours) { TimeSpan ts; ts.QuadPart = static_cast(hours*60.0*60.0)*freq.QuadPart; return ts; } TimeSpan now() { TimeSpan ts; QueryPerformanceCounter(&ts); return ts; } TimeSpan operator-(const TimeSpan &a, const TimeSpan &b) { TimeSpan ts; ts.QuadPart = a.QuadPart - b.QuadPart; return ts; } TimeSpan operator+(const TimeSpan &a, const TimeSpan &b) { TimeSpan ts; ts.QuadPart = a.QuadPart + b.QuadPart; return ts; } TimeSpan operator*(const TimeSpan &a, const TimeSpan &b) { TimeSpan ts; ts.QuadPart = a.QuadPart * b.QuadPart; return ts; } TimeSpan operator/(const TimeSpan &a, const TimeSpan &b) { TimeSpan ts; ts.QuadPart = a.QuadPart / b.QuadPart; return ts; } double to_ms(TimeSpan &ts) { return static_cast(ts.QuadPart*1000)/static_cast(freq.QuadPart); } double to_s(TimeSpan &ts) { return static_cast(ts.QuadPart)/static_cast(freq.QuadPart); } double to_min(TimeSpan &ts) { return static_cast(ts.QuadPart)/static_cast(freq.QuadPart*60); } double to_hours(TimeSpan &ts) { return static_cast(ts.QuadPart)/static_cast(freq.QuadPart*60*60); } #endif } // namespace sync //