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);
}
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;
    }
}