Browse Source

Bring Runner class from DPF, use it for Engine background details

Signed-off-by: falkTX <falktx@falktx.com>
tags/v2.5.0
falkTX 2 years ago
parent
commit
798733e2f1
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
10 changed files with 435 additions and 191 deletions
  1. +2
    -2
      source/backend/CarlaEngine.hpp
  2. +4
    -4
      source/backend/engine/CarlaEngine.cpp
  3. +8
    -8
      source/backend/engine/CarlaEngineInternal.cpp
  4. +7
    -7
      source/backend/engine/CarlaEngineInternal.hpp
  5. +2
    -2
      source/backend/engine/CarlaEngineNative.cpp
  6. +170
    -0
      source/backend/engine/CarlaEngineRunner.cpp
  7. +14
    -8
      source/backend/engine/CarlaEngineRunner.hpp
  8. +0
    -159
      source/backend/engine/CarlaEngineThread.cpp
  9. +1
    -1
      source/backend/engine/Makefile
  10. +227
    -0
      source/utils/CarlaRunner.hpp

+ 2
- 2
source/backend/CarlaEngine.hpp View File

@@ -1311,13 +1311,13 @@ protected:
*/ */
friend class CarlaEngineEventPort; friend class CarlaEngineEventPort;
friend class CarlaEngineOsc; friend class CarlaEngineOsc;
friend class CarlaEngineThread;
friend class CarlaEngineRunner;
friend class CarlaPluginInstance; friend class CarlaPluginInstance;
friend class EngineInternalGraph; friend class EngineInternalGraph;
friend class PendingRtEventsRunner; friend class PendingRtEventsRunner;
friend class ScopedActionLock; friend class ScopedActionLock;
friend class ScopedEngineEnvironmentLocker; friend class ScopedEngineEnvironmentLocker;
friend class ScopedThreadStopper;
friend class ScopedRunnerStopper;
friend class PatchbayGraph; friend class PatchbayGraph;
friend struct ExternalGraph; friend struct ExternalGraph;
friend struct RackGraph; friend struct RackGraph;


+ 4
- 4
source/backend/engine/CarlaEngine.cpp View File

