comparison DPF-Prymula-audioplugins/dpf/distrho/extra/Runner.hpp @ 3:84e66ea83026

DPF-Prymula-audioplugins-0.231015-2
author prymula <prymula76@outlook.com>
date Mon, 16 Oct 2023 21:53:34 +0200
parents
children
comparison
equal deleted inserted replaced
2:cf2cb71d31dd 3:84e66ea83026
1 /*
2 * DISTRHO Plugin Framework (DPF)
3 * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
4 *
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.
8 *
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.
15 */
16
17 #ifndef DISTRHO_RUNNER_HPP_INCLUDED
18 #define DISTRHO_RUNNER_HPP_INCLUDED
19
20 #include "../DistrhoUtils.hpp"
21
22 #ifndef DISTRHO_OS_WASM
23 # include "Thread.hpp"
24 #else
25 # include "String.hpp"
26 # include <emscripten/html5.h>
27 #endif
28
29 START_NAMESPACE_DISTRHO
30
31 #ifdef DISTRHO_RUNNER_INDIRECT_WASM_CALLS
32 long d_emscripten_set_interval(void (*)(void*), double, void*);
33 void d_emscripten_clear_interval(long);
34 #else
35 # define d_emscripten_set_interval emscripten_set_interval
36 # define d_emscripten_clear_interval emscripten_clear_interval
37 #endif
38
39 // -------------------------------------------------------------------------------------------------------------------
40 // Runner class
41
42 /**
43 Runner class for DPF.
44
45 This is a handy class that handles "idle" time in either background or main thread,
46 whichever is more suitable to the target platform.
47 Typically background threads on desktop platforms, main thread on web.
48
49 A single function is expected to be implemented by subclasses,
50 which directly allows it to stop the runner by returning false.
51
52 You can use it for quick operations that do not need to be handled in the main thread if possible.
53 The target is to spread out execution over many runs, instead of spending a lot of time on a single task.
54 */
55 class Runner
56 {
57 protected:
58 /*
59 * Constructor.
60 */
61 Runner(const char* const runnerName = nullptr) noexcept
62 #ifndef DISTRHO_OS_WASM
63 : fRunnerThread(this, runnerName),
64 fTimeInterval(0)
65 #else
66 : fRunnerName(runnerName),
67 fIntervalId(0)
68 #endif
69 {
70 }
71
72 /*
73 * Destructor.
74 */
75 virtual ~Runner() /*noexcept*/
76 {
77 DISTRHO_SAFE_ASSERT(! isRunnerActive());
78
79 stopRunner();
80 }
81
82 /*
83 * Virtual function to be implemented by the subclass.
84 * Return true to keep running, false to stop execution.
85 */
86 virtual bool run() = 0;
87
88 /*
89 * Check if the runner should stop.
90 * To be called from inside the runner to know if a stop request has been made.
91 */
92 bool shouldRunnerStop() const noexcept
93 {
94 #ifndef DISTRHO_OS_WASM
95 return fRunnerThread.shouldThreadExit();
96 #else
97 return fIntervalId == 0;
98 #endif
99 }
100
101 // ---------------------------------------------------------------------------------------------------------------
102
103 public:
104 /*
105 * Check if the runner is active.
106 */
107 bool isRunnerActive() noexcept
108 {
109 #ifndef DISTRHO_OS_WASM
110 return fRunnerThread.isThreadRunning();
111 #else
112 return fIntervalId != 0;
113 #endif
114 }
115
116 /*
117 * Start the thread.
118 */
119 bool startRunner(const uint timeIntervalMilliseconds = 0) noexcept
120 {
121 #ifndef DISTRHO_OS_WASM
122 DISTRHO_SAFE_ASSERT_RETURN(!fRunnerThread.isThreadRunning(), false);
123 fTimeInterval = timeIntervalMilliseconds;
124 return fRunnerThread.startThread();
125 #else
126 DISTRHO_SAFE_ASSERT_RETURN(fIntervalId == 0, false);
127 fIntervalId = d_emscripten_set_interval(_entryPoint, timeIntervalMilliseconds, this);
128 return true;
129 #endif
130 }
131
132 /*
133 * Stop the runner.
134 * This will signal the runner to stop if active, and wait until it finishes.
135 */
136 bool stopRunner() noexcept
137 {
138 #ifndef DISTRHO_OS_WASM
139 return fRunnerThread.stopThread(-1);
140 #else
141 signalRunnerShouldStop();
142 return true;
143 #endif
144 }
145
146 /*
147 * Tell the runner to stop as soon as possible.
148 */
149 void signalRunnerShouldStop() noexcept
150 {
151 #ifndef DISTRHO_OS_WASM
152 fRunnerThread.signalThreadShouldExit();
153 #else
154 if (fIntervalId != 0)
155 {
156 d_emscripten_clear_interval(fIntervalId);
157 fIntervalId = 0;
158 }
159 #endif
160 }
161
162 // ---------------------------------------------------------------------------------------------------------------
163
164 /*
165 * Returns the name of the runner.
166 * This is the name that gets set in the constructor.
167 */
168 const String& getRunnerName() const noexcept
169 {
170 #ifndef DISTRHO_OS_WASM
171 return fRunnerThread.getThreadName();
172 #else
173 return fRunnerName;
174 #endif
175 }
176
177 // ---------------------------------------------------------------------------------------------------------------
178
179 private:
180 #ifndef DISTRHO_OS_WASM
181 class RunnerThread : public Thread
182 {
183 Runner* const runner;
184
185 public:
186 RunnerThread(Runner* const r, const char* const rn)
187 : Thread(rn),
188 runner(r) {}
189
190 protected:
191 void run() override
192 {
193 const uint timeInterval = runner->fTimeInterval;
194
195 while (!shouldThreadExit())
196 {
197 bool stillRunning = false;
198
199 try {
200 stillRunning = runner->run();
201 } catch(...) {}
202
203 if (stillRunning && !shouldThreadExit())
204 {
205 if (timeInterval != 0)
206 d_msleep(timeInterval);
207
208 // FIXME
209 // pthread_yield();
210 continue;
211 }
212
213 break;
214 }
215 }
216 } fRunnerThread;
217
218 uint fTimeInterval;
219 #else
220 const String fRunnerName;
221 long fIntervalId;
222
223 void _runEntryPoint() noexcept
224 {
225 bool stillRunning = false;
226
227 try {
228 stillRunning = run();
229 } catch(...) {}
230
231 if (fIntervalId != 0 && !stillRunning)
232 {
233 d_emscripten_clear_interval(fIntervalId);
234 fIntervalId = 0;
235 }
236 }
237
238 static void _entryPoint(void* const userData) noexcept
239 {
240 static_cast<Runner*>(userData)->_runEntryPoint();
241 }
242 #endif
243
244 DISTRHO_DECLARE_NON_COPYABLE(Runner)
245 };
246
247 // -------------------------------------------------------------------------------------------------------------------
248
249 END_NAMESPACE_DISTRHO
250
251 #endif // DISTRHO_RUNNER_HPP_INCLUDED