Files
Client/Library/dxx8/samples/Multimedia/DirectShow/BaseClasses/schedule.cpp
LGram16 e067522598 Initial commit: ROW Client source code
Game client codebase including:
- CharacterActionControl: Character and creature management
- GlobalScript: Network, items, skills, quests, utilities
- RYLClient: Main client application with GUI and event handlers
- Engine: 3D rendering engine (RYLGL)
- MemoryManager: Custom memory allocation
- Library: Third-party dependencies (DirectX, boost, etc.)
- Tools: Development utilities

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 16:24:34 +09:00

266 lines
7.4 KiB
C++

//------------------------------------------------------------------------------
// File: Schedule.cpp
//
// Desc: DirectShow base classes.
//
// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------
#include <streams.h>
#pragma warning(disable:4706) // C4706: assignment within conditional expression
// 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( 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( 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