45 Thread(
const char*
const threadName =
nullptr) noexcept
51 fHandle({
nullptr, 0}),
64 DAF_SAFE_ASSERT(! isThreadRunning());
72 virtual void run() = 0;
80 bool isThreadRunning()
const noexcept
82 return fRunToken.load(std::memory_order_acquire) != 0;
88 bool shouldThreadExit()
const noexcept
90 return fShouldExit.load(std::memory_order_acquire);
96 bool startThread(
const bool withRealtimePriority =
false)
noexcept
99 DAF_SAFE_ASSERT_RETURN(! isThreadRunning(),
true);
104 pthread_attr_init(&attr);
106 struct sched_param sched_param = {};
108 if (withRealtimePriority)
110 #ifdef __MOD_DEVICES__
112 const char*
const srtprio = std::getenv(
"MOD_PLUGIN_THREAD_PRIORITY");
113 if (srtprio !=
nullptr && (rtprio = std::atoi(srtprio)) > 0)
114 sched_param.sched_priority = rtprio - 1;
117 sched_param.sched_priority = 80;
120 if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) == 0 &&
121 pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) == 0 &&
122 #ifndef DAF_OS_WINDOWS
123 (pthread_attr_setschedpolicy(&attr, SCHED_FIFO) == 0 ||
124 pthread_attr_setschedpolicy(&attr, SCHED_RR) == 0) &&
126 pthread_attr_setschedparam(&attr, &sched_param) == 0)
128 d_stdout(
"Thread setup with realtime priority successful");
133 d_stdout(
"Thread setup with realtime priority failed, going with normal priority instead");
134 pthread_attr_destroy(&attr);
135 pthread_attr_init(&attr);
139 const MutexLocker ml(fLock);
141 fShouldExit.store(
false, std::memory_order_release);
147 if (++fLastRunToken == 0)
149 fRunToken.store(fLastRunToken, std::memory_order_release);
151 bool ok = pthread_create(&handle, &attr, _entryPoint,
this) == 0;
152 pthread_attr_destroy(&attr);
154 if (withRealtimePriority && !ok)
156 d_stdout(
"Thread with realtime priority failed on creation, going with normal priority instead");
157 pthread_attr_init(&attr);
158 ok = pthread_create(&handle, &attr, _entryPoint,
this) == 0;
159 pthread_attr_destroy(&attr);
164 fRunToken.store(0, std::memory_order_release);
165 d_safe_assert(
"ok", __FILE__, __LINE__);
172 fHandleSignal.signal();
174 pthread_detach(handle);
188 bool stopThread(
const int timeOutMilliseconds)
noexcept
190 const MutexLocker ml(fLock);
192 if (isThreadRunning())
194 signalThreadShouldExit();
196 if (timeOutMilliseconds != 0)
199 int timeOutCheck = (timeOutMilliseconds == 1 || timeOutMilliseconds == -1) ? timeOutMilliseconds : timeOutMilliseconds/2;
201 for (; isThreadRunning();)
205 if (timeOutCheck < 0)
208 if (timeOutCheck > 0)
215 if (isThreadRunning())
218 d_stderr2(
"assertion failure: \"! isThreadRunning()\" in file %s, line %i", __FILE__, __LINE__);
223 fRunToken.store(0, std::memory_order_release);
234 void signalThreadShouldExit()
noexcept
236 fShouldExit.store(
true, std::memory_order_release);
245 const String& getThreadName()
const noexcept
254 pthread_t getThreadId()
const noexcept
256 if (isThreadRunning())
260 const pthread_t nullHandle = {
nullptr, 0};
270 static void setCurrentThreadName(
const char*
const name)
noexcept
272 DAF_SAFE_ASSERT_RETURN(name !=
nullptr && name[0] !=
'\0',);
275 prctl(PR_SET_NAME, name, 0, 0, 0);
277 #if defined(__GLIBC__) && (__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2012 && !defined(DAF_OS_GNU_HURD)
278 pthread_setname_np(pthread_self(), name);
282 pthread_setname_np(name);
284 #ifdef DAF_OS_WINDOWS
287 typedef HRESULT(WINAPI* PFN_SetThreadDescription)(HANDLE, PCWSTR);
289 #if defined(__GNUC__) && (__GNUC__ >= 9)
290 # pragma GCC diagnostic push
291 # pragma GCC diagnostic ignored "-Wcast-function-type"
293 static const PFN_SetThreadDescription setThreadDescription = (PFN_SetThreadDescription)
294 GetProcAddress(GetModuleHandleA(
"kernel32.dll"),
"SetThreadDescription");
295 #if defined(__GNUC__) && (__GNUC__ >= 9)
296 # pragma GCC diagnostic pop
299 if (setThreadDescription !=
nullptr)
304 if (MultiByteToWideChar(CP_UTF8, 0, name, -1, wname,
static_cast<int>(ARRAY_SIZE(wname))) > 0)
305 setThreadDescription(GetCurrentThread(), wname);
318 std::atomic<uint32_t> fRunToken;
319 uint32_t fLastRunToken;
320 std::atomic<bool> fShouldExit;
325 void _runEntryPoint()
noexcept
328 fHandleSignal.wait();
331 uint32_t runToken = fRunToken.load(std::memory_order_acquire);
333 if (fName.isNotEmpty())
334 setCurrentThreadName(fName);
345 fRunToken.compare_exchange_strong(runToken, 0, std::memory_order_acq_rel, std::memory_order_relaxed);
351 static void* _entryPoint(
void* userData)
noexcept
353 static_cast<Thread*
>(userData)->_runEntryPoint();
357 DAF_DECLARE_NON_COPYABLE(Thread)