| /* |
| * 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> |
| |
| SkThread_PThreadData::SkThread_PThreadData(SkThread::entryPointProc entryPoint, void* data) |
| : fPThread() |
| , fValidPThread(false) |
| , fParam(data) |
| , fEntryPoint(entryPoint) |
| , fStarted(false) |
| { |
| pthread_mutex_init(&fStartMutex, NULL); |
| |
| pthread_cond_init(&fStartCondition, NULL); |
| |
| pthread_attr_init(&fAttr); |
| pthread_attr_setdetachstate(&fAttr, PTHREAD_CREATE_JOINABLE); |
| } |
| SkThread_PThreadData::~SkThread_PThreadData() { |
| pthread_attr_destroy(&fAttr); |
| pthread_cond_destroy(&fStartCondition); |
| pthread_mutex_destroy(&fStartMutex); |
| } |
| |
| static void* thread_start(void* arg) { |
| SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(arg); |
| //Wait for start signal |
| pthread_mutex_lock(&(pthreadData->fStartMutex)); |
| while (!pthreadData->fStarted) { |
| pthread_cond_wait(&(pthreadData->fStartCondition), &(pthreadData->fStartMutex)); |
| } |
| pthread_mutex_unlock(&(pthreadData->fStartMutex)); |
| |
| //See if this thread was canceled before starting. |
| pthread_testcancel(); |
| |
| pthreadData->fEntryPoint(pthreadData->fParam); |
| return NULL; |
| } |
| |
| 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 != NULL) { |
| SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(fData); |
| // If created thread but start was never called, kill the thread. |
| if (pthreadData->fValidPThread && !pthreadData->fStarted) { |
| if (pthread_cancel(pthreadData->fPThread) == 0) { |
| if (this->start()) { |
| this->join(); |
| } |
| } else { |
| //kill with prejudice |
| pthread_kill(pthreadData->fPThread, SIGKILL); |
| } |
| } |
| delete pthreadData; |
| } |
| } |
| |
| bool SkThread::start() { |
| SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(fData); |
| if (!pthreadData->fValidPThread) { |
| return false; |
| } |
| |
| if (pthreadData->fStarted) { |
| return false; |
| } |
| pthreadData->fStarted = true; |
| pthread_mutex_lock(&(pthreadData->fStartMutex)); |
| pthread_cond_signal(&(pthreadData->fStartCondition)); |
| pthread_mutex_unlock(&(pthreadData->fStartMutex)); |
| return true; |
| } |
| |
| void SkThread::join() { |
| SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(fData); |
| if (!pthreadData->fValidPThread || !pthreadData->fStarted) { |
| return; |
| } |
| |
| pthread_join(pthreadData->fPThread, NULL); |
| } |