@@ -854,7 +854,7 @@ bool CarlaEngine::addPlugin(const BinaryType btype,
{ {
CARLA_SAFE_ASSERT(! pData->loadingProject); CARLA_SAFE_ASSERT(! pData->loadingProject);


const ScopedThreadStopper sts(this);
const ScopedRunnerStopper srs(this);


if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
pData->graph.replacePlugin(oldPlugin, plugin); 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.get() != nullptr, "Could not find plugin to remove");
CARLA_SAFE_ASSERT_RETURN_ERR(plugin->getId() == id, "Invalid engine internal data"); 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 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
@@ -967,7 +967,7 @@ bool CarlaEngine::removeAllPlugins()
if (pData->curPluginCount == 0) if (pData->curPluginCount == 0)
return true; return true;


const ScopedThreadStopper sts(this);
const ScopedRunnerStopper srs(this);


const uint curPluginCount = pData->curPluginCount; 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(pluginA->getId() == idA, "Invalid engine internal data");
CARLA_SAFE_ASSERT_RETURN_ERR(pluginB->getId() == idB, "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) if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
pData->graph.switchPlugins(pluginA, pluginB); pData->graph.switchPlugins(pluginA, pluginB);


+ 8
- 8
source/backend/engine/CarlaEngineInternal.cpp View File

@@ -377,7 +377,7 @@ EngineEvent* CarlaEngine::getInternalEventBuffer(const bool isInput) const noexc
// CarlaEngine::ProtectedData // CarlaEngine::ProtectedData


CarlaEngine::ProtectedData::ProtectedData(CarlaEngine* const engine) CarlaEngine::ProtectedData::ProtectedData(CarlaEngine* const engine)
: thread(engine),
: runner(engine),
#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
osc(engine), osc(engine),
#endif #endif
@@ -511,7 +511,7 @@ bool CarlaEngine::ProtectedData::init(const char* const clientName)
#endif #endif


nextAction.clearAndReset(); nextAction.clearAndReset();
thread.startThread();
runner.start();


return true; return true;
} }
@@ -526,7 +526,7 @@ void CarlaEngine::ProtectedData::close()


aboutToClose = true; aboutToClose = true;


thread.stopThread(500);
runner.stop();
nextAction.clearAndReset(); nextAction.clearAndReset();


#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) #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), : engine(e),
pData(e->pData) pData(e->pData)
{ {
pData->thread.stopThread(500);
pData->runner.stop();
} }


ScopedThreadStopper::~ScopedThreadStopper() noexcept
ScopedRunnerStopper::~ScopedRunnerStopper() noexcept
{ {
if (engine->isRunning() && ! pData->aboutToClose) if (engine->isRunning() && ! pData->aboutToClose)
pData->thread.startThread();
pData->runner.start();
} }


// ----------------------------------------------------------------------- // -----------------------------------------------------------------------


+ 7
- 7
source/backend/engine/CarlaEngineInternal.hpp View File

@@ -18,7 +18,7 @@
#ifndef CARLA_ENGINE_INTERNAL_HPP_INCLUDED #ifndef CARLA_ENGINE_INTERNAL_HPP_INCLUDED
#define CARLA_ENGINE_INTERNAL_HPP_INCLUDED #define CARLA_ENGINE_INTERNAL_HPP_INCLUDED


#include "CarlaEngineThread.hpp"
#include "CarlaEngineRunner.hpp"
#include "CarlaEngineUtils.hpp" #include "CarlaEngineUtils.hpp"
#include "CarlaPlugin.hpp" #include "CarlaPlugin.hpp"
#include "LinkedList.hpp" #include "LinkedList.hpp"
@@ -244,7 +244,7 @@ struct EnginePluginData {
// CarlaEngineProtectedData // CarlaEngineProtectedData


struct CarlaEngine::ProtectedData { struct CarlaEngine::ProtectedData {
CarlaEngineThread thread;
CarlaEngineRunner runner;


#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
CarlaEngineOsc osc; CarlaEngineOsc osc;
@@ -268,7 +268,7 @@ struct CarlaEngine::ProtectedData {
uint32_t bufferSize; uint32_t bufferSize;
double sampleRate; 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 int isIdling; // don't allow any operations while idling
uint curPluginCount; // number of plugins loaded (0...max) uint curPluginCount; // number of plugins loaded (0...max)
uint maxPluginNumber; // number of plugins allowed (0, 16, 99 or 255) uint maxPluginNumber; // number of plugins allowed (0, 16, 99 or 255)
@@ -362,18 +362,18 @@ private:


// ----------------------------------------------------------------------- // -----------------------------------------------------------------------


class ScopedThreadStopper
class ScopedRunnerStopper
{ {
public: public:
ScopedThreadStopper(CarlaEngine* engine) noexcept;
~ScopedThreadStopper() noexcept;
ScopedRunnerStopper(CarlaEngine* engine) noexcept;
~ScopedRunnerStopper() noexcept;


private: private:
CarlaEngine* const engine; CarlaEngine* const engine;
CarlaEngine::ProtectedData* const pData; CarlaEngine::ProtectedData* const pData;


CARLA_PREVENT_HEAP_ALLOCATION CARLA_PREVENT_HEAP_ALLOCATION
CARLA_DECLARE_NON_COPYABLE(ScopedThreadStopper)
CARLA_DECLARE_NON_COPYABLE(ScopedRunnerStopper)
}; };


// ----------------------------------------------------------------------- // -----------------------------------------------------------------------


+ 2
- 2
source/backend/engine/CarlaEngineNative.cpp View File

@@ -1520,8 +1520,8 @@ protected:
} }


// stopped during removeAllPlugins() // stopped during removeAllPlugins()
if (! pData->thread.isThreadRunning())
pData->thread.startThread();
if (! pData->runner.isRunnerActive())
pData->runner.start();


fOptionsForced = true; fOptionsForced = true;
const String state(data); const String state(data);


+ 170
- 0
source/backend/engine/CarlaEngineRunner.cpp View File

@@ -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

source/backend/engine/CarlaEngineThread.hpp → source/backend/engine/CarlaEngineRunner.hpp View File

@@ -1,6 +1,6 @@
/* /*
* Carla Plugin Host * 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
@@ -19,28 +19,34 @@
#define CARLA_ENGINE_THREAD_HPP_INCLUDED #define CARLA_ENGINE_THREAD_HPP_INCLUDED


#include "CarlaBackend.h" #include "CarlaBackend.h"
#include "CarlaThread.hpp"
#include "CarlaRunner.hpp"


#include "CarlaJuceUtils.hpp" #include "CarlaJuceUtils.hpp"


CARLA_BACKEND_START_NAMESPACE CARLA_BACKEND_START_NAMESPACE


// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// CarlaEngineThread
// CarlaEngineRunner


class CarlaEngineThread : public CarlaThread
class CarlaEngineRunner : public CarlaRunner
{ {
public: public:
CarlaEngineThread(CarlaEngine* engine) noexcept;
~CarlaEngineThread() noexcept override;
CarlaEngineRunner(CarlaEngine* engine) noexcept;
~CarlaEngineRunner() noexcept override;

void start();
void stop();


protected: protected:
void run() noexcept override;
bool run() noexcept override;


private: private:
CarlaEngine* const kEngine; CarlaEngine* const kEngine;


CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineThread)
bool fIsAlwaysRunning;
bool fIsPlugin;

CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineRunner)
}; };


// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

+ 0
- 159
source/backend/engine/CarlaEngineThread.cpp View File

@@ -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

+ 1
- 1
source/backend/engine/Makefile View File

@@ -38,7 +38,7 @@ OBJS = \
$(OBJDIR)/CarlaEngineGraph.cpp.o \ $(OBJDIR)/CarlaEngineGraph.cpp.o \
$(OBJDIR)/CarlaEngineInternal.cpp.o \ $(OBJDIR)/CarlaEngineInternal.cpp.o \
$(OBJDIR)/CarlaEnginePorts.cpp.o \ $(OBJDIR)/CarlaEnginePorts.cpp.o \
$(OBJDIR)/CarlaEngineThread.cpp.o
$(OBJDIR)/CarlaEngineRunner.cpp.o


ifeq ($(HAVE_LIBLO),true) ifeq ($(HAVE_LIBLO),true)
OBJS += \ OBJS += \


+ 227
- 0
source/utils/CarlaRunner.hpp View File

@@ -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

Loading…
Cancel
Save