16#if defined(_WIN32) && BT_THREADSAFE
28 int numLogicalProcessors;
34 int numPhysicalPackages;
35 static const int maxNumTeamMasks = 32;
37 UINT64 processorTeamMasks[maxNumTeamMasks];
40UINT64 getProcessorTeamMask(
const btProcessorInfo& procInfo,
int procId)
42 UINT64 procMask = UINT64(1) << procId;
43 for (
int i = 0; i < procInfo.numTeamMasks; ++i)
45 if (procMask & procInfo.processorTeamMasks[i])
47 return procInfo.processorTeamMasks[i];
53int getProcessorTeamIndex(
const btProcessorInfo& procInfo,
int procId)
55 UINT64 procMask = UINT64(1) << procId;
56 for (
int i = 0; i < procInfo.numTeamMasks; ++i)
58 if (procMask & procInfo.processorTeamMasks[i])
66int countSetBits(ULONG64 bits)
80typedef BOOL(WINAPI* Pfn_GetLogicalProcessorInformation)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);
82void getProcessorInformation(btProcessorInfo* procInfo)
84 memset(procInfo, 0,
sizeof(*procInfo));
85#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
89 Pfn_GetLogicalProcessorInformation getLogicalProcInfo =
90 (Pfn_GetLogicalProcessorInformation)GetProcAddress(GetModuleHandle(TEXT(
"kernel32")),
"GetLogicalProcessorInformation");
91 if (getLogicalProcInfo == NULL)
96 PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buf = NULL;
100 if (getLogicalProcInfo(buf, &bufSize))
106 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
112 buf = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc(bufSize);
117 int len = bufSize /
sizeof(*buf);
118 for (
int i = 0; i < len; ++i)
120 PSYSTEM_LOGICAL_PROCESSOR_INFORMATION info = buf + i;
121 switch (info->Relationship)
123 case RelationNumaNode:
124 procInfo->numNumaNodes++;
127 case RelationProcessorCore:
128 procInfo->numCores++;
129 procInfo->numLogicalProcessors += countSetBits(info->ProcessorMask);
133 if (info->Cache.Level == 1)
135 procInfo->numL1Cache++;
137 else if (info->Cache.Level == 2)
139 procInfo->numL2Cache++;
141 else if (info->Cache.Level == 3)
143 procInfo->numL3Cache++;
153 if (procInfo->numTeamMasks < btProcessorInfo::maxNumTeamMasks)
155 procInfo->processorTeamMasks[procInfo->numTeamMasks] = info->ProcessorMask;
156 procInfo->numTeamMasks++;
161 case RelationProcessorPackage:
162 procInfo->numPhysicalPackages++;
174 struct btThreadStatus
180 ThreadFunc m_userThreadFunc;
183 void* m_threadHandle;
185 void* m_eventStartHandle;
186 char m_eventStartHandleName[32];
188 void* m_eventCompleteHandle;
189 char m_eventCompleteHandleName[32];
196 DWORD_PTR m_startedThreadMask;
197 btProcessorInfo m_processorInfo;
199 void startThreads(
const ConstructionInfo& threadInfo);
201 int waitForResponse();
204 btThreadSupportWin32(
const ConstructionInfo& threadConstructionInfo);
205 virtual ~btThreadSupportWin32();
218btThreadSupportWin32::btThreadSupportWin32(const ConstructionInfo& threadConstructionInfo)
220 startThreads(threadConstructionInfo);
223btThreadSupportWin32::~btThreadSupportWin32()
228DWORD WINAPI win32threadStartFunc(LPVOID lpParam)
230 btThreadSupportWin32::btThreadStatus* status = (btThreadSupportWin32::btThreadStatus*)lpParam;
234 WaitForSingleObject(status->m_eventStartHandle, INFINITE);
235 void* userPtr = status->m_userPtr;
240 status->m_userThreadFunc(userPtr);
241 status->m_status = 2;
242 SetEvent(status->m_eventCompleteHandle);
247 status->m_status = 3;
248 printf(
"Thread with taskId %i with handle %p exiting\n", status->m_taskId, status->m_threadHandle);
249 SetEvent(status->m_eventCompleteHandle);
253 printf(
"Thread TERMINATED\n");
257void btThreadSupportWin32::runTask(
int threadIndex,
void* userData)
259 btThreadStatus& threadStatus = m_activeThreadStatus[threadIndex];
261 btAssert(
int(threadIndex) < m_activeThreadStatus.
size());
263 threadStatus.m_commandId = 1;
264 threadStatus.m_status = 1;
265 threadStatus.m_userPtr = userData;
266 m_startedThreadMask |= DWORD_PTR(1) << threadIndex;
269 SetEvent(threadStatus.m_eventStartHandle);
272int btThreadSupportWin32::waitForResponse()
277 DWORD res = WaitForMultipleObjects(m_completeHandles.
size(), &m_completeHandles[0], FALSE, INFINITE);
279 last = res - WAIT_OBJECT_0;
281 btThreadStatus& threadStatus = m_activeThreadStatus[last];
282 btAssert(threadStatus.m_threadHandle);
283 btAssert(threadStatus.m_eventCompleteHandle);
286 btAssert(threadStatus.m_status > 1);
287 threadStatus.m_status = 0;
291 m_startedThreadMask &= ~(DWORD_PTR(1) << last);
296void btThreadSupportWin32::waitForAllTasks()
298 while (m_startedThreadMask)
304void btThreadSupportWin32::startThreads(
const ConstructionInfo& threadConstructionInfo)
308 btProcessorInfo& procInfo = m_processorInfo;
309 getProcessorInformation(&procInfo);
310 DWORD_PTR dwProcessAffinityMask = 0;
311 DWORD_PTR dwSystemAffinityMask = 0;
312 if (!GetProcessAffinityMask(GetCurrentProcess(), &dwProcessAffinityMask, &dwSystemAffinityMask))
314 dwProcessAffinityMask = 0;
319 m_activeThreadStatus.
resize(m_numThreads);
320 m_completeHandles.
resize(m_numThreads);
321 m_startedThreadMask = 0;
324 if (DWORD_PTR mask = dwProcessAffinityMask & getProcessorTeamMask(procInfo, 0))
326 SetThreadAffinityMask(GetCurrentThread(), mask);
327 SetThreadIdealProcessor(GetCurrentThread(), 0);
330 for (
int i = 0; i < m_numThreads; i++)
332 printf(
"starting thread %d\n", i);
334 btThreadStatus& threadStatus = m_activeThreadStatus[i];
336 LPSECURITY_ATTRIBUTES lpThreadAttributes = NULL;
337 SIZE_T dwStackSize = threadConstructionInfo.m_threadStackSize;
338 LPTHREAD_START_ROUTINE lpStartAddress = &win32threadStartFunc;
339 LPVOID lpParameter = &threadStatus;
340 DWORD dwCreationFlags = 0;
341 LPDWORD lpThreadId = 0;
343 threadStatus.m_userPtr = 0;
345 sprintf(threadStatus.m_eventStartHandleName,
"es%.8s%d%d", threadConstructionInfo.m_uniqueName,
uniqueId, i);
346 threadStatus.m_eventStartHandle = CreateEventA(0,
false,
false, threadStatus.m_eventStartHandleName);
348 sprintf(threadStatus.m_eventCompleteHandleName,
"ec%.8s%d%d", threadConstructionInfo.m_uniqueName,
uniqueId, i);
349 threadStatus.m_eventCompleteHandle = CreateEventA(0,
false,
false, threadStatus.m_eventCompleteHandleName);
351 m_completeHandles[i] = threadStatus.m_eventCompleteHandle;
353 HANDLE handle = CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId);
361 int processorId = i + 1;
362 DWORD_PTR teamMask = getProcessorTeamMask(procInfo, processorId);
369 DWORD_PTR mask = teamMask & dwProcessAffinityMask;
372 SetThreadAffinityMask(handle, mask);
375 SetThreadIdealProcessor(handle, processorId);
378 threadStatus.m_taskId = i;
379 threadStatus.m_commandId = 0;
380 threadStatus.m_status = 0;
381 threadStatus.m_threadHandle = handle;
382 threadStatus.m_userThreadFunc = threadConstructionInfo.m_userThreadFunc;
384 printf(
"started %s thread %d with threadHandle %p\n", threadConstructionInfo.m_uniqueName, i, handle);
389void btThreadSupportWin32::stopThreads()
391 for (
int i = 0; i < m_activeThreadStatus.
size(); i++)
393 btThreadStatus& threadStatus = m_activeThreadStatus[i];
394 if (threadStatus.m_status > 0)
396 WaitForSingleObject(threadStatus.m_eventCompleteHandle, INFINITE);
399 threadStatus.m_userPtr = NULL;
400 SetEvent(threadStatus.m_eventStartHandle);
401 WaitForSingleObject(threadStatus.m_eventCompleteHandle, INFINITE);
403 CloseHandle(threadStatus.m_eventCompleteHandle);
404 CloseHandle(threadStatus.m_eventStartHandle);
405 CloseHandle(threadStatus.m_threadHandle);
408 m_activeThreadStatus.
clear();
409 m_completeHandles.
clear();
415 CRITICAL_SECTION mCriticalSection;
418 btWin32CriticalSection()
420 InitializeCriticalSection(&mCriticalSection);
423 ~btWin32CriticalSection()
425 DeleteCriticalSection(&mCriticalSection);
430 EnterCriticalSection(&mCriticalSection);
435 LeaveCriticalSection(&mCriticalSection);
441 unsigned char* mem = (
unsigned char*)
btAlignedAlloc(
sizeof(btWin32CriticalSection), 16);
442 btWin32CriticalSection* cs =
new (mem) btWin32CriticalSection();
446void btThreadSupportWin32::deleteCriticalSection(
btCriticalSection* criticalSection)
454 return new btThreadSupportWin32(info);
#define btAlignedFree(ptr)
#define btAlignedAlloc(size, alignment)
const T & btMin(const T &a, const T &b)
const unsigned int BT_MAX_THREAD_COUNT
The btAlignedObjectArray template class uses a subset of the stl::vector interface for its methods It...
int size() const
return the number of elements in the array
void resize(int newsize, const T &fillData=T())
void clear()
clear the array, deallocated memory. Generally it is better to use array.resize(0),...
virtual ~btCriticalSection()
virtual int getCacheFriendlyNumThreads() const =0
virtual int getLogicalToPhysicalCoreRatio() const =0
virtual void waitForAllTasks()=0
static btThreadSupportInterface * create(const ConstructionInfo &info)
virtual void runTask(int threadIndex, void *userData)=0
virtual int getNumWorkerThreads() const =0