void ArchMultithreadPosix::refThread(ArchThreadImpl* thread) { assert(thread != NULL); assert(findNoRef(thread->m_thread) != NULL); ++thread->m_refCount; }
HANDLE ArchMultithreadWindows::getCancelEventForCurrentThread() { lockMutex(m_threadMutex); ArchThreadImpl* thread = findNoRef(GetCurrentThreadId()); unlockMutex(m_threadMutex); return thread->m_cancel; }
void ArchMultithreadWindows::setNetworkDataForCurrentThread(void* data) { lockMutex(m_threadMutex); ArchThreadImpl* thread = findNoRef(GetCurrentThreadId()); thread->m_networkData = data; unlockMutex(m_threadMutex); }
ArchThreadImpl* ArchMultithreadWindows::find(DWORD id) { ArchThreadImpl* impl = findNoRef(id); if (impl != NULL) { refThread(impl); } return impl; }
ArchThreadImpl* ArchMultithreadPosix::find(pthread_t thread) { ArchThreadImpl* impl = findNoRef(thread); if (impl != NULL) { refThread(impl); } return impl; }
bool ArchMultithreadPosix::wait(ArchThread target, double timeout) { assert(target != NULL); lockMutex(m_threadMutex); // find current thread ArchThreadImpl* self = findNoRef(pthread_self()); // ignore wait if trying to wait on ourself if (target == self) { unlockMutex(m_threadMutex); return false; } // ref the target so it can't go away while we're watching it refThread(target); unlockMutex(m_threadMutex); try { // do first test regardless of timeout testCancelThreadImpl(self); if (isExitedThread(target)) { closeThread(target); return true; } // wait and repeat test if there's a timeout if (timeout != 0.0) { const double start = ARCH->time(); do { // wait a little ARCH->sleep(0.05); // repeat test testCancelThreadImpl(self); if (isExitedThread(target)) { closeThread(target); return true; } // repeat wait and test until timed out } while (timeout < 0.0 || (ARCH->time() - start) <= timeout); } closeThread(target); return false; } catch (...) { closeThread(target); throw; } }
void ArchMultithreadWindows::testCancelThread() { // find current thread lockMutex(m_threadMutex); ArchThreadImpl* thread = findNoRef(GetCurrentThreadId()); unlockMutex(m_threadMutex); // test cancel on thread testCancelThreadImpl(thread); }
void ArchMultithreadPosix::testCancelThread() { // find current thread lockMutex(m_threadMutex); ArchThreadImpl* thread = findNoRef(pthread_self()); unlockMutex(m_threadMutex); // test cancel on thread testCancelThreadImpl(thread); }
void ArchMultithreadPosix::insert(ArchThreadImpl* thread) { assert(thread != NULL); // thread shouldn't already be on the list assert(findNoRef(thread->m_thread) == NULL); // set thread id. note that we don't worry about m_nextID // wrapping back to 0 and duplicating thread ID's since the // likelihood of synergy running that long is vanishingly // small. thread->m_id = ++m_nextID; // append to list m_threadList.push_back(thread); }
void ArchMultithreadPosix::closeThread(ArchThread thread) { assert(thread != NULL); // decrement ref count and clean up thread if no more references if (--thread->m_refCount == 0) { // detach from thread (unless it's the main thread) if (thread->m_func != NULL) { pthread_detach(thread->m_thread); } // remove thread from list lockMutex(m_threadMutex); assert(findNoRef(thread->m_thread) == thread); erase(thread); unlockMutex(m_threadMutex); // done with thread delete thread; } }
bool ArchMultithreadWindows::wait(ArchThread target, double timeout) { assert(target != NULL); lockMutex(m_threadMutex); // find current thread ArchThreadImpl* self = findNoRef(GetCurrentThreadId()); // ignore wait if trying to wait on ourself if (target == self) { unlockMutex(m_threadMutex); return false; } // ref the target so it can't go away while we're watching it refThread(target); unlockMutex(m_threadMutex); // convert timeout DWORD t; if (timeout < 0.0) { t = INFINITE; } else { t = (DWORD)(1000.0 * timeout); } // wait for this thread to be cancelled or woken up or for the // target thread to terminate. HANDLE handles[2]; handles[0] = target->m_exit; handles[1] = self->m_cancel; DWORD result = WaitForMultipleObjects(2, handles, FALSE, t); // cancel takes priority if (result != WAIT_OBJECT_0 + 1 && WaitForSingleObject(handles[1], 0) == WAIT_OBJECT_0) { result = WAIT_OBJECT_0 + 1; } // release target closeThread(target); // handle result switch (result) { case WAIT_OBJECT_0 + 0: // target thread terminated return true; case WAIT_OBJECT_0 + 1: // this thread was cancelled. does not return. testCancelThreadImpl(self); default: // timeout or error return false; } }