• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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