180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/*
280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Copyright 2012 Google Inc.
380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru *
480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Use of this source code is governed by a BSD-style license that can be
580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * found in the LICENSE file.
680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru */
780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkTypes.h"
980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkThreadUtils.h"
1180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkThreadUtils_win.h"
1280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkThread_WinData::SkThread_WinData(SkThread::entryPointProc entryPoint, void* data)
1480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    : fHandle(NULL)
1580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    , fParam(data)
1680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    , fThreadId(0)
1780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    , fEntryPoint(entryPoint)
1880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    , fStarted(false)
1980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru{
2080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fCancelEvent = CreateEvent(
2180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        NULL,  // default security attributes
2280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        false, //auto reset
2380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        false, //not signaled
2480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        NULL); //no name
2580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
2680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
2780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkThread_WinData::~SkThread_WinData() {
2880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    CloseHandle(fCancelEvent);
2980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
3080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
3180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic DWORD WINAPI thread_start(LPVOID data) {
3280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkThread_WinData* winData = static_cast<SkThread_WinData*>(data);
3380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
3480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    //See if this thread was canceled before starting.
3580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (WaitForSingleObject(winData->fCancelEvent, 0) == WAIT_OBJECT_0) {
3680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return 0;
3780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
3880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
3980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    winData->fEntryPoint(winData->fParam);
4080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return 0;
4180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
4280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
4380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkThread::SkThread(entryPointProc entryPoint, void* data) {
4480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkThread_WinData* winData = new SkThread_WinData(entryPoint, data);
4580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fData = winData;
4680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
4780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (NULL == winData->fCancelEvent) {
4880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return;
4980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
5080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
5180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    winData->fHandle = CreateThread(
5280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        NULL,                   // default security attributes
5380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        0,                      // use default stack size
5480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        thread_start,           // thread function name (proxy)
5580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        winData,                // argument to thread function (proxy args)
5680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        CREATE_SUSPENDED,       // create suspended so affinity can be set
5780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        &winData->fThreadId);   // returns the thread identifier
5880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
5980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
6080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkThread::~SkThread() {
6180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (fData != NULL) {
6280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkThread_WinData* winData = static_cast<SkThread_WinData*>(fData);
6380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // If created thread but start was never called, kill the thread.
6480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (winData->fHandle != NULL && !winData->fStarted) {
6580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            if (SetEvent(winData->fCancelEvent) != 0) {
6680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                if (this->start()) {
6780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    this->join();
6880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                }
6980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            } else {
7080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                //kill with prejudice
7180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                TerminateThread(winData->fHandle, -1);
7280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            }
7380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
7480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        delete winData;
7580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
7680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
7780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
7880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querubool SkThread::start() {
7980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkThread_WinData* winData = static_cast<SkThread_WinData*>(fData);
8080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (NULL == winData->fHandle) {
8180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return false;
8280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
8380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
8480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (winData->fStarted) {
8580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return false;
8680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
8780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    winData->fStarted = -1 != ResumeThread(winData->fHandle);
8880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return winData->fStarted;
8980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
9080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
9180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkThread::join() {
9280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkThread_WinData* winData = static_cast<SkThread_WinData*>(fData);
9380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (NULL == winData->fHandle || !winData->fStarted) {
9480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return;
9580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
9680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
9780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    WaitForSingleObject(winData->fHandle, INFINITE);
9880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
9980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
10080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic unsigned int num_bits_set(DWORD_PTR mask) {
10180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    unsigned int count;
10280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    for (count = 0; mask; ++count) {
10380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        mask &= mask - 1;
10480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
10580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return count;
10680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
10780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
10880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic unsigned int nth_set_bit(unsigned int n, DWORD_PTR mask) {
10980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    n %= num_bits_set(mask);
11080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    for (unsigned int setBitsSeen = 0, currentBit = 0; true; ++currentBit) {
11180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (mask & (1 << currentBit)) {
11280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            ++setBitsSeen;
11380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            if (setBitsSeen > n) {
11480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                return currentBit;
11580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            }
11680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
11780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
11880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
11980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
12080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querubool SkThread::setProcessorAffinity(unsigned int processor) {
12180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkThread_WinData* winData = static_cast<SkThread_WinData*>(fData);
12280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (NULL == winData->fHandle) {
12380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return false;
12480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
12580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
12680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    DWORD_PTR processAffinityMask;
12780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    DWORD_PTR systemAffinityMask;
12880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (0 == GetProcessAffinityMask(GetCurrentProcess(),
12980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                    &processAffinityMask,
13080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                    &systemAffinityMask)) {
13180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return false;
13280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
13380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
13480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    DWORD_PTR threadAffinityMask = 1 << nth_set_bit(processor, processAffinityMask);
13580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return 0 != SetThreadAffinityMask(winData->fHandle, threadAffinityMask);
13680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
137