/*-------------------------------------------------------------------------
* 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 */