| /* | |
| * 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); | |
| } |