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 16PThreadEvent::PThreadEvent() : fConditionFlag(false) { 17 pthread_cond_init(&fCondition, NULL); 18 pthread_mutex_init(&fConditionMutex, NULL); 19} 20PThreadEvent::~PThreadEvent() { 21 pthread_mutex_destroy(&fConditionMutex); 22 pthread_cond_destroy(&fCondition); 23} 24void PThreadEvent::trigger() { 25 pthread_mutex_lock(&fConditionMutex); 26 fConditionFlag = true; 27 pthread_cond_signal(&fCondition); 28 pthread_mutex_unlock(&fConditionMutex); 29} 30void PThreadEvent::wait() { 31 pthread_mutex_lock(&fConditionMutex); 32 while (!fConditionFlag) { 33 pthread_cond_wait(&fCondition, &fConditionMutex); 34 } 35 pthread_mutex_unlock(&fConditionMutex); 36} 37bool PThreadEvent::isTriggered() { 38 bool currentFlag; 39 pthread_mutex_lock(&fConditionMutex); 40 currentFlag = fConditionFlag; 41 pthread_mutex_unlock(&fConditionMutex); 42 return currentFlag; 43} 44 45SkThread_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 55SkThread_PThreadData::~SkThread_PThreadData() { 56 pthread_attr_destroy(&fAttr); 57} 58 59static 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 NULL; 69} 70 71SkThread::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 83SkThread::~SkThread() { 84 if (fData != NULL) { 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 97bool 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 110void 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, NULL); 117} 118