blob: 1b332da9c83b805348353ee99434d62f5eb7bb1e [file] [log] [blame]
/*-------------------------------------------------------------------------
* 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 */