c@287: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ c@287: c@287: /* c@287: QM DSP Library c@287: c@287: Centre for Digital Music, Queen Mary, University of London. c@287: This file copyright Chris Cannam, used with permission. c@287: */ c@287: c@287: #include "Thread.h" c@287: c@287: #include c@287: #include c@287: c@287: #ifdef USE_PTHREADS c@287: #include c@287: #include c@287: #endif c@287: c@287: using std::cerr; c@287: using std::endl; c@287: using std::string; c@287: c@287: #ifdef _WIN32 c@287: c@287: Thread::Thread() : c@287: m_id(0), c@287: m_extant(false) c@287: { c@287: #ifdef DEBUG_THREAD c@287: cerr << "THREAD DEBUG: Created thread object " << this << endl; c@287: #endif c@287: } c@287: c@287: Thread::~Thread() c@287: { c@287: #ifdef DEBUG_THREAD c@287: cerr << "THREAD DEBUG: Destroying thread object " << this << ", id " << m_id << endl; c@287: #endif c@287: if (m_extant) { c@287: WaitForSingleObject(m_id, INFINITE); c@287: } c@287: #ifdef DEBUG_THREAD c@287: cerr << "THREAD DEBUG: Destroyed thread object " << this << endl; c@287: #endif c@287: } c@287: c@287: void c@287: Thread::start() c@287: { c@287: m_id = CreateThread(NULL, 0, staticRun, this, 0, 0); c@287: if (!m_id) { c@287: cerr << "ERROR: thread creation failed" << endl; c@287: exit(1); c@287: } else { c@287: #ifdef DEBUG_THREAD c@287: cerr << "THREAD DEBUG: Created thread " << m_id << " for thread object " << this << endl; c@287: #endif c@287: m_extant = true; c@287: } c@287: } c@287: c@287: void c@287: Thread::wait() c@287: { c@287: if (m_extant) { c@287: #ifdef DEBUG_THREAD c@287: cerr << "THREAD DEBUG: Waiting on thread " << m_id << " for thread object " << this << endl; c@287: #endif c@287: WaitForSingleObject(m_id, INFINITE); c@287: #ifdef DEBUG_THREAD c@287: cerr << "THREAD DEBUG: Waited on thread " << m_id << " for thread object " << this << endl; c@287: #endif c@287: m_extant = false; c@287: } c@287: } c@287: c@287: Thread::Id c@287: Thread::id() c@287: { c@287: return m_id; c@287: } c@287: c@287: bool c@287: Thread::threadingAvailable() c@287: { c@287: return true; c@287: } c@287: c@287: DWORD c@287: Thread::staticRun(LPVOID arg) c@287: { c@287: Thread *thread = static_cast(arg); c@287: #ifdef DEBUG_THREAD c@287: cerr << "THREAD DEBUG: " << (void *)GetCurrentThreadId() << ": Running thread " << thread->m_id << " for thread object " << thread << endl; c@287: #endif c@287: thread->run(); c@287: return 0; c@287: } c@287: c@287: Mutex::Mutex() c@287: #ifndef NO_THREAD_CHECKS c@287: : c@287: m_lockedBy(-1) c@287: #endif c@287: { c@287: m_mutex = CreateMutex(NULL, FALSE, NULL); c@287: #ifdef DEBUG_MUTEX c@287: cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Initialised mutex " << &m_mutex << endl; c@287: #endif c@287: } c@287: c@287: Mutex::~Mutex() c@287: { c@287: #ifdef DEBUG_MUTEX c@287: cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Destroying mutex " << &m_mutex << endl; c@287: #endif c@287: CloseHandle(m_mutex); c@287: } c@287: c@287: void c@287: Mutex::lock() c@287: { c@287: #ifndef NO_THREAD_CHECKS c@287: DWORD tid = GetCurrentThreadId(); c@287: if (m_lockedBy == tid) { c@287: cerr << "ERROR: Deadlock on mutex " << &m_mutex << endl; c@287: } c@287: #endif c@287: #ifdef DEBUG_MUTEX c@287: cerr << "MUTEX DEBUG: " << (void *)tid << ": Want to lock mutex " << &m_mutex << endl; c@287: #endif c@287: WaitForSingleObject(m_mutex, INFINITE); c@287: #ifndef NO_THREAD_CHECKS c@287: m_lockedBy = tid; c@287: #endif c@287: #ifdef DEBUG_MUTEX c@287: cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << endl; c@287: #endif c@287: } c@287: c@287: void c@287: Mutex::unlock() c@287: { c@287: #ifndef NO_THREAD_CHECKS c@287: DWORD tid = GetCurrentThreadId(); c@287: if (m_lockedBy != tid) { c@287: cerr << "ERROR: Mutex " << &m_mutex << " not owned by unlocking thread" << endl; c@287: return; c@287: } c@287: #endif c@287: #ifdef DEBUG_MUTEX c@287: cerr << "MUTEX DEBUG: " << (void *)tid << ": Unlocking mutex " << &m_mutex << endl; c@287: #endif c@287: #ifndef NO_THREAD_CHECKS c@287: m_lockedBy = -1; c@287: #endif c@287: ReleaseMutex(m_mutex); c@287: } c@287: c@287: bool c@287: Mutex::trylock() c@287: { c@287: #ifndef NO_THREAD_CHECKS c@287: DWORD tid = GetCurrentThreadId(); c@287: #endif c@287: DWORD result = WaitForSingleObject(m_mutex, 0); c@287: if (result == WAIT_TIMEOUT || result == WAIT_FAILED) { c@287: #ifdef DEBUG_MUTEX c@287: cerr << "MUTEX DEBUG: " << (void *)tid << ": Mutex " << &m_mutex << " unavailable" << endl; c@287: #endif c@287: return false; c@287: } else { c@287: #ifndef NO_THREAD_CHECKS c@287: m_lockedBy = tid; c@287: #endif c@287: #ifdef DEBUG_MUTEX c@287: cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << " (from trylock)" << endl; c@287: #endif c@287: return true; c@287: } c@287: } c@287: c@287: Condition::Condition(string name) : c@287: m_locked(false) c@287: #ifdef DEBUG_CONDITION c@287: , m_name(name) c@287: #endif c@287: { c@287: m_mutex = CreateMutex(NULL, FALSE, NULL); c@287: m_condition = CreateEvent(NULL, FALSE, FALSE, NULL); c@287: #ifdef DEBUG_CONDITION c@287: cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Initialised condition " << &m_condition << " \"" << m_name << "\"" << endl; c@287: #endif c@287: } c@287: c@287: Condition::~Condition() c@287: { c@287: #ifdef DEBUG_CONDITION c@287: cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Destroying condition " << &m_condition << " \"" << m_name << "\"" << endl; c@287: #endif c@287: if (m_locked) ReleaseMutex(m_mutex); c@287: CloseHandle(m_condition); c@287: CloseHandle(m_mutex); c@287: } c@287: c@287: void c@287: Condition::lock() c@287: { c@287: #ifdef DEBUG_CONDITION c@287: cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Want to lock " << &m_condition << " \"" << m_name << "\"" << endl; c@287: #endif c@287: WaitForSingleObject(m_mutex, INFINITE); c@287: m_locked = true; c@287: #ifdef DEBUG_CONDITION c@287: cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Locked " << &m_condition << " \"" << m_name << "\"" << endl; c@287: #endif c@287: } c@287: c@287: void c@287: Condition::unlock() c@287: { c@287: if (!m_locked) { c@287: #ifdef DEBUG_CONDITION c@287: cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Not locked " << &m_condition << " \"" << m_name << "\"" << endl; c@287: #endif c@287: return; c@287: } c@287: #ifdef DEBUG_CONDITION c@287: cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Unlocking " << &m_condition << " \"" << m_name << "\"" << endl; c@287: #endif c@287: m_locked = false; c@287: ReleaseMutex(m_mutex); c@287: } c@287: c@287: void c@287: Condition::wait(int us) c@287: { c@287: if (us == 0) { c@287: c@287: #ifdef DEBUG_CONDITION c@287: cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Waiting on " << &m_condition << " \"" << m_name << "\"" << endl; c@287: #endif c@287: SignalObjectAndWait(m_mutex, m_condition, INFINITE, FALSE); c@287: WaitForSingleObject(m_mutex, INFINITE); c@287: c@287: } else { c@287: c@287: DWORD ms = us / 1000; c@287: if (us > 0 && ms == 0) ms = 1; c@287: c@287: #ifdef DEBUG_CONDITION c@287: cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Timed waiting on " << &m_condition << " \"" << m_name << "\"" << endl; c@287: #endif c@287: SignalObjectAndWait(m_mutex, m_condition, ms, FALSE); c@287: WaitForSingleObject(m_mutex, INFINITE); c@287: } c@287: c@287: #ifdef DEBUG_CONDITION c@287: cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Wait done on " << &m_condition << " \"" << m_name << "\"" << endl; c@287: #endif c@296: c@296: m_locked = true; c@287: } c@287: c@287: void c@287: Condition::signal() c@287: { c@287: #ifdef DEBUG_CONDITION c@287: cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Signalling " << &m_condition << " \"" << m_name << "\"" << endl; c@287: #endif c@287: SetEvent(m_condition); c@287: } c@287: c@287: #else /* !_WIN32 */ c@287: c@287: #ifdef USE_PTHREADS c@287: c@287: Thread::Thread() : c@287: m_id(0), c@287: m_extant(false) c@287: { c@287: #ifdef DEBUG_THREAD c@287: cerr << "THREAD DEBUG: Created thread object " << this << endl; c@287: #endif c@287: } c@287: c@287: Thread::~Thread() c@287: { c@287: #ifdef DEBUG_THREAD c@287: cerr << "THREAD DEBUG: Destroying thread object " << this << ", id " << m_id << endl; c@287: #endif c@287: if (m_extant) { c@287: pthread_join(m_id, 0); c@287: } c@287: #ifdef DEBUG_THREAD c@287: cerr << "THREAD DEBUG: Destroyed thread object " << this << endl; c@287: #endif c@287: } c@287: c@287: void c@287: Thread::start() c@287: { c@287: if (pthread_create(&m_id, 0, staticRun, this)) { c@287: cerr << "ERROR: thread creation failed" << endl; c@287: exit(1); c@287: } else { c@287: #ifdef DEBUG_THREAD c@287: cerr << "THREAD DEBUG: Created thread " << m_id << " for thread object " << this << endl; c@287: #endif c@287: m_extant = true; c@287: } c@287: } c@287: c@287: void c@287: Thread::wait() c@287: { c@287: if (m_extant) { c@287: #ifdef DEBUG_THREAD c@287: cerr << "THREAD DEBUG: Waiting on thread " << m_id << " for thread object " << this << endl; c@287: #endif c@287: pthread_join(m_id, 0); c@287: #ifdef DEBUG_THREAD c@287: cerr << "THREAD DEBUG: Waited on thread " << m_id << " for thread object " << this << endl; c@287: #endif c@287: m_extant = false; c@287: } c@287: } c@287: c@287: Thread::Id c@287: Thread::id() c@287: { c@287: return m_id; c@287: } c@287: c@287: bool c@287: Thread::threadingAvailable() c@287: { c@287: return true; c@287: } c@287: c@287: void * c@287: Thread::staticRun(void *arg) c@287: { c@287: Thread *thread = static_cast(arg); c@287: #ifdef DEBUG_THREAD c@287: cerr << "THREAD DEBUG: " << (void *)pthread_self() << ": Running thread " << thread->m_id << " for thread object " << thread << endl; c@287: #endif c@287: thread->run(); c@287: return 0; c@287: } c@287: c@287: Mutex::Mutex() c@287: #ifndef NO_THREAD_CHECKS c@287: : c@287: m_lockedBy(0), c@287: m_locked(false) c@287: #endif c@287: { c@287: pthread_mutex_init(&m_mutex, 0); c@287: #ifdef DEBUG_MUTEX c@287: cerr << "MUTEX DEBUG: " << (void *)pthread_self() << ": Initialised mutex " << &m_mutex << endl; c@287: #endif c@287: } c@287: c@287: Mutex::~Mutex() c@287: { c@287: #ifdef DEBUG_MUTEX c@287: cerr << "MUTEX DEBUG: " << (void *)pthread_self() << ": Destroying mutex " << &m_mutex << endl; c@287: #endif c@287: pthread_mutex_destroy(&m_mutex); c@287: } c@287: c@287: void c@287: Mutex::lock() c@287: { c@287: #ifndef NO_THREAD_CHECKS c@287: pthread_t tid = pthread_self(); c@287: if (m_locked && m_lockedBy == tid) { c@287: cerr << "ERROR: Deadlock on mutex " << &m_mutex << endl; c@287: } c@287: #endif c@287: #ifdef DEBUG_MUTEX c@287: cerr << "MUTEX DEBUG: " << (void *)tid << ": Want to lock mutex " << &m_mutex << endl; c@287: #endif c@287: pthread_mutex_lock(&m_mutex); c@287: #ifndef NO_THREAD_CHECKS c@287: m_lockedBy = tid; c@287: m_locked = true; c@287: #endif c@287: #ifdef DEBUG_MUTEX c@287: cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << endl; c@287: #endif c@287: } c@287: c@287: void c@287: Mutex::unlock() c@287: { c@287: #ifndef NO_THREAD_CHECKS c@287: pthread_t tid = pthread_self(); c@287: if (!m_locked) { c@287: cerr << "ERROR: Mutex " << &m_mutex << " not locked in unlock" << endl; c@287: return; c@287: } else if (m_lockedBy != tid) { c@287: cerr << "ERROR: Mutex " << &m_mutex << " not owned by unlocking thread" << endl; c@287: return; c@287: } c@287: #endif c@287: #ifdef DEBUG_MUTEX c@287: cerr << "MUTEX DEBUG: " << (void *)tid << ": Unlocking mutex " << &m_mutex << endl; c@287: #endif c@287: #ifndef NO_THREAD_CHECKS c@287: m_locked = false; c@287: #endif c@287: pthread_mutex_unlock(&m_mutex); c@287: } c@287: c@287: bool c@287: Mutex::trylock() c@287: { c@287: #ifndef NO_THREAD_CHECKS c@287: pthread_t tid = pthread_self(); c@287: #endif c@287: if (pthread_mutex_trylock(&m_mutex)) { c@287: #ifdef DEBUG_MUTEX c@287: cerr << "MUTEX DEBUG: " << (void *)tid << ": Mutex " << &m_mutex << " unavailable" << endl; c@287: #endif c@287: return false; c@287: } else { c@287: #ifndef NO_THREAD_CHECKS c@287: m_lockedBy = tid; c@287: m_locked = true; c@287: #endif c@287: #ifdef DEBUG_MUTEX c@287: cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << " (from trylock)" << endl; c@287: #endif c@287: return true; c@287: } c@287: } c@287: c@414: Condition::Condition(string c@414: #ifdef DEBUG_CONDITION c@414: name c@414: #endif c@414: ) : c@287: m_locked(false) c@287: #ifdef DEBUG_CONDITION c@287: , m_name(name) c@287: #endif c@287: { c@287: pthread_mutex_init(&m_mutex, 0); c@287: pthread_cond_init(&m_condition, 0); c@287: #ifdef DEBUG_CONDITION c@287: cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Initialised condition " << &m_condition << " \"" << m_name << "\"" << endl; c@287: #endif c@287: } c@287: c@287: Condition::~Condition() c@287: { c@287: #ifdef DEBUG_CONDITION c@287: cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Destroying condition " << &m_condition << " \"" << m_name << "\"" << endl; c@287: #endif c@287: if (m_locked) pthread_mutex_unlock(&m_mutex); c@287: pthread_cond_destroy(&m_condition); c@287: pthread_mutex_destroy(&m_mutex); c@287: } c@287: c@287: void c@287: Condition::lock() c@287: { c@287: #ifdef DEBUG_CONDITION c@287: cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Want to lock " << &m_condition << " \"" << m_name << "\"" << endl; c@287: #endif c@287: pthread_mutex_lock(&m_mutex); c@287: m_locked = true; c@287: #ifdef DEBUG_CONDITION c@287: cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Locked " << &m_condition << " \"" << m_name << "\"" << endl; c@287: #endif c@287: } c@287: c@287: void c@287: Condition::unlock() c@287: { c@287: if (!m_locked) { c@287: #ifdef DEBUG_CONDITION c@287: cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Not locked " << &m_condition << " \"" << m_name << "\"" << endl; c@287: #endif c@287: return; c@287: } c@287: #ifdef DEBUG_CONDITION c@287: cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Unlocking " << &m_condition << " \"" << m_name << "\"" << endl; c@287: #endif c@287: m_locked = false; c@287: pthread_mutex_unlock(&m_mutex); c@287: } c@287: c@287: void c@287: Condition::wait(int us) c@287: { c@287: if (us == 0) { c@287: c@287: #ifdef DEBUG_CONDITION c@287: cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Waiting on " << &m_condition << " \"" << m_name << "\"" << endl; c@287: #endif c@287: pthread_cond_wait(&m_condition, &m_mutex); c@287: c@287: } else { c@287: c@287: struct timeval now; c@287: gettimeofday(&now, 0); c@287: c@287: now.tv_usec += us; c@287: while (now.tv_usec > 1000000) { c@287: now.tv_usec -= 1000000; c@287: ++now.tv_sec; c@287: } c@287: c@287: struct timespec timeout; c@287: timeout.tv_sec = now.tv_sec; c@287: timeout.tv_nsec = now.tv_usec * 1000; c@287: c@287: #ifdef DEBUG_CONDITION c@287: cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Timed waiting on " << &m_condition << " \"" << m_name << "\"" << endl; c@287: #endif c@287: pthread_cond_timedwait(&m_condition, &m_mutex, &timeout); c@287: } c@287: c@287: #ifdef DEBUG_CONDITION c@287: cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Wait done on " << &m_condition << " \"" << m_name << "\"" << endl; c@287: #endif c@294: c@294: m_locked = true; c@287: } c@287: c@287: void c@287: Condition::signal() c@287: { c@287: #ifdef DEBUG_CONDITION c@287: cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Signalling " << &m_condition << " \"" << m_name << "\"" << endl; c@287: #endif c@287: pthread_cond_signal(&m_condition); c@287: } c@287: c@287: #else /* !USE_PTHREADS */ c@287: c@287: Thread::Thread() c@287: { c@287: } c@287: c@287: Thread::~Thread() c@287: { c@287: } c@287: c@287: void c@287: Thread::start() c@287: { c@287: abort(); c@287: } c@287: c@287: void c@287: Thread::wait() c@287: { c@287: abort(); c@287: } c@287: c@287: Thread::Id c@287: Thread::id() c@287: { c@287: abort(); c@287: } c@287: c@287: bool c@287: Thread::threadingAvailable() c@287: { c@287: return false; c@287: } c@287: c@287: Mutex::Mutex() c@287: { c@287: } c@287: c@287: Mutex::~Mutex() c@287: { c@287: } c@287: c@287: void c@287: Mutex::lock() c@287: { c@287: abort(); c@287: } c@287: c@287: void c@287: Mutex::unlock() c@287: { c@287: abort(); c@287: } c@287: c@287: bool c@287: Mutex::trylock() c@287: { c@287: abort(); c@287: } c@287: c@287: Condition::Condition(const char *) c@287: { c@287: } c@287: c@287: Condition::~Condition() c@287: { c@287: } c@287: c@287: void c@287: Condition::lock() c@287: { c@287: abort(); c@287: } c@287: c@287: void c@287: Condition::wait(int us) c@287: { c@287: abort(); c@287: } c@287: c@287: void c@287: Condition::signal() c@287: { c@287: abort(); c@287: } c@287: c@287: #endif /* !USE_PTHREADS */ c@287: #endif /* !_WIN32 */ c@287: c@287: MutexLocker::MutexLocker(Mutex *mutex) : c@287: m_mutex(mutex) c@287: { c@287: if (m_mutex) { c@287: m_mutex->lock(); c@287: } c@287: } c@287: c@287: MutexLocker::~MutexLocker() c@287: { c@287: if (m_mutex) { c@287: m_mutex->unlock(); c@287: } c@287: } c@287: