diff --git a/source/utils/carla_utils.hpp b/source/utils/carla_utils.hpp index e41585e2c..95c515f31 100644 --- a/source/utils/carla_utils.hpp +++ b/source/utils/carla_utils.hpp @@ -24,8 +24,11 @@ #include #include +// #define CPP11_MUTEX + #ifdef CPP11_MUTEX # include +# include #else # include #endif @@ -314,6 +317,216 @@ private: CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaMutex) }; +// ------------------------------------------------- +// CarlaThread class + +class CarlaThread +{ +public: + CarlaThread() + : fStarted(false), + fFinished(false) + { +#ifdef CPP11_MUTEX + 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_MUTEX + if (cthread != nullptr) + { + cthread->join(); + delete cthread; + } +#else + if (pthreadId != 0) + pthread_join(pthreadId, nullptr); + + pthread_attr_destroy(&pthreadAttr); +#endif + } + + bool start() + { + CARLA_ASSERT(! isRunning()); + + if (isRunning()) + return false; + + fStarted = false; + fFinished = false; + +#ifdef CPP11_MUTEX + CARLA_ASSERT(cthread == nullptr); + + if (cthread != nullptr) + return false; + + cthread = new std::thread(_cthreadRoutine, this); + CARLA_ASSERT(cthread->joinable()); + + return true; +#else + CARLA_ASSERT(pthreadId == 0); + + if (pthreadId != 0) + 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_MUTEX + if (cthread == nullptr) + return true; +#else + if (pthreadId == 0) + return true; +#endif + + if (timeout == 0) + { +#ifdef CPP11_MUTEX + 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_MUTEX + delete cthread; + cthread = nullptr; +#else + _zero(); +#endif + + return true; + } + + void terminate() + { + CARLA_ASSERT(isRunning()); + + if (fFinished) + return; + +#ifdef CPP11_MUTEX + if (cthread == nullptr) + return; +#else + if (pthreadId == 0) + return; +#endif + +#ifdef CPP11_MUTEX + 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() + { + return (fStarted && ! fFinished); + } + + 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_MUTEX + 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); + } + + void _zero() + { + carla_zeroStruct(pthreadId); + } +#endif + + CARLA_PREVENT_HEAP_ALLOCATION + CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaThread) +}; + // ------------------------------------------------- // CarlaString class