/*
* Copyright 2012 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkTypes.h"
#include "SkThreadUtils.h"
#include "SkThreadUtils_win.h"
SkThread_WinData::SkThread_WinData(SkThread::entryPointProc entryPoint, void* data)
: fHandle(NULL)
, fParam(data)
, fThreadId(0)
, fEntryPoint(entryPoint)
, fStarted(false)
{
fCancelEvent = CreateEvent(
NULL, // default security attributes
false, //auto reset
false, //not signaled
NULL); //no name
}
SkThread_WinData::~SkThread_WinData() {
CloseHandle(fCancelEvent);
}
static DWORD WINAPI thread_start(LPVOID data) {
SkThread_WinData* winData = static_cast<SkThread_WinData*>(data);
//See if this thread was canceled before starting.
if (WaitForSingleObject(winData->fCancelEvent, 0) == WAIT_OBJECT_0) {
return 0;
}
winData->fEntryPoint(winData->fParam);
return 0;
}
SkThread::SkThread(entryPointProc entryPoint, void* data) {
SkThread_WinData* winData = new SkThread_WinData(entryPoint, data);
fData = winData;
if (NULL == winData->fCancelEvent) {
return;
}
winData->fHandle = CreateThread(
NULL, // default security attributes
0, // use default stack size
thread_start, // thread function name (proxy)
winData, // argument to thread function (proxy args)
CREATE_SUSPENDED, // create suspended so affinity can be set
&winData->fThreadId); // returns the thread identifier
}
SkThread::~SkThread() {
if (fData != NULL) {
SkThread_WinData* winData = static_cast<SkThread_WinData*>(fData);
// If created thread but start was never called, kill the thread.
if (winData->fHandle != NULL && !winData->fStarted) {
if (SetEvent(winData->fCancelEvent) != 0) {
if (this->start()) {
this->join();
}
} else {
//kill with prejudice
TerminateThread(winData->fHandle, -1);
}
}
delete winData;
}
}
bool SkThread::start() {
SkThread_WinData* winData = static_cast<SkThread_WinData*>(fData);
if (NULL == winData->fHandle) {
return false;
}
if (winData->fStarted) {
return false;
}
winData->fStarted = -1 != ResumeThread(winData->fHandle);
return winData->fStarted;
}
void SkThread::join() {
SkThread_WinData* winData = static_cast<SkThread_WinData*>(fData);
if (NULL == winData->fHandle || !winData->fStarted) {
return;
}
WaitForSingleObject(winData->fHandle, INFINITE);
}
static unsigned int num_bits_set(DWORD_PTR mask) {
unsigned int count;
for (count = 0; mask; ++count) {
mask &= mask - 1;
}
return count;
}
static unsigned int nth_set_bit(unsigned int n, DWORD_PTR mask) {
n %= num_bits_set(mask);
for (unsigned int setBitsSeen = 0, currentBit = 0; true; ++currentBit) {
if (mask & (static_cast<DWORD_PTR>(1) << currentBit)) {
++setBitsSeen;
if (setBitsSeen > n) {
return currentBit;
}
}
}
}
bool SkThread::setProcessorAffinity(unsigned int processor) {
SkThread_WinData* winData = static_cast<SkThread_WinData*>(fData);
if (NULL == winData->fHandle) {
return false;
}
DWORD_PTR processAffinityMask;
DWORD_PTR systemAffinityMask;
if (0 == GetProcessAffinityMask(GetCurrentProcess(),
&processAffinityMask,
&systemAffinityMask)) {
return false;
}
DWORD_PTR threadAffinityMask = 1 << nth_set_bit(processor, processAffinityMask);
return 0 != SetThreadAffinityMask(winData->fHandle, threadAffinityMask);
}