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