Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

234 lines
5.6KB

  1. /*
  2. * Carla Thread
  3. * Copyright (C) 2013-2014 Filipe Coelho <falktx@falktx.com>
  4. *
  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.
  9. *
  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.
  14. *
  15. * For a full copy of the GNU General Public License see the doc/GPL.txt file.
  16. */
  17. #ifndef CARLA_THREAD_HPP_INCLUDED
  18. #define CARLA_THREAD_HPP_INCLUDED
  19. #include "CarlaMutex.hpp"
  20. #include "CarlaString.hpp"
  21. #if defined(__GLIBC__) && (__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2012
  22. // has pthread_setname_np
  23. #elif defined(CARLA_OS_LINUX)
  24. # include <sys/prctl.h>
  25. #endif
  26. // -----------------------------------------------------------------------
  27. // CarlaThread class
  28. class CarlaThread
  29. {
  30. protected:
  31. /*
  32. * Constructor.
  33. */
  34. CarlaThread(const char* const threadName = nullptr) noexcept
  35. : fName(threadName),
  36. fShouldExit(false)
  37. {
  38. _init();
  39. }
  40. /*
  41. * Destructor.
  42. */
  43. virtual ~CarlaThread() /*noexcept*/
  44. {
  45. CARLA_SAFE_ASSERT(! isThreadRunning());
  46. stopThread(-1);
  47. }
  48. /*
  49. * Virtual function to be implemented by the subclass.
  50. */
  51. virtual void run() = 0;
  52. public:
  53. /*
  54. * Check if the thread is running.
  55. */
  56. bool isThreadRunning() const noexcept
  57. {
  58. #ifdef CARLA_OS_WIN
  59. return (fHandle.p != nullptr);
  60. #else
  61. return (fHandle != 0);
  62. #endif
  63. }
  64. /*
  65. * Check if the thread should exit.
  66. */
  67. bool shouldThreadExit() const noexcept
  68. {
  69. return fShouldExit;
  70. }
  71. /*
  72. * Start the thread.
  73. */
  74. bool startThread() noexcept
  75. {
  76. // check if already running
  77. CARLA_SAFE_ASSERT_RETURN(! isThreadRunning(), true);
  78. const CarlaMutexLocker cml(fLock);
  79. fShouldExit = false;
  80. if (pthread_create(&fHandle, nullptr, _entryPoint, this) == 0)
  81. {
  82. #ifdef CARLA_OS_WIN
  83. CARLA_SAFE_ASSERT_RETURN(fHandle.p != nullptr, false);
  84. #else
  85. CARLA_SAFE_ASSERT_RETURN(fHandle != 0, false);
  86. #endif
  87. #if defined(__GLIBC__) && (__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2012
  88. if (fName.isNotEmpty())
  89. pthread_setname_np(fHandle, fName);
  90. #endif
  91. pthread_detach(fHandle);
  92. // wait for thread to start
  93. fLock.lock();
  94. return true;
  95. }
  96. return false;
  97. }
  98. /*
  99. * Stop the thread.
  100. * In the 'timeOutMilliseconds':
  101. * = 0 -> no wait
  102. * > 0 -> wait timeout value
  103. * < 0 -> wait forever
  104. */
  105. bool stopThread(const int timeOutMilliseconds) noexcept
  106. {
  107. const CarlaMutexLocker cml(fLock);
  108. if (isThreadRunning())
  109. {
  110. signalThreadShouldExit();
  111. if (timeOutMilliseconds != 0)
  112. {
  113. // Wait for the thread to stop
  114. int timeOutCheck = (timeOutMilliseconds == 1 || timeOutMilliseconds == -1) ? timeOutMilliseconds : timeOutMilliseconds/2;
  115. for (; isThreadRunning();)
  116. {
  117. carla_msleep(2);
  118. if (timeOutCheck < 0)
  119. continue;
  120. if (timeOutCheck > 0)
  121. timeOutCheck -= 1;
  122. else
  123. break;
  124. }
  125. }
  126. if (isThreadRunning())
  127. {
  128. // should never happen!
  129. carla_stderr2("Carla assertion failure: \"! isThreadRunning()\" in file %s, line %i", __FILE__, __LINE__);
  130. // use a copy thread id so we can clear our own one
  131. pthread_t threadId;
  132. carla_copyStruct<pthread_t>(threadId, fHandle);
  133. _init();
  134. try {
  135. pthread_cancel(threadId);
  136. } catch(...) {}
  137. return false;
  138. }
  139. }
  140. return true;
  141. }
  142. /*
  143. * Tell the thread to stop as soon as possible.
  144. */
  145. void signalThreadShouldExit() noexcept
  146. {
  147. fShouldExit = true;
  148. }
  149. static void setCurrentThreadName(const char* const name) noexcept
  150. {
  151. CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0',);
  152. #if defined(__GLIBC__) && (__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2012
  153. if (fName.isNotEmpty())
  154. pthread_setname_np(pthread_self(), fName);
  155. #elif defined(CARLA_OS_LINUX)
  156. prctl(PR_SET_NAME, name, 0, 0, 0);
  157. #endif
  158. }
  159. private:
  160. CarlaMutex fLock; // Thread lock
  161. const CarlaString fName; // Thread name
  162. pthread_t fHandle; // Handle for this thread
  163. volatile bool fShouldExit; // true if thread should exit
  164. void _init() noexcept
  165. {
  166. #ifdef CARLA_OS_WIN
  167. fHandle.p = nullptr;
  168. fHandle.x = 0;
  169. #else
  170. fHandle = 0;
  171. #endif
  172. }
  173. void _runEntryPoint() noexcept
  174. {
  175. // report ready
  176. fLock.unlock();
  177. try {
  178. run();
  179. } catch(...) {}
  180. // done
  181. _init();
  182. }
  183. static void* _entryPoint(void* userData) noexcept
  184. {
  185. static_cast<CarlaThread*>(userData)->_runEntryPoint();
  186. return nullptr;
  187. }
  188. CARLA_PREVENT_HEAP_ALLOCATION
  189. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaThread)
  190. };
  191. // -----------------------------------------------------------------------
  192. #endif // CARLA_THREAD_HPP_INCLUDED