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.

287 lines
6.5KB

  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. #ifdef CARLA_OS_LINUX
  22. # include <sys/prctl.h>
  23. #endif
  24. // -----------------------------------------------------------------------
  25. // CarlaThread class
  26. class CarlaThread
  27. {
  28. protected:
  29. /*
  30. * Constructor.
  31. */
  32. CarlaThread(const char* const threadName = nullptr) noexcept
  33. : fLock(),
  34. fName(threadName),
  35. #ifdef PTW32_DLLPORT
  36. fHandle({nullptr, 0}),
  37. #else
  38. fHandle(0),
  39. #endif
  40. fShouldExit(false) {}
  41. /*
  42. * Destructor.
  43. */
  44. virtual ~CarlaThread() /*noexcept*/
  45. {
  46. CARLA_SAFE_ASSERT(! isThreadRunning());
  47. stopThread(-1);
  48. }
  49. /*
  50. * Virtual function to be implemented by the subclass.
  51. */
  52. virtual void run() = 0;
  53. // -------------------------------------------------------------------
  54. public:
  55. /*
  56. * Check if the thread is running.
  57. */
  58. bool isThreadRunning() const noexcept
  59. {
  60. #ifdef PTW32_DLLPORT
  61. return (fHandle.p != nullptr);
  62. #else
  63. return (fHandle != 0);
  64. #endif
  65. }
  66. /*
  67. * Check if the thread should exit.
  68. */
  69. bool shouldThreadExit() const noexcept
  70. {
  71. return fShouldExit;
  72. }
  73. /*
  74. * Start the thread.
  75. */
  76. bool startThread() noexcept
  77. {
  78. // check if already running
  79. CARLA_SAFE_ASSERT_RETURN(! isThreadRunning(), true);
  80. const CarlaMutexLocker cml(fLock);
  81. fShouldExit = false;
  82. pthread_t handle;
  83. if (pthread_create(&handle, nullptr, _entryPoint, this) == 0)
  84. {
  85. #ifdef PTW32_DLLPORT
  86. CARLA_SAFE_ASSERT_RETURN(handle.p != nullptr, false);
  87. #else
  88. CARLA_SAFE_ASSERT_RETURN(handle != 0, false);
  89. #endif
  90. pthread_detach(handle);
  91. _copyFrom(handle);
  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. // copy thread id so we can clear our one
  131. pthread_t threadId;
  132. _copyTo(threadId);
  133. _init();
  134. try {
  135. pthread_cancel(threadId);
  136. } CARLA_SAFE_EXCEPTION("pthread_cancel");
  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. // -------------------------------------------------------------------
  150. /*
  151. * Returns the name of the thread.
  152. * This is the name that gets set in the constructor.
  153. */
  154. const CarlaString& getThreadName() const noexcept
  155. {
  156. return fName;
  157. }
  158. /*
  159. * Changes the name of the caller thread.
  160. */
  161. static void setCurrentThreadName(const char* const name) noexcept
  162. {
  163. CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0',);
  164. #ifdef CARLA_OS_LINUX
  165. prctl(PR_SET_NAME, name, 0, 0, 0);
  166. #endif
  167. #if defined(__GLIBC__) && (__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2012
  168. pthread_setname_np(pthread_self(), name);
  169. #endif
  170. }
  171. // -------------------------------------------------------------------
  172. private:
  173. CarlaMutex fLock; // Thread lock
  174. const CarlaString fName; // Thread name
  175. volatile pthread_t fHandle; // Handle for this thread
  176. volatile bool fShouldExit; // true if thread should exit
  177. /*
  178. * Init pthread type.
  179. */
  180. void _init() noexcept
  181. {
  182. #ifdef PTW32_DLLPORT
  183. fHandle.p = nullptr;
  184. fHandle.x = 0;
  185. #else
  186. fHandle = 0;
  187. #endif
  188. }
  189. /*
  190. * Copy our pthread type from another var.
  191. */
  192. void _copyFrom(const pthread_t& handle) noexcept
  193. {
  194. #ifdef PTW32_DLLPORT
  195. fHandle.p = handle.p;
  196. fHandle.x = handle.x;
  197. #else
  198. fHandle = handle;
  199. #endif
  200. }
  201. /*
  202. * Copy our pthread type to another var.
  203. */
  204. void _copyTo(volatile pthread_t& handle) const noexcept
  205. {
  206. #ifdef PTW32_DLLPORT
  207. handle.p = fHandle.p;
  208. handle.x = fHandle.x;
  209. #else
  210. handle = fHandle;
  211. #endif
  212. }
  213. /*
  214. * Thread entry point.
  215. */
  216. void _runEntryPoint() noexcept
  217. {
  218. // report ready
  219. fLock.unlock();
  220. setCurrentThreadName(fName);
  221. try {
  222. run();
  223. } catch(...) {}
  224. // done
  225. _init();
  226. }
  227. /*
  228. * Thread entry point.
  229. */
  230. static void* _entryPoint(void* userData) noexcept
  231. {
  232. static_cast<CarlaThread*>(userData)->_runEntryPoint();
  233. return nullptr;
  234. }
  235. CARLA_DECLARE_NON_COPY_CLASS(CarlaThread)
  236. };
  237. // -----------------------------------------------------------------------
  238. #endif // CARLA_THREAD_HPP_INCLUDED