Signed-off-by: falkTX <falktx@falktx.com>tags/v2.5.0
| @@ -1311,13 +1311,13 @@ protected: | |||
| */ | |||
| friend class CarlaEngineEventPort; | |||
| friend class CarlaEngineOsc; | |||
| friend class CarlaEngineThread; | |||
| friend class CarlaEngineRunner; | |||
| friend class CarlaPluginInstance; | |||
| friend class EngineInternalGraph; | |||
| friend class PendingRtEventsRunner; | |||
| friend class ScopedActionLock; | |||
| friend class ScopedEngineEnvironmentLocker; | |||
| friend class ScopedThreadStopper; | |||
| friend class ScopedRunnerStopper; | |||
| friend class PatchbayGraph; | |||
| friend struct ExternalGraph; | |||
| friend struct RackGraph; | |||
| @@ -854,7 +854,7 @@ bool CarlaEngine::addPlugin(const BinaryType btype, | |||
| { | |||
| CARLA_SAFE_ASSERT(! pData->loadingProject); | |||
| const ScopedThreadStopper sts(this); | |||
| const ScopedRunnerStopper srs(this); | |||
| if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) | |||
| pData->graph.replacePlugin(oldPlugin, plugin); | |||
| @@ -925,7 +925,7 @@ bool CarlaEngine::removePlugin(const uint id) | |||
| CARLA_SAFE_ASSERT_RETURN_ERR(plugin.get() != nullptr, "Could not find plugin to remove"); | |||
| CARLA_SAFE_ASSERT_RETURN_ERR(plugin->getId() == id, "Invalid engine internal data"); | |||
| const ScopedThreadStopper sts(this); | |||
| const ScopedRunnerStopper srs(this); | |||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||
| if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) | |||
| @@ -967,7 +967,7 @@ bool CarlaEngine::removeAllPlugins() | |||
| if (pData->curPluginCount == 0) | |||
| return true; | |||
| const ScopedThreadStopper sts(this); | |||
| const ScopedRunnerStopper srs(this); | |||
| const uint curPluginCount = pData->curPluginCount; | |||
| @@ -1112,7 +1112,7 @@ bool CarlaEngine::switchPlugins(const uint idA, const uint idB) noexcept | |||
| CARLA_SAFE_ASSERT_RETURN_ERR(pluginA->getId() == idA, "Invalid engine internal data"); | |||
| CARLA_SAFE_ASSERT_RETURN_ERR(pluginB->getId() == idB, "Invalid engine internal data"); | |||
| const ScopedThreadStopper sts(this); | |||
| const ScopedRunnerStopper srs(this); | |||
| if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) | |||
| pData->graph.switchPlugins(pluginA, pluginB); | |||
| @@ -377,7 +377,7 @@ EngineEvent* CarlaEngine::getInternalEventBuffer(const bool isInput) const noexc | |||
| // CarlaEngine::ProtectedData | |||
| CarlaEngine::ProtectedData::ProtectedData(CarlaEngine* const engine) | |||
| : thread(engine), | |||
| : runner(engine), | |||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||
| osc(engine), | |||
| #endif | |||
| @@ -511,7 +511,7 @@ bool CarlaEngine::ProtectedData::init(const char* const clientName) | |||
| #endif | |||
| nextAction.clearAndReset(); | |||
| thread.startThread(); | |||
| runner.start(); | |||
| return true; | |||
| } | |||
| @@ -526,7 +526,7 @@ void CarlaEngine::ProtectedData::close() | |||
| aboutToClose = true; | |||
| thread.stopThread(500); | |||
| runner.stop(); | |||
| nextAction.clearAndReset(); | |||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||
| @@ -840,19 +840,19 @@ ScopedActionLock::~ScopedActionLock() noexcept | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // ScopedThreadStopper | |||
| // ScopedRunnerStopper | |||
| ScopedThreadStopper::ScopedThreadStopper(CarlaEngine* const e) noexcept | |||
| ScopedRunnerStopper::ScopedRunnerStopper(CarlaEngine* const e) noexcept | |||
| : engine(e), | |||
| pData(e->pData) | |||
| { | |||
| pData->thread.stopThread(500); | |||
| pData->runner.stop(); | |||
| } | |||
| ScopedThreadStopper::~ScopedThreadStopper() noexcept | |||
| ScopedRunnerStopper::~ScopedRunnerStopper() noexcept | |||
| { | |||
| if (engine->isRunning() && ! pData->aboutToClose) | |||
| pData->thread.startThread(); | |||
| pData->runner.start(); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| @@ -18,7 +18,7 @@ | |||
| #ifndef CARLA_ENGINE_INTERNAL_HPP_INCLUDED | |||
| #define CARLA_ENGINE_INTERNAL_HPP_INCLUDED | |||
| #include "CarlaEngineThread.hpp" | |||
| #include "CarlaEngineRunner.hpp" | |||
| #include "CarlaEngineUtils.hpp" | |||
| #include "CarlaPlugin.hpp" | |||
| #include "LinkedList.hpp" | |||
| @@ -244,7 +244,7 @@ struct EnginePluginData { | |||
| // CarlaEngineProtectedData | |||
| struct CarlaEngine::ProtectedData { | |||
| CarlaEngineThread thread; | |||
| CarlaEngineRunner runner; | |||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||
| CarlaEngineOsc osc; | |||
| @@ -268,7 +268,7 @@ struct CarlaEngine::ProtectedData { | |||
| uint32_t bufferSize; | |||
| double sampleRate; | |||
| bool aboutToClose; // don't re-activate thread if true | |||
| bool aboutToClose; // don't re-activate runner if true | |||
| int isIdling; // don't allow any operations while idling | |||
| uint curPluginCount; // number of plugins loaded (0...max) | |||
| uint maxPluginNumber; // number of plugins allowed (0, 16, 99 or 255) | |||
| @@ -362,18 +362,18 @@ private: | |||
| // ----------------------------------------------------------------------- | |||
| class ScopedThreadStopper | |||
| class ScopedRunnerStopper | |||
| { | |||
| public: | |||
| ScopedThreadStopper(CarlaEngine* engine) noexcept; | |||
| ~ScopedThreadStopper() noexcept; | |||
| ScopedRunnerStopper(CarlaEngine* engine) noexcept; | |||
| ~ScopedRunnerStopper() noexcept; | |||
| private: | |||
| CarlaEngine* const engine; | |||
| CarlaEngine::ProtectedData* const pData; | |||
| CARLA_PREVENT_HEAP_ALLOCATION | |||
| CARLA_DECLARE_NON_COPYABLE(ScopedThreadStopper) | |||
| CARLA_DECLARE_NON_COPYABLE(ScopedRunnerStopper) | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| @@ -1520,8 +1520,8 @@ protected: | |||
| } | |||
| // stopped during removeAllPlugins() | |||
| if (! pData->thread.isThreadRunning()) | |||
| pData->thread.startThread(); | |||
| if (! pData->runner.isRunnerActive()) | |||
| pData->runner.start(); | |||
| fOptionsForced = true; | |||
| const String state(data); | |||
| @@ -0,0 +1,170 @@ | |||
| /* | |||
| * Carla Plugin Host | |||
| * Copyright (C) 2011-2022 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * 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 doc/GPL.txt file. | |||
| */ | |||
| #include "CarlaEngineRunner.hpp" | |||
| #include "CarlaEngineInternal.hpp" | |||
| #include "CarlaPlugin.hpp" | |||
| #include "water/misc/Time.h" | |||
| CARLA_BACKEND_START_NAMESPACE | |||
| // ----------------------------------------------------------------------- | |||
| CarlaEngineRunner::CarlaEngineRunner(CarlaEngine* const engine) noexcept | |||
| : CarlaRunner("CarlaEngineRunner"), | |||
| kEngine(engine), | |||
| fIsAlwaysRunning(false), | |||
| fIsPlugin(false) | |||
| { | |||
| CARLA_SAFE_ASSERT(engine != nullptr); | |||
| carla_debug("CarlaEngineRunner::CarlaEngineRunner(%p)", engine); | |||
| } | |||
| CarlaEngineRunner::~CarlaEngineRunner() noexcept | |||
| { | |||
| carla_debug("CarlaEngineRunner::~CarlaEngineRunner()"); | |||
| } | |||
| void CarlaEngineRunner::start() | |||
| { | |||
| carla_debug("CarlaEngineRunner::start()"); | |||
| if (isRunnerActive()) | |||
| stopRunner(); | |||
| fIsPlugin = kEngine->getType() == kEngineTypePlugin; | |||
| fIsAlwaysRunning = kEngine->getType() == kEngineTypeBridge || fIsPlugin; | |||
| startRunner(25); | |||
| } | |||
| void CarlaEngineRunner::stop() | |||
| { | |||
| carla_debug("CarlaEngineRunner::stop()"); | |||
| stopRunner(); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| bool CarlaEngineRunner::run() noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(kEngine != nullptr, false); | |||
| float value; | |||
| #if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE) | |||
| // int64_t lastPingTime = 0; | |||
| const CarlaEngineOsc& engineOsc(kEngine->pData->osc); | |||
| #endif | |||
| // runner must do something... | |||
| CARLA_SAFE_ASSERT_RETURN(fIsAlwaysRunning || kEngine->isRunning(), false); | |||
| #if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE) | |||
| const bool oscRegistedForUDP = engineOsc.isControlRegisteredForUDP(); | |||
| #else | |||
| const bool oscRegistedForUDP = false; | |||
| #endif | |||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||
| if (kIsPlugin) | |||
| engineOsc.idle(); | |||
| #endif | |||
| for (uint i=0, count = kEngine->getCurrentPluginCount(); i < count; ++i) | |||
| { | |||
| const CarlaPluginPtr plugin = kEngine->getPluginUnchecked(i); | |||
| CARLA_SAFE_ASSERT_CONTINUE(plugin.get() != nullptr && plugin->isEnabled()); | |||
| CARLA_SAFE_ASSERT_UINT2(i == plugin->getId(), i, plugin->getId()); | |||
| const uint hints = plugin->getHints(); | |||
| const bool updateUI = (hints & PLUGIN_HAS_CUSTOM_UI) != 0 && (hints & PLUGIN_NEEDS_UI_MAIN_THREAD) == 0; | |||
| // ----------------------------------------------------------- | |||
| // DSP Idle | |||
| try { | |||
| plugin->idle(); | |||
| } CARLA_SAFE_EXCEPTION("idle()") | |||
| // ----------------------------------------------------------- | |||
| // Post-poned events | |||
| if (oscRegistedForUDP || updateUI) | |||
| { | |||
| // ------------------------------------------------------- | |||
| // Update parameter outputs | |||
| for (uint32_t j=0, pcount=plugin->getParameterCount(); j < pcount; ++j) | |||
| { | |||
| if (! plugin->isParameterOutput(j)) | |||
| continue; | |||
| value = plugin->getParameterValue(j); | |||
| #if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE) | |||
| // Update OSC engine client | |||
| if (oscRegistedForUDP) | |||
| engineOsc.sendParameterValue(i, j, value); | |||
| #endif | |||
| // Update UI | |||
| if (updateUI) | |||
| plugin->uiParameterChange(j, value); | |||
| } | |||
| if (updateUI) | |||
| { | |||
| try { | |||
| plugin->uiIdle(); | |||
| } CARLA_SAFE_EXCEPTION("uiIdle()") | |||
| } | |||
| } | |||
| #if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE) | |||
| // ----------------------------------------------------------- | |||
| // Update OSC control client peaks | |||
| if (oscRegistedForUDP) | |||
| engineOsc.sendPeaks(i, kEngine->getPeaks(i)); | |||
| #endif | |||
| } | |||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||
| if (oscRegistedForUDP) | |||
| engineOsc.sendRuntimeInfo(); | |||
| /* | |||
| if (engineOsc.isControlRegisteredForTCP()) | |||
| { | |||
| const int64_t timeNow = water::Time::currentTimeMillis(); | |||
| if (timeNow - lastPingTime > 1000) | |||
| { | |||
| engineOsc.sendPing(); | |||
| lastPingTime = timeNow; | |||
| } | |||
| } | |||
| */ | |||
| #endif | |||
| return true; | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| CARLA_BACKEND_END_NAMESPACE | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * Carla Plugin Host | |||
| * Copyright (C) 2011-2014 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2011-2022 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU General Public License as | |||
| @@ -19,28 +19,34 @@ | |||
| #define CARLA_ENGINE_THREAD_HPP_INCLUDED | |||
| #include "CarlaBackend.h" | |||
| #include "CarlaThread.hpp" | |||
| #include "CarlaRunner.hpp" | |||
| #include "CarlaJuceUtils.hpp" | |||
| CARLA_BACKEND_START_NAMESPACE | |||
| // ----------------------------------------------------------------------- | |||
| // CarlaEngineThread | |||
| // CarlaEngineRunner | |||
| class CarlaEngineThread : public CarlaThread | |||
| class CarlaEngineRunner : public CarlaRunner | |||
| { | |||
| public: | |||
| CarlaEngineThread(CarlaEngine* engine) noexcept; | |||
| ~CarlaEngineThread() noexcept override; | |||
| CarlaEngineRunner(CarlaEngine* engine) noexcept; | |||
| ~CarlaEngineRunner() noexcept override; | |||
| void start(); | |||
| void stop(); | |||
| protected: | |||
| void run() noexcept override; | |||
| bool run() noexcept override; | |||
| private: | |||
| CarlaEngine* const kEngine; | |||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineThread) | |||
| bool fIsAlwaysRunning; | |||
| bool fIsPlugin; | |||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineRunner) | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| @@ -1,159 +0,0 @@ | |||
| /* | |||
| * Carla Plugin Host | |||
| * Copyright (C) 2011-2020 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * 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 doc/GPL.txt file. | |||
| */ | |||
| #include "CarlaEngineThread.hpp" | |||
| #include "CarlaEngineInternal.hpp" | |||
| #include "CarlaPlugin.hpp" | |||
| #include "water/misc/Time.h" | |||
| CARLA_BACKEND_START_NAMESPACE | |||
| // ----------------------------------------------------------------------- | |||
| CarlaEngineThread::CarlaEngineThread(CarlaEngine* const engine) noexcept | |||
| : CarlaThread("CarlaEngineThread"), | |||
| kEngine(engine) | |||
| { | |||
| CARLA_SAFE_ASSERT(engine != nullptr); | |||
| carla_debug("CarlaEngineThread::CarlaEngineThread(%p)", engine); | |||
| } | |||
| CarlaEngineThread::~CarlaEngineThread() noexcept | |||
| { | |||
| carla_debug("CarlaEngineThread::~CarlaEngineThread()"); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| void CarlaEngineThread::run() noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(kEngine != nullptr,); | |||
| carla_debug("CarlaEngineThread::run()"); | |||
| const bool kIsPlugin = kEngine->getType() == kEngineTypePlugin; | |||
| const bool kIsAlwaysRunning = kEngine->getType() == kEngineTypeBridge || kIsPlugin; | |||
| float value; | |||
| #if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE) | |||
| // int64_t lastPingTime = 0; | |||
| const CarlaEngineOsc& engineOsc(kEngine->pData->osc); | |||
| #endif | |||
| // thread must do something... | |||
| CARLA_SAFE_ASSERT_RETURN(kIsAlwaysRunning || kEngine->isRunning(),); | |||
| for (; (kIsAlwaysRunning || kEngine->isRunning()) && ! shouldThreadExit();) | |||
| { | |||
| #if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE) | |||
| const bool oscRegistedForUDP = engineOsc.isControlRegisteredForUDP(); | |||
| #else | |||
| const bool oscRegistedForUDP = false; | |||
| #endif | |||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||
| if (kIsPlugin) | |||
| engineOsc.idle(); | |||
| #endif | |||
| for (uint i=0, count = kEngine->getCurrentPluginCount(); i < count; ++i) | |||
| { | |||
| const CarlaPluginPtr plugin = kEngine->getPluginUnchecked(i); | |||
| CARLA_SAFE_ASSERT_CONTINUE(plugin.get() != nullptr && plugin->isEnabled()); | |||
| CARLA_SAFE_ASSERT_UINT2(i == plugin->getId(), i, plugin->getId()); | |||
| const uint hints(plugin->getHints()); | |||
| const bool updateUI((hints & PLUGIN_HAS_CUSTOM_UI) != 0 && (hints & PLUGIN_NEEDS_UI_MAIN_THREAD) == 0); | |||
| // ----------------------------------------------------------- | |||
| // DSP Idle | |||
| try { | |||
| plugin->idle(); | |||
| } CARLA_SAFE_EXCEPTION("idle()") | |||
| // ----------------------------------------------------------- | |||
| // Post-poned events | |||
| if (oscRegistedForUDP || updateUI) | |||
| { | |||
| // ------------------------------------------------------- | |||
| // Update parameter outputs | |||
| for (uint32_t j=0, pcount=plugin->getParameterCount(); j < pcount; ++j) | |||
| { | |||
| if (! plugin->isParameterOutput(j)) | |||
| continue; | |||
| value = plugin->getParameterValue(j); | |||
| #if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE) | |||
| // Update OSC engine client | |||
| if (oscRegistedForUDP) | |||
| engineOsc.sendParameterValue(i, j, value); | |||
| #endif | |||
| // Update UI | |||
| if (updateUI) | |||
| plugin->uiParameterChange(j, value); | |||
| } | |||
| if (updateUI) | |||
| { | |||
| try { | |||
| plugin->uiIdle(); | |||
| } CARLA_SAFE_EXCEPTION("uiIdle()") | |||
| } | |||
| } | |||
| #if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE) | |||
| // ----------------------------------------------------------- | |||
| // Update OSC control client peaks | |||
| if (oscRegistedForUDP) | |||
| engineOsc.sendPeaks(i, kEngine->getPeaks(i)); | |||
| #endif | |||
| } | |||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||
| if (oscRegistedForUDP) | |||
| engineOsc.sendRuntimeInfo(); | |||
| /* | |||
| if (engineOsc.isControlRegisteredForTCP()) | |||
| { | |||
| const int64_t timeNow = water::Time::currentTimeMillis(); | |||
| if (timeNow - lastPingTime > 1000) | |||
| { | |||
| engineOsc.sendPing(); | |||
| lastPingTime = timeNow; | |||
| } | |||
| } | |||
| */ | |||
| #endif | |||
| carla_msleep(25); | |||
| } | |||
| carla_debug("CarlaEngineThread closed"); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| CARLA_BACKEND_END_NAMESPACE | |||
| @@ -38,7 +38,7 @@ OBJS = \ | |||
| $(OBJDIR)/CarlaEngineGraph.cpp.o \ | |||
| $(OBJDIR)/CarlaEngineInternal.cpp.o \ | |||
| $(OBJDIR)/CarlaEnginePorts.cpp.o \ | |||
| $(OBJDIR)/CarlaEngineThread.cpp.o | |||
| $(OBJDIR)/CarlaEngineRunner.cpp.o | |||
| ifeq ($(HAVE_LIBLO),true) | |||
| OBJS += \ | |||
| @@ -0,0 +1,227 @@ | |||
| /* | |||
| * Carla Runner | |||
| * Copyright (C) 2022 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| * permission notice appear in all copies. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||
| * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||
| * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||
| * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| */ | |||
| #ifndef CARLA_RUNNER_HPP_INCLUDED | |||
| #define CARLA_RUNNER_HPP_INCLUDED | |||
| #include "CarlaUtils.hpp" | |||
| #ifndef CARLA_OS_WASM | |||
| # include "CarlaThread.hpp" | |||
| #else | |||
| # include "CarlaString.hpp" | |||
| # include <emscripten/emscripten.h> | |||
| #endif | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| // CarlaRunner class | |||
| /** | |||
| This is a handy class that handles "idle" time in either background or main thread, | |||
| whichever is more suitable to the target platform. | |||
| Typically background threads on desktop platforms, main thread on web. | |||
| A single function is expected to be implemented by subclasses, | |||
| which directly allows it to stop the runner by returning false. | |||
| You can use it for quick operations that do not need to be handled in the main thread if possible. | |||
| The target is to spread out execution over many runs, instead of spending a lot of time on a single task. | |||
| */ | |||
| class CarlaRunner | |||
| { | |||
| protected: | |||
| /* | |||
| * Constructor. | |||
| */ | |||
| CarlaRunner(const char* const runnerName = nullptr) noexcept | |||
| #ifndef CARLA_OS_WASM | |||
| : fRunnerThread(runnerName), | |||
| #else | |||
| : fRunnerName(runnerName), | |||
| fShouldStop(false), | |||
| #endif | |||
| fTimeInterval(0) {} | |||
| /* | |||
| * Destructor. | |||
| */ | |||
| virtual ~CarlaRunner() /*noexcept*/ | |||
| { | |||
| CARLA_SAFE_ASSERT(! isRunnerActive()); | |||
| stopRunner(); | |||
| } | |||
| /* | |||
| * Virtual function to be implemented by the subclass. | |||
| * Return true to keep running, false to stop execution. | |||
| */ | |||
| virtual bool run() = 0; | |||
| /* | |||
| * Check if the runner should stop. | |||
| * To be called from inside the runner to know if a stop request has been made. | |||
| */ | |||
| bool shouldRunnerStop() const noexcept | |||
| { | |||
| #ifndef CARLA_OS_WASM | |||
| return fRunnerThread.shouldThreadExit(); | |||
| #else | |||
| return fShouldStop; | |||
| #endif | |||
| } | |||
| // --------------------------------------------------------------------------------------------------------------- | |||
| public: | |||
| /* | |||
| * Check if the runner is active. | |||
| */ | |||
| bool isRunnerActive() noexcept | |||
| { | |||
| #ifndef CARLA_OS_WASM | |||
| return fRunnerThread.isThreadRunning(); | |||
| #else | |||
| fShouldStop = false; | |||
| return true; | |||
| #endif | |||
| } | |||
| /* | |||
| * Start the thread. | |||
| */ | |||
| bool startRunner(const uint timeIntervalMilliseconds = 0) noexcept | |||
| { | |||
| fTimeInterval = timeIntervalMilliseconds; | |||
| #ifndef CARLA_OS_WASM | |||
| return fRunnerThread.startThread(); | |||
| #else | |||
| fShouldStop = false; | |||
| emscripten_async_call(_entryPoint, this, timeIntervalMilliseconds); | |||
| return true; | |||
| #endif | |||
| } | |||
| /* | |||
| * Stop the runner. | |||
| * This will signal the runner to stop if active, and wait until it finishes. | |||
| */ | |||
| bool stopRunner() noexcept | |||
| { | |||
| #ifndef CARLA_OS_WASM | |||
| return fRunnerThread.stopThread(); | |||
| #else | |||
| fShouldStop = true; | |||
| return true; | |||
| #endif | |||
| } | |||
| /* | |||
| * Tell the runner to stop as soon as possible. | |||
| */ | |||
| void signalRunnerShouldStop() noexcept | |||
| { | |||
| #ifndef CARLA_OS_WASM | |||
| fRunnerThread.signalThreadShouldExit(); | |||
| #else | |||
| fShouldStop = true; | |||
| #endif | |||
| } | |||
| // --------------------------------------------------------------------------------------------------------------- | |||
| /* | |||
| * Returns the name of the runner. | |||
| * This is the name that gets set in the constructor. | |||
| */ | |||
| const CarlaString& getRunnerName() const noexcept | |||
| { | |||
| #ifndef CARLA_OS_WASM | |||
| return fRunnerThread.getThreadName(); | |||
| #else | |||
| return fRunnerName; | |||
| #endif | |||
| } | |||
| // --------------------------------------------------------------------------------------------------------------- | |||
| private: | |||
| #ifndef CARLA_OS_WASM | |||
| class RunnerThread : private Thread | |||
| { | |||
| Runner* const runner; | |||
| RunnerThread(Runner* const r, const char* const tn, const uint t) | |||
| : Thread(rn), | |||
| runner(r), | |||
| timeInterval(t) {} | |||
| void run() override | |||
| { | |||
| while (!shouldThreadExit()) | |||
| { | |||
| bool stillRunning = false; | |||
| try { | |||
| stillRunning = run(); | |||
| } catch(...) {} | |||
| if (stillRunning && !shouldThreadExit()) | |||
| { | |||
| if (timeInterval != 0) | |||
| d_msleep(timeInterval) | |||
| pthread_yield(); | |||
| continue; | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| } fRunnerThread; | |||
| #else | |||
| const CarlaString fRunnerName; | |||
| volatile bool fShouldStop; | |||
| void _runEntryPoint() noexcept | |||
| { | |||
| if (fShouldStop) | |||
| return; | |||
| bool stillRunning = false; | |||
| try { | |||
| stillRunning = run(); | |||
| } catch(...) {} | |||
| if (stillRunning && !fShouldStop) | |||
| emscripten_async_call(_entryPoint, this, fTimeInterval); | |||
| } | |||
| static void _entryPoint(void* const userData) noexcept | |||
| { | |||
| static_cast<CarlaRunner*>(userData)->_runEntryPoint(); | |||
| } | |||
| #endif | |||
| uint fTimeInterval; | |||
| CARLA_DECLARE_NON_COPYABLE(CarlaRunner) | |||
| }; | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| #endif // CARLA_RUNNER_HPP_INCLUDED | |||