180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/*
280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Copyright 2012 Google Inc.
380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru *
480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Use of this source code is governed by a BSD-style license that can be
580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * found in the LICENSE file.
680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru */
780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkTypes.h"
980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkThreadUtils.h"
1180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkThreadUtils_pthread.h"
1280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include <pthread.h>
1480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include <signal.h>
1580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruPThreadEvent::PThreadEvent() : fConditionFlag(false) {
1780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    pthread_cond_init(&fCondition, NULL);
1880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    pthread_mutex_init(&fConditionMutex, NULL);
1980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
2080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruPThreadEvent::~PThreadEvent() {
2180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    pthread_mutex_destroy(&fConditionMutex);
2280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    pthread_cond_destroy(&fCondition);
2380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
2480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid PThreadEvent::trigger() {
2580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    pthread_mutex_lock(&fConditionMutex);
2680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fConditionFlag = true;
2780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    pthread_cond_signal(&fCondition);
2880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    pthread_mutex_unlock(&fConditionMutex);
2980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
3080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid PThreadEvent::wait() {
3180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    pthread_mutex_lock(&fConditionMutex);
3280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    while (!fConditionFlag) {
3380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        pthread_cond_wait(&fCondition, &fConditionMutex);
3480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
3580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    pthread_mutex_unlock(&fConditionMutex);
3680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
3780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querubool PThreadEvent::isTriggered() {
3880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    bool currentFlag;
3980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    pthread_mutex_lock(&fConditionMutex);
4080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    currentFlag = fConditionFlag;
4180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    pthread_mutex_unlock(&fConditionMutex);
4280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return currentFlag;
4380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
4480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
4580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkThread_PThreadData::SkThread_PThreadData(SkThread::entryPointProc entryPoint, void* data)
4680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    : fPThread()
4780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    , fValidPThread(false)
4880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    , fParam(data)
4980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    , fEntryPoint(entryPoint)
5080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru{
5180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    pthread_attr_init(&fAttr);
5280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    pthread_attr_setdetachstate(&fAttr, PTHREAD_CREATE_JOINABLE);
5380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
5480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
5580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkThread_PThreadData::~SkThread_PThreadData() {
5680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    pthread_attr_destroy(&fAttr);
5780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
5880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
5980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic void* thread_start(void* arg) {
6080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(arg);
6180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // Wait for start signal
6280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    pthreadData->fStarted.wait();
6380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
6480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // Call entry point only if thread was not canceled before starting.
6580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (!pthreadData->fCanceled.isTriggered()) {
6680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        pthreadData->fEntryPoint(pthreadData->fParam);
6780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
6880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return NULL;
6980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
7080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
7180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkThread::SkThread(entryPointProc entryPoint, void* data) {
7280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkThread_PThreadData* pthreadData = new SkThread_PThreadData(entryPoint, data);
7380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fData = pthreadData;
7480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
7580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    int ret = pthread_create(&(pthreadData->fPThread),
7680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                             &(pthreadData->fAttr),
7780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                             thread_start,
7880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                             pthreadData);
7980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
8080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    pthreadData->fValidPThread = (0 == ret);
8180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
8280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
8380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkThread::~SkThread() {
8480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (fData != NULL) {
8580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(fData);
8680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // If created thread but start was never called, kill the thread.
8780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (pthreadData->fValidPThread && !pthreadData->fStarted.isTriggered()) {
8880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            pthreadData->fCanceled.trigger();
8980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            if (this->start()) {
9080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                this->join();
9180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            }
9280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
9380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        delete pthreadData;
9480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
9580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
9680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
9780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querubool SkThread::start() {
9880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(fData);
9980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (!pthreadData->fValidPThread) {
10080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return false;
10180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
10280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
10380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (pthreadData->fStarted.isTriggered()) {
10480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return false;
10580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
10680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    pthreadData->fStarted.trigger();
10780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return true;
10880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
10980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
11080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkThread::join() {
11180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(fData);
11280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (!pthreadData->fValidPThread || !pthreadData->fStarted.isTriggered()) {
11380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return;
11480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
11580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
11680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    pthread_join(pthreadData->fPThread, NULL);
11780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
118