aRts audio server
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.

399 lines
8.3KB

  1. /*
  2. Copyright (C) 2001 Stefan Westerfeld
  3. stefan@space.twc.de
  4. This library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Library General Public
  6. License as published by the Free Software Foundation; either
  7. version 2 of the License, or (at your option) any later version.
  8. This library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Library General Public License for more details.
  12. You should have received a copy of the GNU Library General Public License
  13. along with this library; see the file COPYING.LIB. If not, write to
  14. the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  15. Boston, MA 02110-1301, USA.
  16. */
  17. #ifdef HAVE_CONFIG_H
  18. #include <config.h>
  19. #endif
  20. /* only compile this if we have libpthread available */
  21. #ifdef HAVE_LIBPTHREAD
  22. #include <gsl/gslconfig.h>
  23. #include <gsl/gslcommon.h>
  24. #include <sys/types.h>
  25. #include <stddef.h>
  26. #include <stdarg.h>
  27. #include <pthread.h>
  28. #include <semaphore.h>
  29. #include <debug.h>
  30. #include <string.h>
  31. #include "thread.h"
  32. /*
  33. * define this if you want to protect mutexes against being locked twice by
  34. * the same thread
  35. */
  36. #undef PTHREAD_DEBUG
  37. namespace Arts {
  38. extern void *gslGlobalMutexTable;
  39. namespace PosixThreads {
  40. class ThreadCondition_impl;
  41. class Mutex_impl : public Arts::Mutex_impl {
  42. protected:
  43. friend class ThreadCondition_impl;
  44. pthread_mutex_t mutex;
  45. #ifdef PTHREAD_DEBUG
  46. pthread_t owner;
  47. #endif
  48. public:
  49. Mutex_impl()
  50. {
  51. pthread_mutex_init(&mutex, 0);
  52. #ifdef PTHREAD_DEBUG
  53. owner = 0;
  54. #endif
  55. }
  56. void lock()
  57. {
  58. #ifdef PTHREAD_DEBUG
  59. pthread_t self = pthread_self();
  60. arts_assert(owner != self);
  61. #endif
  62. pthread_mutex_lock(&mutex);
  63. #ifdef PTHREAD_DEBUG
  64. arts_assert(!owner);
  65. owner = self;
  66. #endif
  67. }
  68. bool tryLock()
  69. {
  70. #ifdef PTHREAD_DEBUG
  71. pthread_t self = pthread_self();
  72. arts_assert(owner != self);
  73. #endif
  74. int result = pthread_mutex_trylock(&mutex);
  75. #ifdef PTHREAD_DEBUG
  76. if(result == 0)
  77. {
  78. arts_assert(!owner);
  79. owner = self;
  80. }
  81. #endif
  82. return(result == 0);
  83. }
  84. void unlock()
  85. {
  86. #ifdef PTHREAD_DEBUG
  87. arts_assert(owner == pthread_self());
  88. owner = 0;
  89. #endif
  90. pthread_mutex_unlock(&mutex);
  91. }
  92. };
  93. class RecMutex_impl : public Arts::Mutex_impl {
  94. protected:
  95. friend class ThreadCondition_impl;
  96. pthread_mutex_t mutex;
  97. pthread_t owner;
  98. int count;
  99. public:
  100. RecMutex_impl()
  101. {
  102. pthread_mutex_init(&mutex, 0);
  103. owner = 0;
  104. count = 0;
  105. }
  106. void lock()
  107. {
  108. pthread_t self = pthread_self();
  109. if(owner != self)
  110. {
  111. pthread_mutex_lock(&mutex);
  112. #ifdef PTHREAD_DEBUG
  113. arts_assert(count == 0);
  114. arts_assert(!owner);
  115. #endif
  116. owner = self;
  117. }
  118. count++;
  119. }
  120. bool tryLock()
  121. {
  122. pthread_t self = pthread_self();
  123. if(owner != self)
  124. {
  125. int result = pthread_mutex_trylock(&mutex);
  126. if(result != 0)
  127. return false;
  128. #ifdef PTHREAD_DEBUG
  129. arts_assert(count == 0);
  130. arts_assert(!owner);
  131. #endif
  132. owner = self;
  133. }
  134. count++;
  135. return true;
  136. }
  137. void unlock()
  138. {
  139. #ifdef PTHREAD_DEBUG
  140. arts_assert(owner == pthread_self());
  141. arts_assert(count > 0);
  142. #endif
  143. count--;
  144. if(count == 0)
  145. {
  146. owner = 0;
  147. pthread_mutex_unlock(&mutex);
  148. }
  149. }
  150. };
  151. class Thread_impl : public Arts::Thread_impl {
  152. protected:
  153. friend class PosixThreads;
  154. pthread_t pthread;
  155. Thread *thread;
  156. public:
  157. Thread_impl(Thread *thread) : thread(thread) {
  158. }
  159. void setPriority(int priority) {
  160. struct sched_param sp;
  161. sp.sched_priority = priority;
  162. if (pthread_setschedparam(pthread, SCHED_FIFO, &sp))
  163. arts_debug("Thread::setPriority: sched_setscheduler failed");
  164. }
  165. static pthread_key_t privateDataKey;
  166. static void *threadStartInternal(void *impl)
  167. {
  168. pthread_setspecific(privateDataKey, impl);
  169. ((Thread_impl *)impl)->thread->run();
  170. return 0;
  171. }
  172. void start() {
  173. pthread_create(&pthread,0,threadStartInternal,this);
  174. }
  175. void waitDone() {
  176. void *foo;
  177. pthread_join(pthread,&foo);
  178. }
  179. };
  180. pthread_key_t Thread_impl::privateDataKey;
  181. class ThreadCondition_impl : public Arts::ThreadCondition_impl {
  182. protected:
  183. pthread_cond_t cond;
  184. public:
  185. ThreadCondition_impl() {
  186. pthread_cond_init(&cond, 0);
  187. }
  188. ~ThreadCondition_impl() {
  189. pthread_cond_destroy(&cond);
  190. }
  191. void wakeOne() {
  192. pthread_cond_signal(&cond);
  193. }
  194. void wakeAll() {
  195. pthread_cond_broadcast(&cond);
  196. }
  197. void wait(Arts::Mutex_impl *mutex) {
  198. #ifdef PTHREAD_DEBUG
  199. pthread_t self = pthread_self();
  200. arts_assert(((Mutex_impl *)mutex)->owner == self);
  201. ((Mutex_impl *)mutex)->owner = 0;
  202. #endif
  203. pthread_cond_wait(&cond, &((Mutex_impl*)mutex)->mutex);
  204. #ifdef PTHREAD_DEBUG
  205. arts_assert(((Mutex_impl *)mutex)->owner == 0);
  206. ((Mutex_impl *)mutex)->owner = self;
  207. #endif
  208. }
  209. };
  210. class Semaphore_impl : public Arts::Semaphore_impl
  211. {
  212. private:
  213. sem_t semaphore;
  214. public:
  215. Semaphore_impl(int shared, int count) {
  216. sem_init(&semaphore, shared, count);
  217. }
  218. ~Semaphore_impl() {
  219. sem_destroy(&semaphore);
  220. }
  221. void wait() {
  222. sem_wait(&semaphore);
  223. }
  224. int tryWait() {
  225. return sem_trywait(&semaphore);
  226. }
  227. void post() {
  228. sem_post(&semaphore);
  229. }
  230. int getValue() {
  231. int retval;
  232. sem_getvalue(&semaphore, &retval);
  233. return retval;
  234. }
  235. };
  236. class PosixThreads : public SystemThreads {
  237. private:
  238. pthread_t mainThread;
  239. public:
  240. PosixThreads() {
  241. mainThread = pthread_self();
  242. }
  243. bool isMainThread() {
  244. return pthread_equal(pthread_self(), mainThread);
  245. }
  246. Arts::Mutex_impl *createMutex_impl() {
  247. return new Mutex_impl();
  248. }
  249. Arts::Mutex_impl *createRecMutex_impl() {
  250. return new RecMutex_impl();
  251. }
  252. Arts::Thread_impl *createThread_impl(Arts::Thread *thread) {
  253. return new Thread_impl(thread);
  254. }
  255. Arts::ThreadCondition_impl *createThreadCondition_impl() {
  256. return new ThreadCondition_impl();
  257. }
  258. Thread *getCurrentThread() {
  259. void *data = pthread_getspecific(Thread_impl::privateDataKey);
  260. if(data)
  261. return ((Thread_impl *)data)->thread;
  262. else
  263. return 0; /* main thread */
  264. }
  265. Arts::Semaphore_impl *createSemaphore_impl(int shared, int count) {
  266. return new Semaphore_impl(shared, count);
  267. }
  268. };
  269. // set posix threads on startup
  270. static class SetSystemThreads {
  271. private:
  272. PosixThreads posixThreads;
  273. public:
  274. SetSystemThreads() {
  275. if(pthread_key_create(&Thread_impl::privateDataKey, 0))
  276. arts_debug("SystemThreads init: pthread_key_create failed");
  277. SystemThreads::init(&posixThreads);
  278. }
  279. ~SetSystemThreads() {
  280. SystemThreads::init(0);
  281. if(pthread_key_delete(Thread_impl::privateDataKey))
  282. arts_debug("SystemThreads init: pthread_key_delete failed");
  283. }
  284. } initOnStartup;
  285. /* -fast- locking for gsl on platforms with unix98 support */
  286. #if (GSL_HAVE_MUTEXATTR_SETTYPE > 0)
  287. static void pth_mutex_init (GslMutex *mutex)
  288. {
  289. /* need NULL attribute here, which is the fast mutex on glibc
  290. * and cannot be chosen through the pthread_mutexattr_settype()
  291. */
  292. pthread_mutex_init ((pthread_mutex_t*) mutex, NULL);
  293. }
  294. static void pth_rec_mutex_init (GslRecMutex *mutex)
  295. {
  296. pthread_mutexattr_t attr;
  297. pthread_mutexattr_init (&attr);
  298. pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
  299. pthread_mutex_init ((pthread_mutex_t*) mutex, &attr);
  300. pthread_mutexattr_destroy (&attr);
  301. }
  302. static void pth_rec_cond_init (GslCond *cond)
  303. {
  304. pthread_cond_init ((pthread_cond_t*) cond, NULL);
  305. }
  306. static void pth_rec_cond_wait_timed (GslCond *cond, GslMutex *mutex,
  307. gulong abs_secs, gulong abs_usecs)
  308. {
  309. struct ::timespec abstime;
  310. abstime.tv_sec = abs_secs;
  311. abstime.tv_nsec = abs_usecs * 1000;
  312. pthread_cond_timedwait ((pthread_cond_t*) cond, (pthread_mutex_t*) mutex, &abstime);
  313. }
  314. static GslMutexTable pth_mutex_table = {
  315. pth_mutex_init,
  316. (void (*) (GslMutex*)) pthread_mutex_lock,
  317. (int (*) (GslMutex*)) pthread_mutex_trylock,
  318. (void (*) (GslMutex*)) pthread_mutex_unlock,
  319. (void (*) (GslMutex*)) pthread_mutex_destroy,
  320. pth_rec_mutex_init,
  321. (void (*) (GslRecMutex*)) pthread_mutex_lock,
  322. (int (*) (GslRecMutex*)) pthread_mutex_trylock,
  323. (void (*) (GslRecMutex*)) pthread_mutex_unlock,
  324. (void (*) (GslRecMutex*)) pthread_mutex_destroy,
  325. pth_rec_cond_init,
  326. (void (*) (GslCond*)) pthread_cond_signal,
  327. (void (*) (GslCond*)) pthread_cond_broadcast,
  328. (void (*) (GslCond*, GslMutex*)) pthread_cond_wait,
  329. pth_rec_cond_wait_timed,
  330. (void (*) (GslCond*)) pthread_cond_destroy,
  331. };
  332. static class SetGslMutexTable {
  333. public:
  334. SetGslMutexTable()
  335. {
  336. gslGlobalMutexTable = &pth_mutex_table;
  337. }
  338. } initGslMutexTable;
  339. #endif
  340. }
  341. }
  342. #endif