/* * Carla common utils * Copyright (C) 2011-2013 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * For a full copy of the GNU General Public License see the GPL.txt file */ #ifndef __CARLA_THREAD_HPP__ #define __CARLA_THREAD_HPP__ #include "CarlaJuceUtils.hpp" // #define CPP11_THREAD #ifdef CPP11_THREAD # include #else # include #endif // ------------------------------------------------- // CarlaThread class class CarlaThread { public: CarlaThread() : fStarted(false), fFinished(false) { #ifdef CPP11_THREAD cthread = nullptr; #else _zero(); pthread_attr_init(&pthreadAttr); pthread_attr_setdetachstate(&pthreadAttr, PTHREAD_CREATE_JOINABLE); #endif } ~CarlaThread() { CARLA_ASSERT(! isRunning()); if (isRunning()) terminate(); #ifdef CPP11_THREAD if (cthread != nullptr) { cthread->join(); delete cthread; } #else if (! _isNull()) pthread_join(pthreadId, nullptr); pthread_attr_destroy(&pthreadAttr); #endif } bool start() { CARLA_ASSERT(! isRunning()); if (isRunning()) return false; fStarted = false; fFinished = false; #ifdef CPP11_THREAD CARLA_ASSERT(cthread == nullptr); if (cthread != nullptr) return false; cthread = new std::thread(_cthreadRoutine, this); CARLA_ASSERT(cthread->joinable()); return true; #else CARLA_ASSERT(_isNull()); if (! _isNull()) return false; return (pthread_create(&pthreadId, &pthreadAttr, _pthreadRoutine, this) == 0); #endif } bool stop(const unsigned int timeout = 0) { CARLA_ASSERT(isRunning()); if (! isRunning()) return true; #ifdef CPP11_THREAD if (cthread == nullptr) return true; #else if (_isNull()) return true; #endif if (timeout == 0) { #ifdef CPP11_THREAD cthread->join(); #else pthread_join(pthreadId, nullptr); #endif } else { for (unsigned int i=0; i < timeout && ! fFinished; i++) carla_msleep(1); } if (! fFinished) return false; #ifdef CPP11_THREAD delete cthread; cthread = nullptr; #else _zero(); #endif return true; } void terminate() { CARLA_ASSERT(isRunning()); if (fFinished) return; #ifdef CPP11_THREAD if (cthread == nullptr) return; #else if (_isNull()) return; #endif #ifdef CPP11_THREAD cthread->detach(); //cthread->join(); delete cthread; cthread = nullptr; #else pthread_detach(pthreadId); //pthread_join(pthreadId, nullptr); pthread_cancel(pthreadId); _zero(); #endif fFinished = true; } bool isRunning() { if (fStarted && ! fFinished) return true; // take the change to clear data #ifdef CPP11_THREAD if (cthread != nullptr) { cthread->join(); delete cthread; cthread = nullptr; } #else if (! _isNull()) { pthread_join(pthreadId, nullptr); _zero(); } #endif return false; } void waitForStarted(const unsigned int timeout = 0) // ms { if (fStarted) return; if (timeout == 0) { while (! fStarted) {} } else { for (unsigned int i=0; i < timeout && ! fStarted; i++) carla_msleep(1); } } void waitForFinished() { waitForStarted(); stop(0); } protected: virtual void run() = 0; private: bool fStarted; bool fFinished; void handleRoutine() { fStarted = true; run(); fFinished = true; } #ifdef CPP11_THREAD std::thread* cthread; static void _cthreadRoutine(CarlaThread* const _this_) { _this_->handleRoutine(); } #else pthread_t pthreadId; pthread_attr_t pthreadAttr; static void* _pthreadRoutine(void* const _this_) { ((CarlaThread*)_this_)->handleRoutine(); pthread_exit(nullptr); return nullptr; } bool _isNull() { #ifdef CARLA_OS_WIN return (pthreadId.p == nullptr); #else return (pthreadId == 0); #endif } void _zero() { carla_zeroStruct(pthreadId); } #endif CARLA_PREVENT_HEAP_ALLOCATION CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaThread) }; // ------------------------------------------------- #endif // __CARLA_THREAD_HPP__