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"
27 # error Threads do not work under wasm!
30 // -----------------------------------------------------------------------
39 CarlaThread(const char* const threadName
) noexcept
44 fHandle({nullptr, 0}),
53 virtual ~CarlaThread() /*noexcept*/
55 CARLA_SAFE_ASSERT(! isThreadRunning());
61 * Virtual function to be implemented by the subclass.
63 virtual void run() = 0;
65 // -------------------------------------------------------------------
69 * Check if the thread is running.
71 bool isThreadRunning() const noexcept
74 return fHandle
.p
!= nullptr;
81 * Check if the thread should exit.
83 bool shouldThreadExit() const noexcept
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;
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 &&
115 (pthread_attr_setschedpolicy(&attr
, SCHED_FIFO
) == 0 ||
116 pthread_attr_setschedpolicy(&attr
, SCHED_RR
) == 0) &&
118 pthread_attr_setschedparam(&attr
, &sched_param
) == 0)
120 carla_stdout("CarlaThread setup with realtime priority successful");
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
);
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);
151 CARLA_SAFE_ASSERT_RETURN(handle
.p
!= nullptr, false);
153 CARLA_SAFE_ASSERT_RETURN(handle
!= 0, false);
157 // wait for thread to start
164 * In the 'timeOutMilliseconds':
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();)
186 if (timeOutCheck
< 0)
189 if (timeOutCheck
> 0)
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
206 pthread_detach(threadId
);
215 * Tell the thread to stop as soon as possible.
217 void signalThreadShouldExit() noexcept
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
234 * Returns the Id/handle of the thread.
236 pthread_t
getThreadId() const noexcept
239 const pthread_t handle
= { fHandle
.p
, fHandle
.x
};
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
);
259 // -------------------------------------------------------------------
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
271 void _init() noexcept
282 * Copy our pthread type from another var.
284 void _copyFrom(const pthread_t
& handle
) noexcept
287 fHandle
.p
= handle
.p
;
288 fHandle
.x
= handle
.x
;
295 * Copy our pthread type to another var.
297 void _copyTo(volatile pthread_t
& handle
) const noexcept
300 handle
.p
= fHandle
.p
;
301 handle
.x
= fHandle
.x
;
308 * Thread entry point.
310 void _runEntryPoint() noexcept
312 if (fName
.isNotEmpty())
313 setCurrentThreadName(fName
);
327 * Thread entry point.
329 static void* _entryPoint(void* userData
) noexcept
331 static_cast<CarlaThread
*>(userData
)->_runEntryPoint();
335 CARLA_DECLARE_NON_COPYABLE(CarlaThread
)
338 // -----------------------------------------------------------------------
340 #endif // CARLA_THREAD_HPP_INCLUDED