3 * Copyright (C) 2022-2023 Filipe Coelho <falktx@falktx.com>
5 * Permission to use, copy, modify, and/or distribute this software for any purpose with
6 * or without fee is hereby granted, provided that the above copyright notice and this
7 * permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
10 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
11 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
13 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #ifndef CARLA_RUNNER_HPP_INCLUDED
18 #define CARLA_RUNNER_HPP_INCLUDED
20 #include "CarlaUtils.hpp"
23 # include "CarlaThread.hpp"
25 # include "CarlaString.hpp"
26 # include <emscripten/html5.h>
29 // -------------------------------------------------------------------------------------------------------------------
33 This is a handy class that handles "idle" time in either background or main thread,
34 whichever is more suitable to the target platform.
35 Typically background threads on desktop platforms, main thread on web.
37 A single function is expected to be implemented by subclasses,
38 which directly allows it to stop the runner by returning false.
40 You can use it for quick operations that do not need to be handled in the main thread if possible.
41 The target is to spread out execution over many runs, instead of spending a lot of time on a single task.
49 CarlaRunner(const char* const runnerName
= nullptr) noexcept
51 : fRunnerThread(this, runnerName
),
54 : fRunnerName(runnerName
),
63 virtual ~CarlaRunner() /*noexcept*/
65 CARLA_SAFE_ASSERT(! isRunnerActive());
71 * Virtual function to be implemented by the subclass.
72 * Return true to keep running, false to stop execution.
74 virtual bool run() = 0;
77 * Check if the runner should stop.
78 * To be called from inside the runner to know if a stop request has been made.
80 bool shouldRunnerStop() const noexcept
83 return fRunnerThread
.shouldThreadExit();
85 return fIntervalId
== 0;
89 // ---------------------------------------------------------------------------------------------------------------
93 * Check if the runner is active.
95 bool isRunnerActive() noexcept
98 return fRunnerThread
.isThreadRunning();
100 return fIntervalId
!= 0;
107 bool startRunner(const uint timeIntervalMilliseconds
= 0) noexcept
109 #ifndef CARLA_OS_WASM
110 CARLA_SAFE_ASSERT_RETURN(!fRunnerThread
.isThreadRunning(), false);
111 fTimeInterval
= timeIntervalMilliseconds
;
112 return fRunnerThread
.startThread();
114 CARLA_SAFE_ASSERT_RETURN(fIntervalId
== 0, false);
115 fIntervalId
= emscripten_set_interval(_entryPoint
, timeIntervalMilliseconds
, this);
122 * This will signal the runner to stop if active, and wait until it finishes.
124 bool stopRunner() noexcept
126 #ifndef CARLA_OS_WASM
127 return fRunnerThread
.stopThread(-1);
129 signalRunnerShouldStop();
135 * Tell the runner to stop as soon as possible.
137 void signalRunnerShouldStop() noexcept
139 #ifndef CARLA_OS_WASM
140 fRunnerThread
.signalThreadShouldExit();
142 if (fIntervalId
!= 0)
144 emscripten_clear_interval(fIntervalId
);
150 // ---------------------------------------------------------------------------------------------------------------
153 * Returns the name of the runner.
154 * This is the name that gets set in the constructor.
156 const CarlaString
& getRunnerName() const noexcept
158 #ifndef CARLA_OS_WASM
159 return fRunnerThread
.getThreadName();
165 // ---------------------------------------------------------------------------------------------------------------
168 #ifndef CARLA_OS_WASM
169 class RunnerThread
: public CarlaThread
171 CarlaRunner
* const runner
;
174 RunnerThread(CarlaRunner
* const r
, const char* const rn
)
181 const uint timeInterval
= runner
->fTimeInterval
;
183 while (!shouldThreadExit())
185 bool stillRunning
= false;
188 stillRunning
= runner
->run();
191 if (stillRunning
&& !shouldThreadExit())
193 if (timeInterval
!= 0)
194 carla_msleep(timeInterval
);
205 CARLA_DECLARE_NON_COPYABLE(RunnerThread
)
210 const CarlaString fRunnerName
;
213 void _runEntryPoint() noexcept
215 bool stillRunning
= false;
218 stillRunning
= run();
221 if (fIntervalId
!= 0 && !stillRunning
)
223 emscripten_clear_interval(fIntervalId
);
228 static void _entryPoint(void* const userData
) noexcept
230 static_cast<CarlaRunner
*>(userData
)->_runEntryPoint();
234 CARLA_DECLARE_NON_COPYABLE(CarlaRunner
)
237 // -------------------------------------------------------------------------------------------------------------------
239 #endif // CARLA_RUNNER_HPP_INCLUDED