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#if defined(SK_BUILD_FOR_WIN32)
10
11#include "SkThreadUtils.h"
12#include "SkThreadUtils_win.h"
13
14SkThread_WinData::SkThread_WinData(SkThread::entryPointProc entryPoint, void* data)
15    : fHandle(nullptr)
16    , fParam(data)
17    , fThreadId(0)
18    , fEntryPoint(entryPoint)
19    , fStarted(false)
20{
21    fCancelEvent = CreateEvent(
22        nullptr,  // default security attributes
23        false, //auto reset
24        false, //not signaled
25        nullptr); //no name
26}
27
28SkThread_WinData::~SkThread_WinData() {
29    CloseHandle(fCancelEvent);
30}
31
32static DWORD WINAPI thread_start(LPVOID data) {
33    SkThread_WinData* winData = static_cast<SkThread_WinData*>(data);
34
35    //See if this thread was canceled before starting.
36    if (WaitForSingleObject(winData->fCancelEvent, 0) == WAIT_OBJECT_0) {
37        return 0;
38    }
39
40    winData->fEntryPoint(winData->fParam);
41    return 0;
42}
43
44SkThread::SkThread(entryPointProc entryPoint, void* data) {
45    SkThread_WinData* winData = new SkThread_WinData(entryPoint, data);
46    fData = winData;
47
48    if (nullptr == winData->fCancelEvent) {
49        return;
50    }
51
52    winData->fHandle = CreateThread(
53        nullptr,                   // default security attributes
54        0,                      // use default stack size
55        thread_start,           // thread function name (proxy)
56        winData,                // argument to thread function (proxy args)
57        CREATE_SUSPENDED,       // we used to set processor affinity, which needed this
58        &winData->fThreadId);   // returns the thread identifier
59}
60
61SkThread::~SkThread() {
62    if (fData != nullptr) {
63        SkThread_WinData* winData = static_cast<SkThread_WinData*>(fData);
64        // If created thread but start was never called, kill the thread.
65        if (winData->fHandle != nullptr && !winData->fStarted) {
66            if (SetEvent(winData->fCancelEvent) != 0) {
67                if (this->start()) {
68                    this->join();
69                }
70            } else {
71                //kill with prejudice
72                TerminateThread(winData->fHandle, -1);
73            }
74        }
75        delete winData;
76    }
77}
78
79bool SkThread::start() {
80    SkThread_WinData* winData = static_cast<SkThread_WinData*>(fData);
81    if (nullptr == winData->fHandle) {
82        return false;
83    }
84
85    if (winData->fStarted) {
86        return false;
87    }
88    winData->fStarted = -1 != ResumeThread(winData->fHandle);
89    return winData->fStarted;
90}
91
92void SkThread::join() {
93    SkThread_WinData* winData = static_cast<SkThread_WinData*>(fData);
94    if (nullptr == winData->fHandle || !winData->fStarted) {
95        return;
96    }
97
98    WaitForSingleObject(winData->fHandle, INFINITE);
99}
100
101#endif//defined(SK_BUILD_FOR_WIN32)
102