SCHEDULE.H
//==========================================================================; 
// 
//  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR 
//  PURPOSE. 
// 
//  Copyright (c) 1996 - 1997 Microsoft Corporation.  All Rights Reserved. 
// 
//--------------------------------------------------------------------------; 
//  SCHEDULE.H 
 
#ifndef __CAMSchedule__ 
#define __CAMSchedule__ 
 
class CAMSchedule : private CBaseObject 
{ 
public: 
    virtual ~CAMSchedule(); 
    // ev is the event we should fire if the advise time needs re-evaluating 
    CAMSchedule( HANDLE ev ); 
 
    DWORD GetAdviseCount(); 
    REFERENCE_TIME GetNextAdviseTime(); 
 
    // We need a method for derived classes to add advise packets, we return the cookie 
    DWORD AddAdvisePacket( const REFERENCE_TIME & time1, const REFERENCE_TIME & time2, HANDLE h, BOOL periodic ); 
    // And a way to cancel 
    HRESULT Unadvise(DWORD dwAdviseCookie); 
 
    // Tell us the time please, and we'll dispatch the expired events.  We return the time of the next event. 
    // NB: The time returned will be "useless" if you start adding extra Advises.  But that's the problem of 
    // whoever is using this helper class (typically a clock). 
    REFERENCE_TIME Advise( const REFERENCE_TIME & rtTime ); 
 
    // Get the event handle which will be set if advise time requires re-evaluation. 
    HANDLE GetEvent() const { return m_ev; } 
 
private: 
    // We define the nodes that will be used in our singly linked list 
    // of advise packets.  The list is ordered by time, with the 
    // elements that will expire first at the front. 
    class CAdvisePacket 
    { 
    public: 
        CAdvisePacket() 
        {} 
 
        CAdvisePacket * m_next; 
        DWORD           m_dwAdviseCookie; 
        REFERENCE_TIME  m_rtEventTime;      // Time at which event should be set 
        REFERENCE_TIME  m_rtPeriod;         // Periodic time 
        HANDLE          m_hNotify;          // Handle to event or semephore 
        BOOL            m_bPeriodic;        // TRUE => Periodic event 
 
        CAdvisePacket( CAdvisePacket * next, LONGLONG time ) : m_next(next), m_rtEventTime(time) 
        {} 
 
        void InsertAfter( CAdvisePacket * p ) 
        { 
            p->m_next = m_next; 
            m_next    = p; 
        } 
 
        int IsZ() const // That is, is it the node that represents the end of the list 
    { return m_next == 0; } 
 
    CAdvisePacket * RemoveNext() 
    { 
        CAdvisePacket *const next = m_next; 
        CAdvisePacket *const new_next = next->m_next; 
        m_next = new_next; 
        return next; 
    } 
 
    void DeleteNext() 
    { 
        delete RemoveNext(); 
    } 
 
    CAdvisePacket * Next() const 
    { 
        CAdvisePacket * result = m_next; 
        if (result->IsZ()) result = 0; 
        return result; 
    } 
 
        DWORD Cookie() const 
        { return m_dwAdviseCookie; } 
    }; 
 
    // Structure is: 
    // head -> elmt1 -> elmt2 -> z -> null 
    // So an empty list is:       head -> z -> null 
    // Having head & z as links makes insertaion, 
    // deletion and shunting much easier. 
    CAdvisePacket   head, z;            // z is both a tail and a sentry 
 
    volatile DWORD  m_dwNextCookie;     // Strictly increasing 
    volatile DWORD  m_dwAdviseCount;    // Number of elements on list 
 
    CCritSec        m_Serialize; 
 
    // AddAdvisePacket: adds the packet, returns the cookie (0 if failed) 
    DWORD AddAdvisePacket( CAdvisePacket * pPacket ); 
    // Event that we should set if the packed added above will be the next to fire. 
    const HANDLE m_ev; 
 
    // A Shunt is where we have changed the first element in the 
    // list and want it re-evaluating (i.e. repositioned) in 
    // the list. 
    void ShuntHead(); 
 
    // Rather than delete advise packets, we cache them for future use 
    CAdvisePacket * m_pAdviseCache; 
    DWORD           m_dwCacheCount; 
    enum { dwCacheMax = 5 };             // Don't bother caching more than five 
 
    void Delete( CAdvisePacket * pLink );// This "Delete" will cache the Link 
 
// Attributes and methods for debugging 
public: 
#ifdef DEBUG 
    void DumpLinkedList(); 
#else 
    void DumpLinkedList() {} 
#endif 
 
}; 
 
#endif // __CAMSchedule__