1 /* 2 * Copyright 2012 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkTypes.h" 9 10 #include "SkThreadUtils.h" 11 #include "SkThreadUtils_win.h" 12 13 SkThread_WinData::SkThread_WinData(SkThread::entryPointProc entryPoint, void* data) 14 : fHandle(NULL) 15 , fParam(data) 16 , fThreadId(0) 17 , fEntryPoint(entryPoint) 18 , fStarted(false) 19 { 20 fCancelEvent = CreateEvent( 21 NULL, // default security attributes 22 false, //auto reset 23 false, //not signaled 24 NULL); //no name 25 } 26 27 SkThread_WinData::~SkThread_WinData() { 28 CloseHandle(fCancelEvent); 29 } 30 31 static DWORD WINAPI thread_start(LPVOID data) { 32 SkThread_WinData* winData = static_cast<SkThread_WinData*>(data); 33 34 //See if this thread was canceled before starting. 35 if (WaitForSingleObject(winData->fCancelEvent, 0) == WAIT_OBJECT_0) { 36 return 0; 37 } 38 39 winData->fEntryPoint(winData->fParam); 40 return 0; 41 } 42 43 SkThread::SkThread(entryPointProc entryPoint, void* data) { 44 SkThread_WinData* winData = new SkThread_WinData(entryPoint, data); 45 fData = winData; 46 47 if (NULL == winData->fCancelEvent) { 48 return; 49 } 50 51 winData->fHandle = CreateThread( 52 NULL, // default security attributes 53 0, // use default stack size 54 thread_start, // thread function name (proxy) 55 winData, // argument to thread function (proxy args) 56 CREATE_SUSPENDED, // create suspended so affinity can be set 57 &winData->fThreadId); // returns the thread identifier 58 } 59 60 SkThread::~SkThread() { 61 if (fData != NULL) { 62 SkThread_WinData* winData = static_cast<SkThread_WinData*>(fData); 63 // If created thread but start was never called, kill the thread. 64 if (winData->fHandle != NULL && !winData->fStarted) { 65 if (SetEvent(winData->fCancelEvent) != 0) { 66 if (this->start()) { 67 this->join(); 68 } 69 } else { 70 //kill with prejudice 71 TerminateThread(winData->fHandle, -1); 72 } 73 } 74 delete winData; 75 } 76 } 77 78 bool SkThread::start() { 79 SkThread_WinData* winData = static_cast<SkThread_WinData*>(fData); 80 if (NULL == winData->fHandle) { 81 return false; 82 } 83 84 if (winData->fStarted) { 85 return false; 86 } 87 winData->fStarted = -1 != ResumeThread(winData->fHandle); 88 return winData->fStarted; 89 } 90 91 void SkThread::join() { 92 SkThread_WinData* winData = static_cast<SkThread_WinData*>(fData); 93 if (NULL == winData->fHandle || !winData->fStarted) { 94 return; 95 } 96 97 WaitForSingleObject(winData->fHandle, INFINITE); 98 } 99 100 static unsigned int num_bits_set(DWORD_PTR mask) { 101 unsigned int count; 102 for (count = 0; mask; ++count) { 103 mask &= mask - 1; 104 } 105 return count; 106 } 107 108 static unsigned int nth_set_bit(unsigned int n, DWORD_PTR mask) { 109 n %= num_bits_set(mask); 110 for (unsigned int setBitsSeen = 0, currentBit = 0; true; ++currentBit) { 111 if (mask & (static_cast<DWORD_PTR>(1) << currentBit)) { 112 ++setBitsSeen; 113 if (setBitsSeen > n) { 114 return currentBit; 115 } 116 } 117 } 118 } 119 120 bool SkThread::setProcessorAffinity(unsigned int processor) { 121 SkThread_WinData* winData = static_cast<SkThread_WinData*>(fData); 122 if (NULL == winData->fHandle) { 123 return false; 124 } 125 126 DWORD_PTR processAffinityMask; 127 DWORD_PTR systemAffinityMask; 128 if (0 == GetProcessAffinityMask(GetCurrentProcess(), 129 &processAffinityMask, 130 &systemAffinityMask)) { 131 return false; 132 } 133 134 DWORD_PTR threadAffinityMask = 1 << nth_set_bit(processor, processAffinityMask); 135 return 0 != SetThreadAffinityMask(winData->fHandle, threadAffinityMask); 136 } 137