BOOL FairMonitor::EndSynchronized() { if( ! LockHeldByCallingThread() ) { ::SetLastError(ERROR_INVALID_FUNCTION); // for the lack of better... return FALSE; } // Record the lock release for proper release in Wait(). --m_nLockCount; // Release lock. Win32 allows no error checking here. ::LeaveCriticalSection(&m_critsecSynchronized); return TRUE; }
DWORD FairMonitor::Wait( DWORD dwMillisecondsTimeout/* = INFINITE*/, BOOL bAlertable/* = FALSE */ ) { if( ! LockHeldByCallingThread() ) { ::SetLastError(ERROR_INVALID_FUNCTION); // for the lack of better... return WAIT_FAILED; } // Enter a new event handle into the wait set. HANDLE hWaitEvent = Push(); if( NULL == hWaitEvent ) return WAIT_FAILED; // Store the current lock count for re-acquisition. int nThisThreadsLockCount = m_nLockCount; m_nLockCount = 0; // Release the synchronization lock the appropriate number of times. // Win32 allows no error checking here. for( int i=0; i<nThisThreadsLockCount; ++i) ::LeaveCriticalSection(&m_critsecSynchronized); // NOTE: Conceptually, releasing the lock and entering the wait // state is done in one atomic step. Technically, that is not // true here, because we first leave the critical section and // then, in a separate line of code, call WaitForSingleObjectEx. // The reason why this code is correct is that our thread is placed // in the wait set *before* the lock is released. Therefore, if // we get preempted right here and another thread notifies us, then // that notification will *not* be missed: the wait operation below // will find the event signalled. // Wait for the event to become signalled. DWORD dwWaitResult = ::WaitForSingleObjectEx( hWaitEvent, dwMillisecondsTimeout, bAlertable ); // If the wait failed, store the last error because it will get // overwritten when acquiring the lock. DWORD dwLastError; if( WAIT_FAILED == dwWaitResult ) dwLastError = ::GetLastError(); // Acquire the synchronization lock the appropriate number of times. // Win32 allows no error checking here. for( int j=0; j<nThisThreadsLockCount; ++j) ::EnterCriticalSection(&m_critsecSynchronized); // Handle the wait timeout case. ::EnterCriticalSection(&m_critsecWaitSetProtection); std::deque<HANDLE>::const_iterator it_end = m_deqWaitSet.end(); for ( std::deque<HANDLE>::const_iterator it = m_deqWaitSet.begin(); it < it_end; it++ ) { if ((*it) == hWaitEvent) { m_deqWaitSet.erase(it); break; } } ::LeaveCriticalSection(&m_critsecWaitSetProtection); // Restore lock count. m_nLockCount = nThisThreadsLockCount; // Close event handle if( ! CloseHandle(hWaitEvent) ) return WAIT_FAILED; if( WAIT_FAILED == dwWaitResult ) ::SetLastError(dwLastError); return dwWaitResult; }
DWORD Condition::Wait() { DWORD dwMillisecondsTimeout = INFINITE; BOOL bAlertable = FALSE; ASSERT(LockHeldByCallingThread()); // Enter a new event handle into the wait set. HANDLE hWaitEvent = Push(); if( NULL == hWaitEvent ) return WAIT_FAILED; // Store the current lock count for re-acquisition. int nThisThreadsLockCount = m_nLockCount; m_nLockCount = 0; // Release the synchronization lock the appropriate number of times. // Win32 allows no error checking here. for( int i=0; i<nThisThreadsLockCount; ++i) { //::LeaveCriticalSection(&m_critsecSynchronized); m_externalMutex->Release(); } // NOTE: Conceptually, releasing the lock and entering the wait // state is done in one atomic step. Technically, that is not // true here, because we first leave the critical section and // then, in a separate line of code, call WaitForSingleObjectEx. // The reason why this code is correct is that our thread is placed // in the wait set *before* the lock is released. Therefore, if // we get preempted right here and another thread notifies us, then // that notification will *not* be missed: the wait operation below // will find the event signalled. // Wait for the event to become signalled. DWORD dwWaitResult = ::WaitForSingleObjectEx( hWaitEvent, dwMillisecondsTimeout, bAlertable ); // If the wait failed, store the last error because it will get // overwritten when acquiring the lock. DWORD dwLastError = 0; if( WAIT_FAILED == dwWaitResult ) dwLastError = ::GetLastError(); // Acquire the synchronization lock the appropriate number of times. // Win32 allows no error checking here. for( int j=0; j<nThisThreadsLockCount; ++j) { //::EnterCriticalSection(&m_critsecSynchronized); m_externalMutex->Acquire(); } // Restore lock count. m_nLockCount = nThisThreadsLockCount; // Close event handle if( ! CloseHandle(hWaitEvent) ) return WAIT_FAILED; if( WAIT_FAILED == dwWaitResult ) ::SetLastError(dwLastError); return dwWaitResult; }