add queen mary DSP library
[ardour.git] / libs / qm-dsp / thread / Thread.cpp
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
2
3 /*
4     QM DSP Library
5
6     Centre for Digital Music, Queen Mary, University of London.
7     This file copyright Chris Cannam, used with permission.
8 */
9
10 #include "Thread.h"
11
12 #include <iostream>
13 #include <cstdlib>
14
15 #ifdef USE_PTHREADS
16 #include <sys/time.h>
17 #include <time.h>
18 #endif
19
20 using std::cerr;
21 using std::endl;
22 using std::string;
23
24 #ifdef _WIN32
25
26 Thread::Thread() :
27     m_id(0),
28     m_extant(false)
29 {
30 #ifdef DEBUG_THREAD
31     cerr << "THREAD DEBUG: Created thread object " << this << endl;
32 #endif
33 }
34
35 Thread::~Thread()
36 {
37 #ifdef DEBUG_THREAD
38     cerr << "THREAD DEBUG: Destroying thread object " << this << ", id " << m_id << endl;
39 #endif
40     if (m_extant) {
41         WaitForSingleObject(m_id, INFINITE);
42     }
43 #ifdef DEBUG_THREAD
44     cerr << "THREAD DEBUG: Destroyed thread object " << this << endl;
45 #endif
46 }
47
48 void
49 Thread::start()
50 {
51     m_id = CreateThread(NULL, 0, staticRun, this, 0, 0);
52     if (!m_id) {
53         cerr << "ERROR: thread creation failed" << endl;
54         exit(1);
55     } else {
56 #ifdef DEBUG_THREAD
57         cerr << "THREAD DEBUG: Created thread " << m_id << " for thread object " << this << endl;
58 #endif
59         m_extant = true;
60     }
61 }    
62
63 void 
64 Thread::wait()
65 {
66     if (m_extant) {
67 #ifdef DEBUG_THREAD
68         cerr << "THREAD DEBUG: Waiting on thread " << m_id << " for thread object " << this << endl;
69 #endif
70         WaitForSingleObject(m_id, INFINITE);
71 #ifdef DEBUG_THREAD
72         cerr << "THREAD DEBUG: Waited on thread " << m_id << " for thread object " << this << endl;
73 #endif
74         m_extant = false;
75     }
76 }
77
78 Thread::Id
79 Thread::id()
80 {
81     return m_id;
82 }
83
84 bool
85 Thread::threadingAvailable()
86 {
87     return true;
88 }
89
90 DWORD
91 Thread::staticRun(LPVOID arg)
92 {
93     Thread *thread = static_cast<Thread *>(arg);
94 #ifdef DEBUG_THREAD
95     cerr << "THREAD DEBUG: " << (void *)GetCurrentThreadId() << ": Running thread " << thread->m_id << " for thread object " << thread << endl;
96 #endif
97     thread->run();
98     return 0;
99 }
100
101 Mutex::Mutex()
102 #ifndef NO_THREAD_CHECKS
103     :
104     m_lockedBy(-1)
105 #endif
106 {
107     m_mutex = CreateMutex(NULL, FALSE, NULL);
108 #ifdef DEBUG_MUTEX
109     cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Initialised mutex " << &m_mutex << endl;
110 #endif
111 }
112
113 Mutex::~Mutex()
114 {
115 #ifdef DEBUG_MUTEX
116     cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Destroying mutex " << &m_mutex << endl;
117 #endif
118     CloseHandle(m_mutex);
119 }
120
121 void
122 Mutex::lock()
123 {
124 #ifndef NO_THREAD_CHECKS
125     DWORD tid = GetCurrentThreadId();
126     if (m_lockedBy == tid) {
127         cerr << "ERROR: Deadlock on mutex " << &m_mutex << endl;
128     }
129 #endif
130 #ifdef DEBUG_MUTEX
131     cerr << "MUTEX DEBUG: " << (void *)tid << ": Want to lock mutex " << &m_mutex << endl;
132 #endif
133     WaitForSingleObject(m_mutex, INFINITE);
134 #ifndef NO_THREAD_CHECKS
135     m_lockedBy = tid;
136 #endif
137 #ifdef DEBUG_MUTEX
138     cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << endl;
139 #endif
140 }
141
142 void
143 Mutex::unlock()
144 {
145 #ifndef NO_THREAD_CHECKS
146     DWORD tid = GetCurrentThreadId();
147     if (m_lockedBy != tid) {
148         cerr << "ERROR: Mutex " << &m_mutex << " not owned by unlocking thread" << endl;
149         return;
150     }
151 #endif
152 #ifdef DEBUG_MUTEX
153     cerr << "MUTEX DEBUG: " << (void *)tid << ": Unlocking mutex " << &m_mutex << endl;
154 #endif
155 #ifndef NO_THREAD_CHECKS
156     m_lockedBy = -1;
157 #endif
158     ReleaseMutex(m_mutex);
159 }
160
161 bool
162 Mutex::trylock()
163 {
164 #ifndef NO_THREAD_CHECKS
165     DWORD tid = GetCurrentThreadId();
166 #endif
167     DWORD result = WaitForSingleObject(m_mutex, 0);
168     if (result == WAIT_TIMEOUT || result == WAIT_FAILED) {
169 #ifdef DEBUG_MUTEX
170         cerr << "MUTEX DEBUG: " << (void *)tid << ": Mutex " << &m_mutex << " unavailable" << endl;
171 #endif
172         return false;
173     } else {
174 #ifndef NO_THREAD_CHECKS
175         m_lockedBy = tid;
176 #endif
177 #ifdef DEBUG_MUTEX
178         cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << " (from trylock)" << endl;
179 #endif
180         return true;
181     }
182 }
183
184 Condition::Condition(string name) :
185     m_locked(false)
186 #ifdef DEBUG_CONDITION
187     , m_name(name)
188 #endif
189 {
190     m_mutex = CreateMutex(NULL, FALSE, NULL);
191     m_condition = CreateEvent(NULL, FALSE, FALSE, NULL);
192 #ifdef DEBUG_CONDITION
193     cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Initialised condition " << &m_condition << " \"" << m_name << "\"" << endl;
194 #endif
195 }
196
197 Condition::~Condition()
198 {
199 #ifdef DEBUG_CONDITION
200     cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Destroying condition " << &m_condition << " \"" << m_name << "\"" << endl;
201 #endif
202     if (m_locked) ReleaseMutex(m_mutex);
203     CloseHandle(m_condition);
204     CloseHandle(m_mutex);
205 }
206
207 void
208 Condition::lock()
209 {
210 #ifdef DEBUG_CONDITION
211     cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Want to lock " << &m_condition << " \"" << m_name << "\"" << endl;
212 #endif
213     WaitForSingleObject(m_mutex, INFINITE);
214     m_locked = true;
215 #ifdef DEBUG_CONDITION
216     cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Locked " << &m_condition << " \"" << m_name << "\"" << endl;
217 #endif
218 }
219
220 void
221 Condition::unlock()
222 {
223     if (!m_locked) {
224 #ifdef DEBUG_CONDITION
225         cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Not locked " << &m_condition << " \"" << m_name << "\"" << endl;
226 #endif
227         return;
228     }
229 #ifdef DEBUG_CONDITION
230     cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Unlocking " << &m_condition << " \"" << m_name << "\"" << endl;
231 #endif
232     m_locked = false;
233     ReleaseMutex(m_mutex);
234 }
235
236 void 
237 Condition::wait(int us)
238 {
239     if (us == 0) {
240
241 #ifdef DEBUG_CONDITION
242         cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Waiting on " << &m_condition << " \"" << m_name << "\"" << endl;
243 #endif
244         SignalObjectAndWait(m_mutex, m_condition, INFINITE, FALSE);
245         WaitForSingleObject(m_mutex, INFINITE);
246
247     } else {
248
249         DWORD ms = us / 1000;
250         if (us > 0 && ms == 0) ms = 1;
251     
252 #ifdef DEBUG_CONDITION
253         cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Timed waiting on " << &m_condition << " \"" << m_name << "\"" << endl;
254 #endif
255         SignalObjectAndWait(m_mutex, m_condition, ms, FALSE);
256         WaitForSingleObject(m_mutex, INFINITE);
257     }
258
259 #ifdef DEBUG_CONDITION
260     cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Wait done on " << &m_condition << " \"" << m_name << "\"" << endl;
261 #endif
262
263     m_locked = true;
264 }
265
266 void
267 Condition::signal()
268 {
269 #ifdef DEBUG_CONDITION
270     cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Signalling " << &m_condition << " \"" << m_name << "\"" << endl;
271 #endif
272     SetEvent(m_condition);
273 }
274
275 #else /* !_WIN32 */
276
277 #ifdef USE_PTHREADS
278
279 Thread::Thread() :
280     m_id(0),
281     m_extant(false)
282 {
283 #ifdef DEBUG_THREAD
284     cerr << "THREAD DEBUG: Created thread object " << this << endl;
285 #endif
286 }
287
288 Thread::~Thread()
289 {
290 #ifdef DEBUG_THREAD
291     cerr << "THREAD DEBUG: Destroying thread object " << this << ", id " << m_id << endl;
292 #endif
293     if (m_extant) {
294         pthread_join(m_id, 0);
295     }
296 #ifdef DEBUG_THREAD
297     cerr << "THREAD DEBUG: Destroyed thread object " << this << endl;
298 #endif
299 }
300
301 void
302 Thread::start()
303 {
304     if (pthread_create(&m_id, 0, staticRun, this)) {
305         cerr << "ERROR: thread creation failed" << endl;
306         exit(1);
307     } else {
308 #ifdef DEBUG_THREAD
309         cerr << "THREAD DEBUG: Created thread " << m_id << " for thread object " << this << endl;
310 #endif
311         m_extant = true;
312     }
313 }    
314
315 void 
316 Thread::wait()
317 {
318     if (m_extant) {
319 #ifdef DEBUG_THREAD
320         cerr << "THREAD DEBUG: Waiting on thread " << m_id << " for thread object " << this << endl;
321 #endif
322         pthread_join(m_id, 0);
323 #ifdef DEBUG_THREAD
324         cerr << "THREAD DEBUG: Waited on thread " << m_id << " for thread object " << this << endl;
325 #endif
326         m_extant = false;
327     }
328 }
329
330 Thread::Id
331 Thread::id()
332 {
333     return m_id;
334 }
335
336 bool
337 Thread::threadingAvailable()
338 {
339     return true;
340 }
341
342 void *
343 Thread::staticRun(void *arg)
344 {
345     Thread *thread = static_cast<Thread *>(arg);
346 #ifdef DEBUG_THREAD
347     cerr << "THREAD DEBUG: " << (void *)pthread_self() << ": Running thread " << thread->m_id << " for thread object " << thread << endl;
348 #endif
349     thread->run();
350     return 0;
351 }
352
353 Mutex::Mutex()
354 #ifndef NO_THREAD_CHECKS
355     :
356     m_lockedBy(0),
357     m_locked(false)
358 #endif
359 {
360     pthread_mutex_init(&m_mutex, 0);
361 #ifdef DEBUG_MUTEX
362     cerr << "MUTEX DEBUG: " << (void *)pthread_self() << ": Initialised mutex " << &m_mutex << endl;
363 #endif
364 }
365
366 Mutex::~Mutex()
367 {
368 #ifdef DEBUG_MUTEX
369     cerr << "MUTEX DEBUG: " << (void *)pthread_self() << ": Destroying mutex " << &m_mutex << endl;
370 #endif
371     pthread_mutex_destroy(&m_mutex);
372 }
373
374 void
375 Mutex::lock()
376 {
377 #ifndef NO_THREAD_CHECKS
378     pthread_t tid = pthread_self();
379     if (m_locked && m_lockedBy == tid) {
380         cerr << "ERROR: Deadlock on mutex " << &m_mutex << endl;
381     }
382 #endif
383 #ifdef DEBUG_MUTEX
384     cerr << "MUTEX DEBUG: " << (void *)tid << ": Want to lock mutex " << &m_mutex << endl;
385 #endif
386     pthread_mutex_lock(&m_mutex);
387 #ifndef NO_THREAD_CHECKS
388     m_lockedBy = tid;
389     m_locked = true;
390 #endif
391 #ifdef DEBUG_MUTEX
392     cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << endl;
393 #endif
394 }
395
396 void
397 Mutex::unlock()
398 {
399 #ifndef NO_THREAD_CHECKS
400     pthread_t tid = pthread_self();
401     if (!m_locked) {
402         cerr << "ERROR: Mutex " << &m_mutex << " not locked in unlock" << endl;
403         return;
404     } else if (m_lockedBy != tid) {
405         cerr << "ERROR: Mutex " << &m_mutex << " not owned by unlocking thread" << endl;
406         return;
407     }
408 #endif
409 #ifdef DEBUG_MUTEX
410     cerr << "MUTEX DEBUG: " << (void *)tid << ": Unlocking mutex " << &m_mutex << endl;
411 #endif
412 #ifndef NO_THREAD_CHECKS
413     m_locked = false;
414 #endif
415     pthread_mutex_unlock(&m_mutex);
416 }
417
418 bool
419 Mutex::trylock()
420 {
421 #ifndef NO_THREAD_CHECKS
422     pthread_t tid = pthread_self();
423 #endif
424     if (pthread_mutex_trylock(&m_mutex)) {
425 #ifdef DEBUG_MUTEX
426         cerr << "MUTEX DEBUG: " << (void *)tid << ": Mutex " << &m_mutex << " unavailable" << endl;
427 #endif
428         return false;
429     } else {
430 #ifndef NO_THREAD_CHECKS
431         m_lockedBy = tid;
432         m_locked = true;
433 #endif
434 #ifdef DEBUG_MUTEX
435         cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << " (from trylock)" << endl;
436 #endif
437         return true;
438     }
439 }
440
441 Condition::Condition(string name) :
442     m_locked(false)
443 #ifdef DEBUG_CONDITION
444     , m_name(name)
445 #endif
446 {
447     pthread_mutex_init(&m_mutex, 0);
448     pthread_cond_init(&m_condition, 0);
449 #ifdef DEBUG_CONDITION
450     cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Initialised condition " << &m_condition << " \"" << m_name << "\"" << endl;
451 #endif
452 }
453
454 Condition::~Condition()
455 {
456 #ifdef DEBUG_CONDITION
457     cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Destroying condition " << &m_condition << " \"" << m_name << "\"" << endl;
458 #endif
459     if (m_locked) pthread_mutex_unlock(&m_mutex);
460     pthread_cond_destroy(&m_condition);
461     pthread_mutex_destroy(&m_mutex);
462 }
463
464 void
465 Condition::lock()
466 {
467 #ifdef DEBUG_CONDITION
468     cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Want to lock " << &m_condition << " \"" << m_name << "\"" << endl;
469 #endif
470     pthread_mutex_lock(&m_mutex);
471     m_locked = true;
472 #ifdef DEBUG_CONDITION
473     cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Locked " << &m_condition << " \"" << m_name << "\"" << endl;
474 #endif
475 }
476
477 void
478 Condition::unlock()
479 {
480     if (!m_locked) {
481 #ifdef DEBUG_CONDITION
482         cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Not locked " << &m_condition << " \"" << m_name << "\"" << endl;
483 #endif
484         return;
485     }
486 #ifdef DEBUG_CONDITION
487     cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Unlocking " << &m_condition << " \"" << m_name << "\"" << endl;
488 #endif
489     m_locked = false;
490     pthread_mutex_unlock(&m_mutex);
491 }
492
493 void 
494 Condition::wait(int us)
495 {
496     if (us == 0) {
497
498 #ifdef DEBUG_CONDITION
499         cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Waiting on " << &m_condition << " \"" << m_name << "\"" << endl;
500 #endif
501         pthread_cond_wait(&m_condition, &m_mutex);
502
503     } else {
504
505         struct timeval now;
506         gettimeofday(&now, 0);
507
508         now.tv_usec += us;
509         while (now.tv_usec > 1000000) {
510             now.tv_usec -= 1000000;
511             ++now.tv_sec;
512         }
513
514         struct timespec timeout;
515         timeout.tv_sec = now.tv_sec;
516         timeout.tv_nsec = now.tv_usec * 1000;
517     
518 #ifdef DEBUG_CONDITION
519         cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Timed waiting on " << &m_condition << " \"" << m_name << "\"" << endl;
520 #endif
521         pthread_cond_timedwait(&m_condition, &m_mutex, &timeout);
522     }
523
524 #ifdef DEBUG_CONDITION
525     cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Wait done on " << &m_condition << " \"" << m_name << "\"" << endl;
526 #endif
527
528     m_locked = true;
529 }
530
531 void
532 Condition::signal()
533 {
534 #ifdef DEBUG_CONDITION
535     cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Signalling " << &m_condition << " \"" << m_name << "\"" << endl;
536 #endif
537     pthread_cond_signal(&m_condition);
538 }
539
540 #else /* !USE_PTHREADS */
541
542 Thread::Thread()
543 {
544 }
545
546 Thread::~Thread()
547 {
548 }
549
550 void
551 Thread::start()
552 {
553     abort();
554 }    
555
556 void 
557 Thread::wait()
558 {
559     abort();
560 }
561
562 Thread::Id
563 Thread::id()
564 {
565     abort();
566 }
567
568 bool
569 Thread::threadingAvailable()
570 {
571     return false;
572 }
573
574 Mutex::Mutex()
575 {
576 }
577
578 Mutex::~Mutex()
579 {
580 }
581
582 void
583 Mutex::lock()
584 {
585     abort();
586 }
587
588 void
589 Mutex::unlock()
590 {
591     abort();
592 }
593
594 bool
595 Mutex::trylock()
596 {
597     abort();
598 }
599
600 Condition::Condition(const char *)
601 {
602 }
603
604 Condition::~Condition()
605 {
606 }
607
608 void
609 Condition::lock()
610 {
611     abort();
612 }
613
614 void 
615 Condition::wait(int us)
616 {
617     abort();
618 }
619
620 void
621 Condition::signal()
622 {
623     abort();
624 }
625
626 #endif /* !USE_PTHREADS */
627 #endif /* !_WIN32 */
628
629 MutexLocker::MutexLocker(Mutex *mutex) :
630     m_mutex(mutex)
631 {
632     if (m_mutex) {
633         m_mutex->lock();
634     }
635 }
636
637 MutexLocker::~MutexLocker()
638 {
639     if (m_mutex) {
640         m_mutex->unlock();
641     }
642 }
643