www.pudn.com > PPPOE.rar > timer.cpp


 
//******************************************************************** 
//	ÈÕÆÚ:	2004/08/24 - 24:8:2004   19:15 
//	Ãûǰ:	tiamo 
//	ÃèÊö:	timer routine 
//********************************************************************* 
 
#include "Stdafx.h" 
 
// timer 
TIMER g_timer; 
 
namespace 
{ 
	// intenal use 
	LARGE_INTEGER _s_ZeroTime = {0,0}; 
} 
 
#pragma alloc_text(PAGE,InitializeTimerSystem) 
 
#pragma alloc_text("TIMER",ShutdownTimerSystem) 
#pragma alloc_text("TIMER",ShutdownTimerSystem) 
#pragma alloc_text("TIMER",ScheduleTimerItem) 
#pragma alloc_text("TIMER",CancelTimerItem) 
#pragma alloc_text("TIMER",CommonTimerRoutine) 
#pragma alloc_text("TIMER",SetTimer) 
 
// init timer system,you should call it in your driver entry 
VOID InitializeTimerSystem() 
{ 
	PAGED_CODE(); 
 
	NdisInitializeListHead(&g_timer.m_ltTimerItemsHead); 
 
	g_timer.m_ulSig = TIMER_SIG; 
 
	NdisAllocateSpinLock(&g_timer.m_lockSelf); 
 
	NdisInitializeTimer(&g_timer.m_ndisTimer,CommonTimerRoutine,&g_timer); 
} 
 
// shut down timer system,you should call it in your driver unload 
VOID ShutdownTimerSystem() 
{ 
	ASSERT(g_timer.m_ulSig == TIMER_SIG); 
 
	NdisFreeSpinLock(&g_timer.m_lockSelf); 
} 
 
// init timer item 
VOID InitializeTimerItem(PTIMER_ITEM pItem) 
{ 
	ASSERT(pItem); 
 
	NdisInitializeListHead(&pItem->m_ltTimerItemAnchor); 
} 
 
// schedule time call 
VOID ScheduleTimerItem(PTIMER_ITEM pItem,TIMER_ROUTINE pRoutine,ULONG ulMsDelay,PVOID pContext) 
{ 
	ASSERT(g_timer.m_ulSig == TIMER_SIG && pItem && pRoutine); 
 
	pItem->m_pContext = pContext; 
	pItem->m_pTimerRoutine = pRoutine; 
 
	LARGE_INTEGER curTime; 
	KeQuerySystemTime(&curTime); 
 
	pItem->m_ullExecuteTime.QuadPart = curTime.QuadPart + ulMsDelay * 10000; 
 
	NdisAcquireSpinLock(&g_timer.m_lockSelf); 
 
	if(!IsListEmpty(&g_timer.m_ltTimerItemsHead)) 
	{ 
		PLIST_ENTRY pEntry = g_timer.m_ltTimerItemsHead.Blink; 
 
		for(;;) 
		{ 
			PTIMER_ITEM pCurItem = CONTAINING_RECORD(pEntry,TIMER_ITEM, m_ltTimerItemAnchor); 
 
			if(pCurItem->m_ullExecuteTime.QuadPart < pItem->m_ullExecuteTime.QuadPart || pEntry == &g_timer.m_ltTimerItemsHead) 
			{ 
				InsertHeadList(pEntry,&pItem->m_ltTimerItemAnchor); 
 
				if(&pItem->m_ltTimerItemAnchor == g_timer.m_ltTimerItemsHead.Flink) 
					SetTimer(curTime); 
 
				break; 
			} 
 
			pEntry = pEntry->Blink; 
		} 
	} 
	else 
	{ 
		InsertHeadList(&g_timer.m_ltTimerItemsHead,&pItem->m_ltTimerItemAnchor); 
		SetTimer(curTime); 
	} 
 
	NdisReleaseSpinLock(&g_timer.m_lockSelf); 
} 
 
