VST3: fetch midi mappings all at once, use it for note/sound-off
[carla.git] / source / utils / CarlaThread.hpp
blobb871cf9e40d80ec9f166a38815cae85b2d91364e
1 /*
2 * Carla Thread
3 * Copyright (C) 2013-2023 Filipe Coelho <falktx@falktx.com>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * For a full copy of the GNU General Public License see the doc/GPL.txt file.
18 #ifndef CARLA_THREAD_HPP_INCLUDED
19 #define CARLA_THREAD_HPP_INCLUDED
21 #include "CarlaMutex.hpp"
22 #include "CarlaString.hpp"
23 #include "CarlaProcessUtils.hpp"
24 #include "CarlaTimeUtils.hpp"
26 #ifdef CARLA_OS_WASM
27 # error Threads do not work under wasm!
28 #endif
30 // -----------------------------------------------------------------------
31 // CarlaThread class
33 class CarlaThread
35 protected:
37 * Constructor.
39 CarlaThread(const char* const threadName) noexcept
40 : fLock(),
41 fSignal(),
42 fName(threadName),
43 #ifdef PTW32_DLLPORT
44 fHandle({nullptr, 0}),
45 #else
46 fHandle(0),
47 #endif
48 fShouldExit(false) {}
51 * Destructor.
53 virtual ~CarlaThread() /*noexcept*/
55 CARLA_SAFE_ASSERT(! isThreadRunning());
57 stopThread(-1);
61 * Virtual function to be implemented by the subclass.
63 virtual void run() = 0;
65 // -------------------------------------------------------------------
67 public:
69 * Check if the thread is running.
71 bool isThreadRunning() const noexcept
73 #ifdef PTW32_DLLPORT
74 return fHandle.p != nullptr;
75 #else
76 return fHandle != 0;
77 #endif
81 * Check if the thread should exit.
83 bool shouldThreadExit() const noexcept
85 return fShouldExit;
89 * Start the thread.
91 bool startThread(bool withRealtimePriority = false) noexcept
93 // check if already running
94 CARLA_SAFE_ASSERT_RETURN(! isThreadRunning(), true);
96 if (withRealtimePriority && std::getenv("CARLA_BRIDGE_DUMMY") != nullptr)
97 withRealtimePriority = false;
99 pthread_t handle;
101 pthread_attr_t attr;
102 pthread_attr_init(&attr);
104 struct sched_param sched_param;
105 carla_zeroStruct(sched_param);
107 if (withRealtimePriority)
109 sched_param.sched_priority = 80;
111 #ifndef CARLA_OS_HAIKU
112 if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) == 0 &&
113 pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) == 0 &&
114 #ifndef CARLA_OS_WIN
115 (pthread_attr_setschedpolicy(&attr, SCHED_FIFO) == 0 ||
116 pthread_attr_setschedpolicy(&attr, SCHED_RR) == 0) &&
117 #endif
118 pthread_attr_setschedparam(&attr, &sched_param) == 0)
120 carla_stdout("CarlaThread setup with realtime priority successful");
122 else
123 #endif
125 carla_stdout("CarlaThread setup with realtime priority failed, going with normal priority instead");
126 pthread_attr_destroy(&attr);
127 pthread_attr_init(&attr);
131 pthread_attr_setdetachstate(&attr, 1);
133 const CarlaMutexLocker cml(fLock);
135 fShouldExit = false;
137 bool ok = pthread_create(&handle, &attr, _entryPoint, this) == 0;
138 pthread_attr_destroy(&attr);
140 if (withRealtimePriority && !ok)
142 carla_stdout("CarlaThread with realtime priority failed on creation, going with normal priority instead");
143 pthread_attr_init(&attr);
144 pthread_attr_setdetachstate(&attr, 1);
145 ok = pthread_create(&handle, &attr, _entryPoint, this) == 0;
146 pthread_attr_destroy(&attr);
149 CARLA_SAFE_ASSERT_RETURN(ok, false);
150 #ifdef PTW32_DLLPORT
151 CARLA_SAFE_ASSERT_RETURN(handle.p != nullptr, false);
152 #else
153 CARLA_SAFE_ASSERT_RETURN(handle != 0, false);
154 #endif
155 _copyFrom(handle);
157 // wait for thread to start
158 fSignal.wait();
159 return true;
163 * Stop the thread.
164 * In the 'timeOutMilliseconds':
165 * = 0 -> no wait
166 * > 0 -> wait timeout value
167 * < 0 -> wait forever
169 bool stopThread(const int timeOutMilliseconds) noexcept
171 const CarlaMutexLocker cml(fLock);
173 if (isThreadRunning())
175 signalThreadShouldExit();
177 if (timeOutMilliseconds != 0)
179 // Wait for the thread to stop
180 int timeOutCheck = (timeOutMilliseconds == 1 || timeOutMilliseconds == -1) ? timeOutMilliseconds : timeOutMilliseconds/2;
182 for (; isThreadRunning();)
184 carla_msleep(2);
186 if (timeOutCheck < 0)
187 continue;
189 if (timeOutCheck > 0)
190 timeOutCheck -= 1;
191 else
192 break;
196 if (isThreadRunning())
198 // should never happen!
199 carla_stderr2("Carla assertion failure: \"! isThreadRunning()\" in file %s, line %i", __FILE__, __LINE__);
201 // copy thread id so we can clear our one
202 pthread_t threadId;
203 _copyTo(threadId);
204 _init();
206 pthread_detach(threadId);
207 return false;
211 return true;
215 * Tell the thread to stop as soon as possible.
217 void signalThreadShouldExit() noexcept
219 fShouldExit = true;
222 // -------------------------------------------------------------------
225 * Returns the name of the thread.
226 * This is the name that gets set in the constructor.
228 const CarlaString& getThreadName() const noexcept
230 return fName;
234 * Returns the Id/handle of the thread.
236 pthread_t getThreadId() const noexcept
238 #ifdef PTW32_DLLPORT
239 const pthread_t handle = { fHandle.p, fHandle.x };
240 return handle;
241 #else
242 return fHandle;
243 #endif
247 * Changes the name of the caller thread.
249 static void setCurrentThreadName(const char* const name) noexcept
251 CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0',);
253 carla_setProcessName(name);
254 #if defined(__GLIBC__) && (__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2012 && !defined(CARLA_OS_GNU_HURD)
255 pthread_setname_np(pthread_self(), name);
256 #endif
259 // -------------------------------------------------------------------
261 private:
262 CarlaMutex fLock; // Thread lock
263 CarlaSignal fSignal; // Thread start wait signal
264 const CarlaString fName; // Thread name
265 volatile pthread_t fHandle; // Handle for this thread
266 volatile bool fShouldExit; // true if thread should exit
269 * Init pthread type.
271 void _init() noexcept
273 #ifdef PTW32_DLLPORT
274 fHandle.p = nullptr;
275 fHandle.x = 0;
276 #else
277 fHandle = 0;
278 #endif
282 * Copy our pthread type from another var.
284 void _copyFrom(const pthread_t& handle) noexcept
286 #ifdef PTW32_DLLPORT
287 fHandle.p = handle.p;
288 fHandle.x = handle.x;
289 #else
290 fHandle = handle;
291 #endif
295 * Copy our pthread type to another var.
297 void _copyTo(volatile pthread_t& handle) const noexcept
299 #ifdef PTW32_DLLPORT
300 handle.p = fHandle.p;
301 handle.x = fHandle.x;
302 #else
303 handle = fHandle;
304 #endif
308 * Thread entry point.
310 void _runEntryPoint() noexcept
312 if (fName.isNotEmpty())
313 setCurrentThreadName(fName);
315 // report ready
316 fSignal.signal();
318 try {
319 run();
320 } catch(...) {}
322 // done
323 _init();
327 * Thread entry point.
329 static void* _entryPoint(void* userData) noexcept
331 static_cast<CarlaThread*>(userData)->_runEntryPoint();
332 return nullptr;
335 CARLA_DECLARE_NON_COPYABLE(CarlaThread)
338 // -----------------------------------------------------------------------
340 #endif // CARLA_THREAD_HPP_INCLUDED