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