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