// cancel timer call 
VOID CancelTimerItem(PTIMER_ITEM pItem,PVOID pCancelContext) 
{ 
	ASSERT(pItem); 
 
	// not in the timer list 
	if(IsListEmpty(&pItem->m_ltTimerItemAnchor)) 
		return; 
 
	NdisAcquireSpinLock(&g_timer.m_lockSelf); 
 
	// next item 
	PLIST_ENTRY pEntry = g_timer.m_ltTimerItemsHead.Flink; 
 
	BOOLEAN bCanceled = TRUE; 
 
	// if next item is that we want to cancel 
	BOOLEAN bNextItem = pEntry == &pItem->m_ltTimerItemAnchor; 
 
	if(pEntry != &g_timer.m_ltTimerItemsHead) 
	{ 
		if(bNextItem) 
		{ 
			// cancel 
			NdisCancelTimer(&g_timer.m_ndisTimer,&bCanceled); 
		} 
 
		if(bCanceled) 
		{ 
			// remove from list 
			RemoveEntryList(pEntry); 
 
			// reinit it 
			NdisInitializeListHead(pEntry); 
 
			// request another timer call 
			if(bNextItem) 
				SetTimer(_s_ZeroTime); 
		} 
	} 
 
	NdisReleaseSpinLock(&g_timer.m_lockSelf); 
 
	// call the routine with the cancel context 
	if(!bNextItem || bCanceled) 
	{ 
		pItem->m_pTimerRoutine(pItem,pItem->m_pContext,pCancelContext); 
	} 
} 
 
// ndis timer routine 
VOID CommonTimerRoutine(PVOID pSystem1,PVOID pContext,PVOID pSystem3,PVOID pSystem4) 
{ 
	PTIMER pTimer = static_cast(pContext); 
 
	ASSERT(pTimer && pTimer->m_ulSig == TIMER_SIG); 
 
	ASSERT(DISPATCH_LEVEL == KeGetCurrentIrql()); 
 
	// acquire spinlock 
	NdisDprAcquireSpinLock(&pTimer->m_lockSelf); 
 
	// remove head 
	PLIST_ENTRY pEntry = RemoveHeadList(&pTimer->m_ltTimerItemsHead); 
 
	if(pEntry) 
	{ 
		InitializeListHead(pEntry); 
 
		// set next timer 
		SetTimer(_s_ZeroTime); 
	} 
 
	// release lock 
	NdisDprReleaseSpinLock(&pTimer->m_lockSelf); 
 
	if(pEntry) 
	{ 
		PTIMER_ITEM pTimerItem = CONTAINING_RECORD(pEntry,TIMER_ITEM,m_ltTimerItemAnchor); 
 
		// call the routine normal fire 
		pTimerItem->m_pTimerRoutine(pTimerItem,pTimerItem->m_pContext,NULL); 
	} 
} 
 
// set timer 
VOID SetTimer(LARGE_INTEGER ullCurrentTime) 
{ 
	ASSERT(g_timer.m_ulSig == TIMER_SIG); 
 
	ASSERT(DISPATCH_LEVEL == KeGetCurrentIrql()); 
 
	// check 
	if(IsListEmpty(&g_timer.m_ltTimerItemsHead)) 
		return; 
 
	// get current time 
	if(ullCurrentTime.QuadPart == 0) 
	{ 
		KeQuerySystemTime(&ullCurrentTime); 
	} 
 
	PTIMER_ITEM pTimerItem = CONTAINING_RECORD((g_timer.m_ltTimerItemsHead.Flink),TIMER_ITEM, m_ltTimerItemAnchor); 
 
	ullCurrentTime.QuadPart = (pTimerItem->m_ullExecuteTime.QuadPart - ullCurrentTime.QuadPart) / 10000; 
 
	if(ullCurrentTime.QuadPart < 0) 
		return; 
 
	NdisSetTimer(&g_timer.m_ndisTimer,ullCurrentTime.LowPart); 
}