comparison DPF-Prymula-audioplugins/dpf/distrho/extra/Thread.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_THREAD_HPP_INCLUDED
18 #define DISTRHO_THREAD_HPP_INCLUDED
19
20 #include "Mutex.hpp"
21 #include "Sleep.hpp"
22 #include "String.hpp"
23
24 #ifdef DISTRHO_OS_LINUX
25 # include <sys/prctl.h>
26 #endif
27
28 #ifdef DISTRHO_OS_WASM
29 # error Threads do not work under wasm!
30 #endif
31
32 START_NAMESPACE_DISTRHO
33
34 // -----------------------------------------------------------------------
35 // Thread class
36
37 class Thread
38 {
39 protected:
40 /*
41 * Constructor.
42 */
43 Thread(const char* const threadName = nullptr) noexcept
44 : fLock(),
45 fSignal(),
46 fName(threadName),
47 #ifdef PTW32_DLLPORT
48 fHandle({nullptr, 0}),
49 #else
50 fHandle(0),
51 #endif
52 fShouldExit(false) {}
53
54 /*
55 * Destructor.
56 */
57 virtual ~Thread() /*noexcept*/
58 {
59 DISTRHO_SAFE_ASSERT(! isThreadRunning());
60
61 stopThread(-1);
62 }
63
64 /*
65 * Virtual function to be implemented by the subclass.
66 */
67 virtual void run() = 0;
68
69 // -------------------------------------------------------------------
70
71 public:
72 /*
73 * Check if the thread is running.
74 */
75 bool isThreadRunning() const noexcept
76 {
77 #ifdef PTW32_DLLPORT
78 return (fHandle.p != nullptr);
79 #else
80 return (fHandle != 0);
81 #endif
82 }
83
84 /*
85 * Check if the thread should exit.
86 */
87 bool shouldThreadExit() const noexcept
88 {
89 return fShouldExit;
90 }
91
92 /*
93 * Start the thread.
94 */
95 bool startThread(const bool withRealtimePriority = false) noexcept
96 {
97 // check if already running
98 DISTRHO_SAFE_ASSERT_RETURN(! isThreadRunning(), true);
99
100 pthread_t handle;
101
102 pthread_attr_t attr;
103 pthread_attr_init(&attr);
104
105 struct sched_param sched_param = {};
106
107 if (withRealtimePriority)
108 {
109 #ifdef __MOD_DEVICES__
110 int rtprio;
111 const char* const srtprio = std::getenv("MOD_PLUGIN_THREAD_PRIORITY");
112 if (srtprio != nullptr && (rtprio = std::atoi(srtprio)) > 0)
113 sched_param.sched_priority = rtprio - 1;
114 else
115 #endif
116 sched_param.sched_priority = 80;
117
118 #ifndef DISTRHO_OS_HAIKU
119 if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) == 0 &&
120 pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) == 0 &&
121 #ifndef DISTRHO_OS_WINDOWS
122 (pthread_attr_setschedpolicy(&attr, SCHED_FIFO) == 0 ||
123 pthread_attr_setschedpolicy(&attr, SCHED_RR) == 0) &&
124 #endif
125 pthread_attr_setschedparam(&attr, &sched_param) == 0)
126 {
127 d_stdout("Thread setup with realtime priority successful");
128 }
129 else
130 #endif
131 {
132 d_stdout("Thread setup with realtime priority failed, going with normal priority instead");
133 pthread_attr_destroy(&attr);
134 pthread_attr_init(&attr);
135 }
136 }
137
138 const MutexLocker ml(fLock);
139
140 fShouldExit = false;
141
142 bool ok = pthread_create(&handle, &attr, _entryPoint, this) == 0;
143 pthread_attr_destroy(&attr);
144
145 if (withRealtimePriority && !ok)
146 {
147 d_stdout("Thread with realtime priority failed on creation, going with normal priority instead");
148 pthread_attr_init(&attr);
149 ok = pthread_create(&handle, &attr, _entryPoint, this) == 0;
150 pthread_attr_destroy(&attr);
151 }
152
153 DISTRHO_SAFE_ASSERT_RETURN(ok, false);
154 #ifdef PTW32_DLLPORT
155 DISTRHO_SAFE_ASSERT_RETURN(handle.p != nullptr, false);
156 #else
157 DISTRHO_SAFE_ASSERT_RETURN(handle != 0, false);
158 #endif
159 pthread_detach(handle);
160 _copyFrom(handle);
161
162 // wait for thread to start
163 fSignal.wait();
164 return true;
165 }
166
167 /*
168 * Stop the thread.
169 * In the 'timeOutMilliseconds':
170 * = 0 -> no wait
171 * > 0 -> wait timeout value
172 * < 0 -> wait forever
173 */
174 bool stopThread(const int timeOutMilliseconds) noexcept
175 {
176 const MutexLocker ml(fLock);
177
178 if (isThreadRunning())
179 {
180 signalThreadShouldExit();
181
182 if (timeOutMilliseconds != 0)
183 {
184 // Wait for the thread to stop
185 int timeOutCheck = (timeOutMilliseconds == 1 || timeOutMilliseconds == -1) ? timeOutMilliseconds : timeOutMilliseconds/2;
186
187 for (; isThreadRunning();)
188 {
189 d_msleep(2);
190
191 if (timeOutCheck < 0)
192 continue;
193
194 if (timeOutCheck > 0)
195 timeOutCheck -= 1;
196 else
197 break;
198 }
199 }
200
201 if (isThreadRunning())
202 {
203 // should never happen!
204 d_stderr2("assertion failure: \"! isThreadRunning()\" in file %s, line %i", __FILE__, __LINE__);
205
206 // copy thread id so we can clear our one
207 pthread_t threadId;
208 _copyTo(threadId);
209 _init();
210
211 pthread_detach(threadId);
212 return false;
213 }
214 }
215
216 return true;
217 }
218
219 /*
220 * Tell the thread to stop as soon as possible.
221 */
222 void signalThreadShouldExit() noexcept
223 {
224 fShouldExit = true;
225 }
226
227 // -------------------------------------------------------------------
228
229 /*
230 * Returns the name of the thread.
231 * This is the name that gets set in the constructor.
232 */
233 const String& getThreadName() const noexcept
234 {
235 return fName;
236 }
237
238 /*
239 * Returns the Id/handle of the thread.
240 */
241 pthread_t getThreadId() const noexcept
242 {
243 return fHandle;
244 }
245
246 /*
247 * Changes the name of the caller thread.
248 */
249 static void setCurrentThreadName(const char* const name) noexcept
250 {
251 DISTRHO_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0',);
252
253 #ifdef DISTRHO_OS_LINUX
254 prctl(PR_SET_NAME, name, 0, 0, 0);
255 #endif
256 #if defined(__GLIBC__) && (__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2012 && !defined(DISTRHO_OS_GNU_HURD)
257 pthread_setname_np(pthread_self(), name);
258 #endif
259 }
260
261 // -------------------------------------------------------------------
262
263 private:
264 Mutex fLock; // Thread lock
265 Signal fSignal; // Thread start wait signal
266 const String fName; // Thread name
267 volatile pthread_t fHandle; // Handle for this thread
268 volatile bool fShouldExit; // true if thread should exit
269
270 /*
271 * Init pthread type.
272 */
273 void _init() noexcept
274 {
275 #ifdef PTW32_DLLPORT
276 fHandle.p = nullptr;
277 fHandle.x = 0;
278 #else
279 fHandle = 0;
280 #endif
281 }
282
283 /*
284 * Copy our pthread type from another var.
285 */
286 void _copyFrom(const pthread_t& handle) noexcept
287 {
288 #ifdef PTW32_DLLPORT
289 fHandle.p = handle.p;
290 fHandle.x = handle.x;
291 #else
292 fHandle = handle;
293 #endif
294 }
295
296 /*
297 * Copy our pthread type to another var.
298 */
299 void _copyTo(volatile pthread_t& handle) const noexcept
300 {
301 #ifdef PTW32_DLLPORT
302 handle.p = fHandle.p;
303 handle.x = fHandle.x;
304 #else
305 handle = fHandle;
306 #endif
307 }
308
309 /*
310 * Thread entry point.
311 */
312 void _runEntryPoint() noexcept
313 {
314 if (fName.isNotEmpty())
315 setCurrentThreadName(fName);
316
317 // report ready
318 fSignal.signal();
319
320 try {
321 run();
322 } catch(...) {}
323
324 // done
325 _init();
326 }
327
328 /*
329 * Thread entry point.
330 */
331 static void* _entryPoint(void* userData) noexcept
332 {
333 static_cast<Thread*>(userData)->_runEntryPoint();
334 return nullptr;
335 }
336
337 DISTRHO_DECLARE_NON_COPYABLE(Thread)
338 };
339
340 // -----------------------------------------------------------------------
341
342 END_NAMESPACE_DISTRHO
343
344 #endif // DISTRHO_THREAD_HPP_INCLUDED