| /*------------------------------------------------------------------------- |
| * 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(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; |
| } |
| |
| bool deThread_join(deThread thread) |
| { |
| HANDLE handle = (HANDLE)thread; |
| WaitForSingleObject(handle, INFINITE); |
| |
| return true; |
| } |
| |
| void deThread_destroy(deThread thread) |
| { |
| HANDLE handle = (HANDLE)thread; |
| CloseHandle(handle); |
| } |
| |
| void deSleep(uint32_t milliseconds) |
| { |
| Sleep((DWORD)milliseconds); |
| } |
| |
| void deYield(void) |
| { |
| SwitchToThread(); |
| } |
| |
| static SYSTEM_LOGICAL_PROCESSOR_INFORMATION *getWin32ProcessorInfo(uint32_t *numBytes) |
| { |
| uint32_t curSize = (uint32_t)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 |
| { |
| uint32_t numPhysicalCores; |
| uint32_t numLogicalCores; |
| } ProcessorInfo; |
| |
| void parseWin32ProcessorInfo(ProcessorInfo *dst, const SYSTEM_LOGICAL_PROCESSOR_INFORMATION *src, uint32_t numBytes) |
| { |
| const SYSTEM_LOGICAL_PROCESSOR_INFORMATION *cur = src; |
| |
| deMemset(dst, 0, sizeof(ProcessorInfo)); |
| |
| while (((const uint8_t *)cur - (const uint8_t *)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++; |
| } |
| } |
| |
| bool getProcessorInfo(ProcessorInfo *info) |
| { |
| uint32_t numBytes = 0; |
| SYSTEM_LOGICAL_PROCESSOR_INFORMATION *rawInfo = getWin32ProcessorInfo(&numBytes); |
| |
| if (!numBytes) |
| return false; |
| |
| parseWin32ProcessorInfo(info, rawInfo, numBytes); |
| deFree(rawInfo); |
| |
| return true; |
| } |
| |
| uint32_t deGetNumTotalPhysicalCores(void) |
| { |
| ProcessorInfo info; |
| |
| if (!getProcessorInfo(&info)) |
| return 1u; |
| |
| return info.numPhysicalCores; |
| } |
| |
| uint32_t deGetNumTotalLogicalCores(void) |
| { |
| ProcessorInfo info; |
| |
| if (!getProcessorInfo(&info)) |
| return 1u; |
| |
| return info.numLogicalCores; |
| } |
| |
| uint32_t deGetNumAvailableLogicalCores(void) |
| { |
| return deGetNumTotalLogicalCores(); |
| } |
| |
| #endif /* DE_OS */ |