Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

156 lines
5.4 KiB

/*==========================================================================
*
* Copyright (C) 2002 Microsoft Corporation. All Rights Reserved.
*
* File: dvtimer.pp
* Content: Implementation of DvTimer class.
*
* History:
* Date By Reason
* ==== == ======
* 05-06-02 simonpow Created
*
***************************************************************************/
#include "dxvutilspch.h"
#undef DPF_SUBCOMP
#define DPF_SUBCOMP DN_SUBCOMP_VOICE
#undef DPF_MODNAME
#define DPF_MODNAME "DvTimer::DvTimer"
DvTimer::DvTimer()
{
DPFX(DPFPREP, DVF_TRACELEVEL, "Entry");
m_pfnUserCallback=NULL;
m_pvUserData=NULL;
m_dwPeriod=0;
m_pvTimerData=NULL;
m_uiTimerUnique=0;
DPFX(DPFPREP, DVF_INFOLEVEL, "DvTimer object create at 0x%p", this);
DPFX(DPFPREP, DVF_TRACELEVEL, "Exit");
}
#undef DPF_MODNAME
#define DPF_MODNAME "DvTimer::~DvTimer"
DvTimer::~DvTimer()
{
DPFX(DPFPREP, DVF_TRACELEVEL, "Entry");
//if we've actually created a timer and got a thread pool interface
if (m_pThreadPool)
{
HRESULT hr;
//If we're in the middle of the callback we'll not be able to cancel the timer
//hence spin until we do (since its rescheduled at the end of every callback)
DPFX(DPFPREP, DVF_INFOLEVEL, "Starting cancel loop");
DNASSERT(m_pvTimerData);
//we don't want to be in the situation where the timer keeps getting rescheduled and we keep
//missing it. i.e. Constantly waking up in the period its active rather than the period its scheduled
//hence, set the period to a high value to ensure the next time it fires (if at all) it will be 24hrs away
m_dwPeriod=1000*60*60*24;
while (1)
{
hr=IDirectPlay8ThreadPoolWork_CancelTimer(m_pThreadPool, m_pvTimerData, m_uiTimerUnique, 0);
if (hr==DPN_OK)
break;
DNASSERT(hr==DPNERR_CANNOTCANCEL);
Sleep(DvTimer_SleepPeriodInCancelSpin);
}
IDirectPlay8ThreadPoolWork_Release(m_pThreadPool);
}
DPFX(DPFPREP, DVF_INFOLEVEL, "DvTimer destroyed at 0x%p", this);
DPFX(DPFPREP, DVF_TRACELEVEL, "Exit");
}
#undef DPF_MODNAME
#define DPF_MODNAME "DvTimer::Create"
BOOL DvTimer::Create (DWORD dwPeriod, void * pvUserData, DvTimerCallback pfnCallback)
{
DPFX(DPFPREP, DVF_TRACELEVEL, "Entry dwPeriod %u pvUserData 0x%p pfnCallback 0x%p",
dwPeriod, pvUserData, pfnCallback);
//sanity checks
DNASSERT(pfnCallback);
DNASSERT(dwPeriod);
//store state user specifies for timer
m_pfnUserCallback=pfnCallback;
m_pvUserData=pvUserData;
m_dwPeriod=dwPeriod;
//get a thread pool interface. Since the thread pool is a singleton object, this probably won't
//actually do the creation
HRESULT hr=CoCreateInstance(CLSID_DirectPlay8ThreadPool, NULL, CLSCTX_INPROC_SERVER,
IID_IDirectPlay8ThreadPoolWork, (void **) &m_pThreadPool);
if (FAILED(hr))
{
DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed to CoCreate CLSID_DirectPlay8ThreadPool hr 0x%x", hr);
return FALSE;
}
//schedule the first timer
hr=IDirectPlay8ThreadPoolWork_ScheduleTimer(m_pThreadPool, -1,
dwPeriod, ThreadpoolTimerCallbackStatic, this, &m_pvTimerData, (UINT* ) &m_uiTimerUnique, 0);
if (FAILED(hr))
{
//need to return state to 'uncreated', so we don't do any clean up in the d'tor
IDirectPlay8ThreadPoolWork_Release(m_pThreadPool);
m_pThreadPool=NULL;
DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed to schedule timer hr 0x%x", hr);
return FALSE;
}
DPFX(DPFPREP, DVF_INFOLEVEL, "DvTimer create success m_pvTimerData 0x%p m_uiTimerUnique 0x%p",
m_pvTimerData, m_uiTimerUnique);
//need to ensure that at least one thread is around to service our timer
IDirectPlay8ThreadPoolWork_RequestTotalThreadCount(m_pThreadPool, 1, 0);
DPFX(DPFPREP, DVF_TRACELEVEL, "Exit");
return TRUE;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DvTimer::ThreadpoolTimerCallbackStatic"
void DvTimer::ThreadpoolTimerCallbackStatic(void * const pvContext,
void * const pvTimerData, const UINT uiTimerUnique)
{
DPFX(DPFPREP, DVF_TRACELEVEL, "Entry pvContext 0x%p pvTimerData 0x%p uiTimerUnique %u",
pvContext, pvTimerData, uiTimerUnique);
//extract the timer object from the context
DvTimer * pTimer=(DvTimer * ) pvContext;
//and store the time we started the callback
DWORD dwStartTime=GETTIMESTAMP();
//generate the callback to the user
(*pTimer->m_pfnUserCallback)(pTimer->m_pvUserData);
//compute the period for the next timer, based on the required period minus
//the time that elasped doing the actual work
//This ensures that the user is called at periods as close to m_dwPeriod as possible
DWORD dwPeriod=pTimer->m_dwPeriod-(GETTIMESTAMP()-dwStartTime);
//if the new period is in the past (i.e. we spent so long in the callback we are due another one
//immediately) then set the minimum period for the next callback
if (((int ) dwPeriod)<0)
dwPeriod=1;
//N.B. We don't pass m_dwTimerUnique direct to the Reset timer function, since we could be using
//the value in a cancel spin. Hence, we wait until the timer has definitely been rescheduled
//before storing the new unique value for it.
UINT uiNextTimerUnique;
IDirectPlay8ThreadPoolWork_ResetCompletingTimer(pTimer->m_pThreadPool, pvTimerData, dwPeriod,
ThreadpoolTimerCallbackStatic, pTimer, &uiNextTimerUnique, 0);
pTimer->m_uiTimerUnique=uiNextTimerUnique;
DPFX(DPFPREP, DVF_TRACELEVEL, "Exit");
}