ArchThread ArchMultithreadWindows::newThread(ThreadFunc func, void* data) { lockMutex(m_threadMutex); // create thread impl for new thread ArchThreadImpl* thread = new ArchThreadImpl; thread->m_func = func; thread->m_userData = data; // create thread unsigned int id = 0; thread->m_thread = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0, threadFunc, (void*)thread, 0, &id)); thread->m_id = static_cast<DWORD>(id); // check if thread was started if (thread->m_thread == 0) { // failed to start thread so clean up delete thread; thread = NULL; } else { // add thread to list insert(thread); // increment ref count to account for the thread itself refThread(thread); } // note that the child thread will wait until we release this mutex unlockMutex(m_threadMutex); return thread; }
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; } }
ArchThread ArchMultithreadPosix::newThread(ThreadFunc func, void* data) { assert(func != NULL); // initialize signal handler. we do this here instead of the // constructor so we can avoid daemonizing (using fork()) // when there are multiple threads. clients can safely // use condition variables and mutexes before creating a // new thread and they can safely use the only thread // they have access to, the main thread, so they really // can't tell the difference. if (!m_newThreadCalled) { m_newThreadCalled = true; #if HAVE_PTHREAD_SIGNAL startSignalHandler(); #endif } lockMutex(m_threadMutex); // create thread impl for new thread ArchThreadImpl* thread = new ArchThreadImpl; thread->m_func = func; thread->m_userData = data; // create the thread. pthread_create() on RedHat 7.2 smp fails // if passed a NULL attr so use a default attr. pthread_attr_t attr; int status = pthread_attr_init(&attr); if (status == 0) { status = pthread_create(&thread->m_thread, &attr, &ArchMultithreadPosix::threadFunc, thread); pthread_attr_destroy(&attr); } // check if thread was started if (status != 0) { // failed to start thread so clean up delete thread; thread = NULL; } else { // add thread to list insert(thread); // increment ref count to account for the thread itself refThread(thread); } // note that the child thread will wait until we release this mutex unlockMutex(m_threadMutex); return 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; } }
ArchThread ArchMultithreadWindows::copyThread(ArchThread thread) { refThread(thread); return thread; }
ArchThread ArchMultithreadPosix::copyThread(ArchThread thread) { refThread(thread); return thread; }