| /*------------------------------------------------------------------------- |
| * drawElements Thread Library |
| * --------------------------- |
| * |
| * Copyright 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| *//*! |
| * \file |
| * \brief Win32 implementation of thread management. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "deThread.h" |
| |
| #if (DE_OS == DE_OS_WIN32 || DE_OS == DE_OS_WINCE) |
| |
| #include "deMemory.h" |
| #include "deInt32.h" |
| |
| #define VC_EXTRALEAN |
| #define WIN32_LEAN_AND_MEAN |
| #include <windows.h> |
| |
| /* Thread handle equals deThread in this implementation. */ |
| DE_STATIC_ASSERT(sizeof(deThread) >= sizeof(HANDLE)); |
| |
| typedef struct ThreadEntry_s |
| { |
| deThreadFunc func; |
| void* arg; |
| } ThreadEntry; |
| |
| static int mapPriority (deThreadPriority priority) |
| { |
| switch (priority) |
| { |
| case DE_THREADPRIORITY_LOWEST: return THREAD_PRIORITY_IDLE; |
| case DE_THREADPRIORITY_LOW: return THREAD_PRIORITY_LOWEST; |
| case DE_THREADPRIORITY_NORMAL: return THREAD_PRIORITY_NORMAL; |
| case DE_THREADPRIORITY_HIGH: return THREAD_PRIORITY_ABOVE_NORMAL; |
| case DE_THREADPRIORITY_HIGHEST: return THREAD_PRIORITY_HIGHEST; |
| default: DE_ASSERT(DE_FALSE); |
| } |
| return 0; |
| } |
| |
| static DWORD __stdcall startThread (LPVOID entryPtr) |
| { |
| ThreadEntry* entry = (ThreadEntry*)entryPtr; |
| deThreadFunc func = entry->func; |
| void* arg = entry->arg; |
| |
| deFree(entry); |
| |
| func(arg); |
| |
| return 0; |
| } |
| |
| deThread deThread_create (deThreadFunc func, void* arg, const deThreadAttributes* attributes) |
| { |
| ThreadEntry* entry = (ThreadEntry*)deMalloc(sizeof(ThreadEntry)); |
| HANDLE thread = 0; |
| |
| if (!entry) |
| return 0; |
| |
| entry->func = func; |
| entry->arg = arg; |
| |
| thread = CreateThread(DE_NULL, 0, startThread, entry, 0, DE_NULL); |
| if (!thread) |
| { |
| deFree(entry); |
| return 0; |
| } |
| |
| if (attributes) |
| SetThreadPriority(thread, mapPriority(attributes->priority)); |
| |
| return (deThread)thread; |
| } |
| |
| deBool deThread_join (deThread thread) |
| { |
| HANDLE handle = (HANDLE)thread; |
| WaitForSingleObject(handle, INFINITE); |
| |
| return DE_TRUE; |
| } |
| |
| void deThread_destroy (deThread thread) |
| { |
| HANDLE handle = (HANDLE)thread; |
| CloseHandle(handle); |
| } |
| |
| void deSleep (deUint32 milliseconds) |
| { |
| Sleep((DWORD)milliseconds); |
| } |
| |
| void deYield (void) |
| { |
| SwitchToThread(); |
| } |
| |
| static SYSTEM_LOGICAL_PROCESSOR_INFORMATION* getWin32ProcessorInfo (deUint32* numBytes) |
| { |
| deUint32 curSize = (deUint32)sizeof(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)*8; |
| SYSTEM_LOGICAL_PROCESSOR_INFORMATION* info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION*)deMalloc(curSize); |
| |
| for (;;) |
| { |
| DWORD inOutLen = curSize; |
| DWORD err; |
| |
| if (GetLogicalProcessorInformation(info, &inOutLen)) |
| { |
| *numBytes = inOutLen; |
| return info; |
| } |
| else |
| { |
| err = GetLastError(); |
| |
| if (err == ERROR_INSUFFICIENT_BUFFER) |
| { |
| curSize <<= 1; |
| info = deRealloc(info, curSize); |
| } |
| else |
| { |
| deFree(info); |
| return DE_NULL; |
| } |
| } |
| } |
| } |
| |
| typedef struct ProcessorInfo_s |
| { |
| deUint32 numPhysicalCores; |
| deUint32 numLogicalCores; |
| } ProcessorInfo; |
| |
| void parseWin32ProcessorInfo (ProcessorInfo* dst, const SYSTEM_LOGICAL_PROCESSOR_INFORMATION* src, deUint32 numBytes) |
| { |
| const SYSTEM_LOGICAL_PROCESSOR_INFORMATION* cur = src; |
| |
| deMemset(dst, 0, sizeof(ProcessorInfo)); |
| |
| while (((const deUint8*)cur - (const deUint8*)src) + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= numBytes) |
| { |
| if (cur->Relationship == RelationProcessorCore) |
| { |
| dst->numPhysicalCores += 1; |
| #if (DE_PTR_SIZE == 8) |
| dst->numLogicalCores += dePop64(cur->ProcessorMask); |
| #else |
| dst->numLogicalCores += dePop32(cur->ProcessorMask); |
| #endif |
| } |
| |
| cur++; |
| } |
| } |
| |
| deBool getProcessorInfo (ProcessorInfo* info) |
| { |
| deUint32 numBytes = 0; |
| SYSTEM_LOGICAL_PROCESSOR_INFORMATION* rawInfo = getWin32ProcessorInfo(&numBytes); |
| |
| if (!numBytes) |
| return DE_FALSE; |
| |
| parseWin32ProcessorInfo(info, rawInfo, numBytes); |
| deFree(rawInfo); |
| |
| return DE_TRUE; |
| } |
| |
| deUint32 deGetNumTotalPhysicalCores (void) |
| { |
| ProcessorInfo info; |
| |
| if (!getProcessorInfo(&info)) |
| return 1u; |
| |
| return info.numPhysicalCores; |
| } |
| |
| deUint32 deGetNumTotalLogicalCores (void) |
| { |
| ProcessorInfo info; |
| |
| if (!getProcessorInfo(&info)) |
| return 1u; |
| |
| return info.numLogicalCores; |
| } |
| |
| deUint32 deGetNumAvailableLogicalCores (void) |
| { |
| return deGetNumTotalLogicalCores(); |
| } |
| |
| #endif /* DE_OS */ |