blob: 17a2075ab048bb644172bfe87e27d8e269f2692d [file] [log] [blame]
/*
* 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);
}