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_pthread.h"
12
13 #include <pthread.h>
14 #include <signal.h>
15
PThreadEvent()16 PThreadEvent::PThreadEvent() : fConditionFlag(false) {
17 pthread_cond_init(&fCondition, nullptr);
18 pthread_mutex_init(&fConditionMutex, nullptr);
19 }
~PThreadEvent()20 PThreadEvent::~PThreadEvent() {
21 pthread_mutex_destroy(&fConditionMutex);
22 pthread_cond_destroy(&fCondition);
23 }
trigger()24 void PThreadEvent::trigger() {
25 pthread_mutex_lock(&fConditionMutex);
26 fConditionFlag = true;
27 pthread_cond_signal(&fCondition);
28 pthread_mutex_unlock(&fConditionMutex);
29 }
wait()30 void PThreadEvent::wait() {
31 pthread_mutex_lock(&fConditionMutex);
32 while (!fConditionFlag) {
33 pthread_cond_wait(&fCondition, &fConditionMutex);
34 }
35 pthread_mutex_unlock(&fConditionMutex);
36 }
isTriggered()37 bool PThreadEvent::isTriggered() {
38 bool currentFlag;
39 pthread_mutex_lock(&fConditionMutex);
40 currentFlag = fConditionFlag;
41 pthread_mutex_unlock(&fConditionMutex);
42 return currentFlag;
43 }
44
SkThread_PThreadData(SkThread::entryPointProc entryPoint,void * data)45 SkThread_PThreadData::SkThread_PThreadData(SkThread::entryPointProc entryPoint, void* data)
46 : fPThread()
47 , fValidPThread(false)
48 , fParam(data)
49 , fEntryPoint(entryPoint)
50 {
51 pthread_attr_init(&fAttr);
52 pthread_attr_setdetachstate(&fAttr, PTHREAD_CREATE_JOINABLE);
53 }
54
~SkThread_PThreadData()55 SkThread_PThreadData::~SkThread_PThreadData() {
56 pthread_attr_destroy(&fAttr);
57 }
58
thread_start(void * arg)59 static void* thread_start(void* arg) {
60 SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(arg);
61 // Wait for start signal
62 pthreadData->fStarted.wait();
63
64 // Call entry point only if thread was not canceled before starting.
65 if (!pthreadData->fCanceled.isTriggered()) {
66 pthreadData->fEntryPoint(pthreadData->fParam);
67 }
68 return nullptr;
69 }
70
SkThread(entryPointProc entryPoint,void * data)71 SkThread::SkThread(entryPointProc entryPoint, void* data) {
72 SkThread_PThreadData* pthreadData = new SkThread_PThreadData(entryPoint, data);
73 fData = pthreadData;
74
75 int ret = pthread_create(&(pthreadData->fPThread),
76 &(pthreadData->fAttr),
77 thread_start,
78 pthreadData);
79
80 pthreadData->fValidPThread = (0 == ret);
81 }
82
~SkThread()83 SkThread::~SkThread() {
84 if (fData != nullptr) {
85 SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(fData);
86 // If created thread but start was never called, kill the thread.
87 if (pthreadData->fValidPThread && !pthreadData->fStarted.isTriggered()) {
88 pthreadData->fCanceled.trigger();
89 if (this->start()) {
90 this->join();
91 }
92 }
93 delete pthreadData;
94 }
95 }
96
start()97 bool SkThread::start() {
98 SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(fData);
99 if (!pthreadData->fValidPThread) {
100 return false;
101 }
102
103 if (pthreadData->fStarted.isTriggered()) {
104 return false;
105 }
106 pthreadData->fStarted.trigger();
107 return true;
108 }
109
join()110 void SkThread::join() {
111 SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(fData);
112 if (!pthreadData->fValidPThread || !pthreadData->fStarted.isTriggered()) {
113 return;
114 }
115
116 pthread_join(pthreadData->fPThread, nullptr);
117 }
118