Home | History | Annotate | Download | only in utils
      1 /*
      2  * Copyright 2012 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkTypes.h"
      9 
     10 #include "SkThreadUtils.h"
     11 #include "SkThreadUtils_pthread.h"
     12 
     13 #include <pthread.h>
     14 #include <signal.h>
     15 
     16 PThreadEvent::PThreadEvent() : fConditionFlag(false) {
     17     pthread_cond_init(&fCondition, NULL);
     18     pthread_mutex_init(&fConditionMutex, NULL);
     19 }
     20 PThreadEvent::~PThreadEvent() {
     21     pthread_mutex_destroy(&fConditionMutex);
     22     pthread_cond_destroy(&fCondition);
     23 }
     24 void PThreadEvent::trigger() {
     25     pthread_mutex_lock(&fConditionMutex);
     26     fConditionFlag = true;
     27     pthread_cond_signal(&fCondition);
     28     pthread_mutex_unlock(&fConditionMutex);
     29 }
     30 void PThreadEvent::wait() {
     31     pthread_mutex_lock(&fConditionMutex);
     32     while (!fConditionFlag) {
     33         pthread_cond_wait(&fCondition, &fConditionMutex);
     34     }
     35     pthread_mutex_unlock(&fConditionMutex);
     36 }
     37 bool PThreadEvent::isTriggered() {
     38     bool currentFlag;
     39     pthread_mutex_lock(&fConditionMutex);
     40     currentFlag = fConditionFlag;
     41     pthread_mutex_unlock(&fConditionMutex);
     42     return currentFlag;
     43 }
     44 
     45 SkThread_PThreadData::SkThread_PThreadData(SkThread::entryPointProc entryPoint, void* data)
     46     : fPThread()
     47     , fValidPThread(false)
     48     , fParam(data)
     49     , fEntryPoint(entryPoint)
     50 {
     51     pthread_attr_init(&fAttr);
     52     pthread_attr_setdetachstate(&fAttr, PTHREAD_CREATE_JOINABLE);
     53 }
     54 
     55 SkThread_PThreadData::~SkThread_PThreadData() {
     56     pthread_attr_destroy(&fAttr);
     57 }
     58 
     59 static void* thread_start(void* arg) {
     60     SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(arg);
     61     // Wait for start signal
     62     pthreadData->fStarted.wait();
     63 
     64     // Call entry point only if thread was not canceled before starting.
     65     if (!pthreadData->fCanceled.isTriggered()) {
     66         pthreadData->fEntryPoint(pthreadData->fParam);
     67     }
     68     return NULL;
     69 }
     70 
     71 SkThread::SkThread(entryPointProc entryPoint, void* data) {
     72     SkThread_PThreadData* pthreadData = new SkThread_PThreadData(entryPoint, data);
     73     fData = pthreadData;
     74 
     75     int ret = pthread_create(&(pthreadData->fPThread),
     76                              &(pthreadData->fAttr),
     77                              thread_start,
     78                              pthreadData);
     79 
     80     pthreadData->fValidPThread = (0 == ret);
     81 }
     82 
     83 SkThread::~SkThread() {
     84     if (fData != NULL) {
     85         SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(fData);
     86         // If created thread but start was never called, kill the thread.
     87         if (pthreadData->fValidPThread && !pthreadData->fStarted.isTriggered()) {
     88             pthreadData->fCanceled.trigger();
     89             if (this->start()) {
     90                 this->join();
     91             }
     92         }
     93         delete pthreadData;
     94     }
     95 }
     96 
     97 bool SkThread::start() {
     98     SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(fData);
     99     if (!pthreadData->fValidPThread) {
    100         return false;
    101     }
    102 
    103     if (pthreadData->fStarted.isTriggered()) {
    104         return false;
    105     }
    106     pthreadData->fStarted.trigger();
    107     return true;
    108 }
    109 
    110 void SkThread::join() {
    111     SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(fData);
    112     if (!pthreadData->fValidPThread || !pthreadData->fStarted.isTriggered()) {
    113         return;
    114     }
    115 
    116     pthread_join(pthreadData->fPThread, NULL);
    117 }
    118