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 16 PThreadEvent::PThreadEvent() : fConditionFlag(false) { 17 pthread_cond_init(&fCondition, nullptr); 18 pthread_mutex_init(&fConditionMutex, nullptr); 19 } 20 PThreadEvent::~PThreadEvent() { 21 pthread_mutex_destroy(&fConditionMutex); 22 pthread_cond_destroy(&fCondition); 23 } 24 void PThreadEvent::trigger() { 25 pthread_mutex_lock(&fConditionMutex); 26 fConditionFlag = true; 27 pthread_cond_signal(&fCondition); 28 pthread_mutex_unlock(&fConditionMutex); 29 } 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 } 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 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 55 SkThread_PThreadData::~SkThread_PThreadData() { 56 pthread_attr_destroy(&fAttr); 57 } 58 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 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 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 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 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