After signalling an event, always wait for the signalled thread to touch

m_WaitersDone.  This fixes problems with

 event.Lock();
 event.Signal();
 while(x) event.Wait();

picking up the signal that it just sent (which is wrong), especially in the
debugger.
This commit is contained in:
Glenn Maynard
2005-01-27 01:19:24 +00:00
parent 582a2ec27a
commit 903aaadcc5
2 changed files with 9 additions and 13 deletions
+9 -12
View File
@@ -259,7 +259,6 @@ EventImpl_Win32::EventImpl_Win32( MutexImpl_Win32 *pParent )
{ {
m_pParent = pParent; m_pParent = pParent;
m_iNumWaiting = 0; m_iNumWaiting = 0;
m_bNeedSignal = false;
m_WakeupSema = CreateSemaphore( NULL, 0, 0x7fffffff, NULL ); m_WakeupSema = CreateSemaphore( NULL, 0, 0x7fffffff, NULL );
InitializeCriticalSection( &m_iNumWaitingLock ); InitializeCriticalSection( &m_iNumWaitingLock );
m_WaitersDone = CreateEvent( NULL, FALSE, FALSE, NULL ); m_WaitersDone = CreateEvent( NULL, FALSE, FALSE, NULL );
@@ -334,11 +333,10 @@ bool EventImpl_Win32::Wait( RageTimer *pTimeout )
EnterCriticalSection( &m_iNumWaitingLock ); EnterCriticalSection( &m_iNumWaitingLock );
--m_iNumWaiting; --m_iNumWaiting;
bool bLastWaiting = m_bNeedSignal && m_iNumWaiting == 0; bool bLastWaiting = m_iNumWaiting == 0;
LeaveCriticalSection( &m_iNumWaitingLock ); LeaveCriticalSection( &m_iNumWaitingLock );
/* If m_bNeedSignal is set, and we're the last waiter to wake up, signal the /* If we're the last waiter to wake up, wake up the signaller. */
* broadcaster. */
if( bLastWaiting ) if( bLastWaiting )
PortableSignalObjectAndWait( m_WaitersDone, m_pParent->mutex, false ); PortableSignalObjectAndWait( m_WaitersDone, m_pParent->mutex, false );
else else
@@ -354,7 +352,12 @@ void EventImpl_Win32::Signal()
LeaveCriticalSection( &m_iNumWaitingLock ); LeaveCriticalSection( &m_iNumWaitingLock );
if( bHaveWaiters ) if( bHaveWaiters )
{
ReleaseSemaphore( m_WakeupSema, 1, 0 ); ReleaseSemaphore( m_WakeupSema, 1, 0 );
/* The waiter will touch m_WaitersDone. */
WaitForSingleObject( m_WaitersDone, INFINITE );
}
} }
void EventImpl_Win32::Broadcast() void EventImpl_Win32::Broadcast()
@@ -367,19 +370,13 @@ void EventImpl_Win32::Broadcast()
return; return;
} }
/* Since we're broadcasting, we need to wait for all waiters to wake up and
* start waiting for the mutex before returning. */
m_bNeedSignal = true;
ReleaseSemaphore( m_WakeupSema, m_iNumWaiting, 0 ); ReleaseSemaphore( m_WakeupSema, m_iNumWaiting, 0 );
LeaveCriticalSection( &m_iNumWaitingLock ); LeaveCriticalSection( &m_iNumWaitingLock );
/* We set m_bNeedSignal; the last waiter will touch m_WaitersDone. Note that /* The last waiter will touch m_WaitersDone, so we wait for all waiters to wake up and
* we still hold the parent mutex, so no other thread is currently broadcasting; * start waiting for the mutex before returning. */
* we don't have to worry about m_bNeedSignal being set to false on us. */
WaitForSingleObject( m_WaitersDone, INFINITE ); WaitForSingleObject( m_WaitersDone, INFINITE );
m_bNeedSignal = false;
} }
EventImpl *MakeEvent( MutexImpl *pMutex ) EventImpl *MakeEvent( MutexImpl *pMutex )
@@ -57,7 +57,6 @@ private:
CRITICAL_SECTION m_iNumWaitingLock; CRITICAL_SECTION m_iNumWaitingLock;
HANDLE m_WakeupSema; HANDLE m_WakeupSema;
HANDLE m_WaitersDone; HANDLE m_WaitersDone;
bool m_bNeedSignal;
}; };
class SemaImpl_Win32: public SemaImpl class SemaImpl_Win32: public SemaImpl