mirror of
https://github.com/PCSX2/pcsx2.git
synced 2025-04-02 10:52:54 -04:00
Update it to the version found at https://github.com/Microsoft/Windows-classic-samples , which is in an MIT licensed repo, and add the LICENSE file (edited to remove the SIL Open Font LICENSE part since that doesn't apply). Some modifications have been made to reduce the diff/stop git complaining (not including any file that wasn't in the previous version and removing the related header includes in streams.h, and fixing some but not all of the whitespace issues).
284 lines
7.5 KiB
C++
284 lines
7.5 KiB
C++
//------------------------------------------------------------------------------
|
|
// File: Schedule.cpp
|
|
//
|
|
// Desc: DirectShow base classes.
|
|
//
|
|
// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved.
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
#include <streams.h>
|
|
|
|
// DbgLog values (all on LOG_TIMING):
|
|
//
|
|
// 2 for schedulting, firing and shunting of events
|
|
// 3 for wait delays and wake-up times of event thread
|
|
// 4 for details of whats on the list when the thread awakes
|
|
|
|
/* Construct & destructors */
|
|
|
|
CAMSchedule::CAMSchedule( HANDLE ev )
|
|
: CBaseObject(TEXT("CAMSchedule"))
|
|
, head(&z, 0), z(0, MAX_TIME)
|
|
, m_dwNextCookie(0), m_dwAdviseCount(0)
|
|
, m_pAdviseCache(0), m_dwCacheCount(0)
|
|
, m_ev( ev )
|
|
{
|
|
head.m_dwAdviseCookie = z.m_dwAdviseCookie = 0;
|
|
}
|
|
|
|
CAMSchedule::~CAMSchedule()
|
|
{
|
|
m_Serialize.Lock();
|
|
|
|
// Delete cache
|
|
CAdvisePacket * p = m_pAdviseCache;
|
|
while (p)
|
|
{
|
|
CAdvisePacket *const p_next = p->m_next;
|
|
delete p;
|
|
p = p_next;
|
|
}
|
|
|
|
ASSERT( m_dwAdviseCount == 0 );
|
|
// Better to be safe than sorry
|
|
if ( m_dwAdviseCount > 0 )
|
|
{
|
|
DumpLinkedList();
|
|
while ( !head.m_next->IsZ() )
|
|
{
|
|
head.DeleteNext();
|
|
--m_dwAdviseCount;
|
|
}
|
|
}
|
|
|
|
// If, in the debug version, we assert twice, it means, not only
|
|
// did we have left over advises, but we have also let m_dwAdviseCount
|
|
// get out of sync. with the number of advises actually on the list.
|
|
ASSERT( m_dwAdviseCount == 0 );
|
|
|
|
m_Serialize.Unlock();
|
|
}
|
|
|
|
/* Public methods */
|
|
|
|
DWORD CAMSchedule::GetAdviseCount()
|
|
{
|
|
// No need to lock, m_dwAdviseCount is 32bits & declared volatile
|
|
return m_dwAdviseCount;
|
|
}
|
|
|
|
REFERENCE_TIME CAMSchedule::GetNextAdviseTime()
|
|
{
|
|
CAutoLock lck(&m_Serialize); // Need to stop the linked list from changing
|
|
return head.m_next->m_rtEventTime;
|
|
}
|
|
|
|
DWORD_PTR CAMSchedule::AddAdvisePacket
|
|
( const REFERENCE_TIME & time1
|
|
, const REFERENCE_TIME & time2
|
|
, HANDLE h, BOOL periodic
|
|
)
|
|
{
|
|
// Since we use MAX_TIME as a sentry, we can't afford to
|
|
// schedule a notification at MAX_TIME
|
|
ASSERT( time1 < MAX_TIME );
|
|
DWORD_PTR Result;
|
|
CAdvisePacket * p;
|
|
|
|
m_Serialize.Lock();
|
|
|
|
if (m_pAdviseCache)
|
|
{
|
|
p = m_pAdviseCache;
|
|
m_pAdviseCache = p->m_next;
|
|
--m_dwCacheCount;
|
|
}
|
|
else
|
|
{
|
|
p = new CAdvisePacket();
|
|
}
|
|
if (p)
|
|
{
|
|
p->m_rtEventTime = time1; p->m_rtPeriod = time2;
|
|
p->m_hNotify = h; p->m_bPeriodic = periodic;
|
|
Result = AddAdvisePacket( p );
|
|
}
|
|
else Result = 0;
|
|
|
|
m_Serialize.Unlock();
|
|
|
|
return Result;
|
|
}
|
|
|
|
HRESULT CAMSchedule::Unadvise(DWORD_PTR dwAdviseCookie)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
CAdvisePacket * p_prev = &head;
|
|
CAdvisePacket * p_n;
|
|
m_Serialize.Lock();
|
|
while ( p_n = p_prev->Next() ) // The Next() method returns NULL when it hits z
|
|
{
|
|
if ( p_n->m_dwAdviseCookie == dwAdviseCookie )
|
|
{
|
|
Delete( p_prev->RemoveNext() );
|
|
--m_dwAdviseCount;
|
|
hr = S_OK;
|
|
// Having found one cookie that matches, there should be no more
|
|
#ifdef DEBUG
|
|
while (p_n = p_prev->Next())
|
|
{
|
|
ASSERT(p_n->m_dwAdviseCookie != dwAdviseCookie);
|
|
p_prev = p_n;
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
p_prev = p_n;
|
|
};
|
|
m_Serialize.Unlock();
|
|
return hr;
|
|
}
|
|
|
|
REFERENCE_TIME CAMSchedule::Advise( const REFERENCE_TIME & rtTime )
|
|
{
|
|
REFERENCE_TIME rtNextTime;
|
|
CAdvisePacket * pAdvise;
|
|
|
|
DbgLog((LOG_TIMING, 2,
|
|
TEXT("CAMSchedule::Advise( %lu ms )"), ULONG(rtTime / (UNITS / MILLISECONDS))));
|
|
|
|
CAutoLock lck(&m_Serialize);
|
|
|
|
#ifdef DEBUG
|
|
if (DbgCheckModuleLevel(LOG_TIMING, 4)) DumpLinkedList();
|
|
#endif
|
|
|
|
// Note - DON'T cache the difference, it might overflow
|
|
while ( rtTime >= (rtNextTime = (pAdvise=head.m_next)->m_rtEventTime) &&
|
|
!pAdvise->IsZ() )
|
|
{
|
|
ASSERT(pAdvise->m_dwAdviseCookie); // If this is zero, its the head or the tail!!
|
|
|
|
ASSERT(pAdvise->m_hNotify != INVALID_HANDLE_VALUE);
|
|
|
|
if (pAdvise->m_bPeriodic == TRUE)
|
|
{
|
|
ReleaseSemaphore(pAdvise->m_hNotify,1,NULL);
|
|
pAdvise->m_rtEventTime += pAdvise->m_rtPeriod;
|
|
ShuntHead();
|
|
}
|
|
else
|
|
{
|
|
ASSERT( pAdvise->m_bPeriodic == FALSE );
|
|
EXECUTE_ASSERT(SetEvent(pAdvise->m_hNotify));
|
|
--m_dwAdviseCount;
|
|
Delete( head.RemoveNext() );
|
|
}
|
|
|
|
}
|
|
|
|
DbgLog((LOG_TIMING, 3,
|
|
TEXT("CAMSchedule::Advise() Next time stamp: %lu ms, for advise %lu."),
|
|
DWORD(rtNextTime / (UNITS / MILLISECONDS)), pAdvise->m_dwAdviseCookie ));
|
|
|
|
return rtNextTime;
|
|
}
|
|
|
|
/* Private methods */
|
|
|
|
DWORD_PTR CAMSchedule::AddAdvisePacket( __inout CAdvisePacket * pPacket )
|
|
{
|
|
ASSERT(pPacket->m_rtEventTime >= 0 && pPacket->m_rtEventTime < MAX_TIME);
|
|
ASSERT(CritCheckIn(&m_Serialize));
|
|
|
|
CAdvisePacket * p_prev = &head;
|
|
CAdvisePacket * p_n;
|
|
|
|
const DWORD_PTR Result = pPacket->m_dwAdviseCookie = ++m_dwNextCookie;
|
|
// This relies on the fact that z is a sentry with a maximal m_rtEventTime
|
|
for(;;p_prev = p_n)
|
|
{
|
|
p_n = p_prev->m_next;
|
|
if ( p_n->m_rtEventTime >= pPacket->m_rtEventTime ) break;
|
|
}
|
|
p_prev->InsertAfter( pPacket );
|
|
++m_dwAdviseCount;
|
|
|
|
DbgLog((LOG_TIMING, 2, TEXT("Added advise %lu, for thread 0x%02X, scheduled at %lu"),
|
|
pPacket->m_dwAdviseCookie, GetCurrentThreadId(), (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) ));
|
|
|
|
// If packet added at the head, then clock needs to re-evaluate wait time.
|
|
if ( p_prev == &head ) SetEvent( m_ev );
|
|
|
|
return Result;
|
|
}
|
|
|
|
void CAMSchedule::Delete( __inout CAdvisePacket * pPacket )
|
|
{
|
|
if ( m_dwCacheCount >= dwCacheMax ) delete pPacket;
|
|
else
|
|
{
|
|
m_Serialize.Lock();
|
|
pPacket->m_next = m_pAdviseCache;
|
|
m_pAdviseCache = pPacket;
|
|
++m_dwCacheCount;
|
|
m_Serialize.Unlock();
|
|
}
|
|
}
|
|
|
|
|
|
// Takes the head of the list & repositions it
|
|
void CAMSchedule::ShuntHead()
|
|
{
|
|
CAdvisePacket * p_prev = &head;
|
|
CAdvisePacket * p_n;
|
|
|
|
m_Serialize.Lock();
|
|
CAdvisePacket *const pPacket = head.m_next;
|
|
|
|
// This will catch both an empty list,
|
|
// and if somehow a MAX_TIME time gets into the list
|
|
// (which would also break this method).
|
|
ASSERT( pPacket->m_rtEventTime < MAX_TIME );
|
|
|
|
// This relies on the fact that z is a sentry with a maximal m_rtEventTime
|
|
for(;;p_prev = p_n)
|
|
{
|
|
p_n = p_prev->m_next;
|
|
if ( p_n->m_rtEventTime > pPacket->m_rtEventTime ) break;
|
|
}
|
|
// If p_prev == pPacket then we're already in the right place
|
|
if (p_prev != pPacket)
|
|
{
|
|
head.m_next = pPacket->m_next;
|
|
(p_prev->m_next = pPacket)->m_next = p_n;
|
|
}
|
|
#ifdef DEBUG
|
|
DbgLog((LOG_TIMING, 2, TEXT("Periodic advise %lu, shunted to %lu"),
|
|
pPacket->m_dwAdviseCookie, (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) ));
|
|
#endif
|
|
m_Serialize.Unlock();
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
void CAMSchedule::DumpLinkedList()
|
|
{
|
|
m_Serialize.Lock();
|
|
int i=0;
|
|
DbgLog((LOG_TIMING, 1, TEXT("CAMSchedule::DumpLinkedList() this = 0x%p"), this));
|
|
for ( CAdvisePacket * p = &head
|
|
; p
|
|
; p = p->m_next , i++
|
|
)
|
|
{
|
|
DbgLog((LOG_TIMING, 1, TEXT("Advise List # %lu, Cookie %d, RefTime %lu"),
|
|
i,
|
|
p->m_dwAdviseCookie,
|
|
p->m_rtEventTime / (UNITS / MILLISECONDS)
|
|
));
|
|
}
|
|
m_Serialize.Unlock();
|
|
}
|
|
#endif
|