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