michael@0: /* michael@0: * Copyright 2012 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: #include "SkTypes.h" michael@0: michael@0: #include "SkThreadUtils.h" michael@0: #include "SkThreadUtils_pthread.h" michael@0: michael@0: #include michael@0: #include michael@0: michael@0: PThreadEvent::PThreadEvent() : fConditionFlag(false) { michael@0: pthread_cond_init(&fCondition, NULL); michael@0: pthread_mutex_init(&fConditionMutex, NULL); michael@0: } michael@0: PThreadEvent::~PThreadEvent() { michael@0: pthread_mutex_destroy(&fConditionMutex); michael@0: pthread_cond_destroy(&fCondition); michael@0: } michael@0: void PThreadEvent::trigger() { michael@0: pthread_mutex_lock(&fConditionMutex); michael@0: fConditionFlag = true; michael@0: pthread_cond_signal(&fCondition); michael@0: pthread_mutex_unlock(&fConditionMutex); michael@0: } michael@0: void PThreadEvent::wait() { michael@0: pthread_mutex_lock(&fConditionMutex); michael@0: while (!fConditionFlag) { michael@0: pthread_cond_wait(&fCondition, &fConditionMutex); michael@0: } michael@0: pthread_mutex_unlock(&fConditionMutex); michael@0: } michael@0: bool PThreadEvent::isTriggered() { michael@0: bool currentFlag; michael@0: pthread_mutex_lock(&fConditionMutex); michael@0: currentFlag = fConditionFlag; michael@0: pthread_mutex_unlock(&fConditionMutex); michael@0: return currentFlag; michael@0: } michael@0: michael@0: SkThread_PThreadData::SkThread_PThreadData(SkThread::entryPointProc entryPoint, void* data) michael@0: : fPThread() michael@0: , fValidPThread(false) michael@0: , fParam(data) michael@0: , fEntryPoint(entryPoint) michael@0: { michael@0: pthread_attr_init(&fAttr); michael@0: pthread_attr_setdetachstate(&fAttr, PTHREAD_CREATE_JOINABLE); michael@0: } michael@0: michael@0: SkThread_PThreadData::~SkThread_PThreadData() { michael@0: pthread_attr_destroy(&fAttr); michael@0: } michael@0: michael@0: static void* thread_start(void* arg) { michael@0: SkThread_PThreadData* pthreadData = static_cast(arg); michael@0: // Wait for start signal michael@0: pthreadData->fStarted.wait(); michael@0: michael@0: // Call entry point only if thread was not canceled before starting. michael@0: if (!pthreadData->fCanceled.isTriggered()) { michael@0: pthreadData->fEntryPoint(pthreadData->fParam); michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: SkThread::SkThread(entryPointProc entryPoint, void* data) { michael@0: SkThread_PThreadData* pthreadData = new SkThread_PThreadData(entryPoint, data); michael@0: fData = pthreadData; michael@0: michael@0: int ret = pthread_create(&(pthreadData->fPThread), michael@0: &(pthreadData->fAttr), michael@0: thread_start, michael@0: pthreadData); michael@0: michael@0: pthreadData->fValidPThread = (0 == ret); michael@0: } michael@0: michael@0: SkThread::~SkThread() { michael@0: if (fData != NULL) { michael@0: SkThread_PThreadData* pthreadData = static_cast(fData); michael@0: // If created thread but start was never called, kill the thread. michael@0: if (pthreadData->fValidPThread && !pthreadData->fStarted.isTriggered()) { michael@0: pthreadData->fCanceled.trigger(); michael@0: if (this->start()) { michael@0: this->join(); michael@0: } michael@0: } michael@0: delete pthreadData; michael@0: } michael@0: } michael@0: michael@0: bool SkThread::start() { michael@0: SkThread_PThreadData* pthreadData = static_cast(fData); michael@0: if (!pthreadData->fValidPThread) { michael@0: return false; michael@0: } michael@0: michael@0: if (pthreadData->fStarted.isTriggered()) { michael@0: return false; michael@0: } michael@0: pthreadData->fStarted.trigger(); michael@0: return true; michael@0: } michael@0: michael@0: void SkThread::join() { michael@0: SkThread_PThreadData* pthreadData = static_cast(fData); michael@0: if (!pthreadData->fValidPThread || !pthreadData->fStarted.isTriggered()) { michael@0: return; michael@0: } michael@0: michael@0: pthread_join(pthreadData->fPThread, NULL); michael@0: }