Home | History | Annotate | Download | only in utils
      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