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 
SkThread_WinData(SkThread::entryPointProc entryPoint,void * data)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 
~SkThread_WinData()27 SkThread_WinData::~SkThread_WinData() {
28     CloseHandle(fCancelEvent);
29 }
30 
thread_start(LPVOID data)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 
SkThread(entryPointProc entryPoint,void * data)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 
~SkThread()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 
start()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 
join()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 
num_bits_set(DWORD_PTR mask)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 
nth_set_bit(unsigned int n,DWORD_PTR mask)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 
setProcessorAffinity(unsigned int processor)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