|
|
/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
tcpip\ip\mcasttmr.c
Abstract:
Timer routine for cleanup of MFEs
Author:
Amritansh Raghav
Revision History:
AmritanR Created
Notes:
--*/
#include "precomp.h"
#if IPMCAST
#define __FILE_SIG__ TMR_SIG
#include "ipmcast.h"
#include "ipmcstxt.h"
#include "mcastmfe.h"
VOID CompleteNotificationIrp( IN PNOTIFICATION_MSG pMsg );
VOID McastTimerRoutine( PKDPC Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2 );
//
// MUST BE PAGED IN
//
#pragma alloc_text(PAGEIPMc, McastTimerRoutine)
VOID McastTimerRoutine( PKDPC Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2 )
/*++
Routine Description:
The DPC routine associated with the timer. The global variable g_ulNextHashIndex keeps track of the bucket that needs to be walked and checked for activity. The routine walks all the groups in BUCKETS_PER_QUANTUM number of buckets.
N.B.: We should probably use a JOB object for this.
Locks:
Takes the lock for each hash bucket walked as writer
Arguments:
Dpc DeferredContext SystemArgument1 SystemArgument2
Return Value:
NONE
--*/
{ LONGLONG llCurrentTime, llTime; ULONG ulIndex, ulNumBuckets, ulMsgIndex; PLIST_ENTRY pleGrpNode, pleSrcNode; PGROUP pGroup; PSOURCE pSource;
LARGE_INTEGER liDueTime; PNOTIFICATION_MSG pCopy; PIPMCAST_MFE_MSG pMsg;
TraceEnter(TMR, "McastTimerRoutine");
KeQueryTickCount((PLARGE_INTEGER)&llCurrentTime);
ulIndex = g_ulNextHashIndex; ulMsgIndex = 0; pCopy = NULL; pMsg = NULL;
Trace(TMR, TRACE, ("McastTimerRoutine: Starting at index %d\n", ulIndex));
for(ulNumBuckets = 0; ulNumBuckets < BUCKETS_PER_QUANTUM; ulNumBuckets++) { //
// Acquire the bucket lock as writer. Since we are off a TIMER
// we are at DPC
//
EnterWriterAtDpcLevel(&g_rgGroupTable[ulIndex].rwlLock);
pleGrpNode = g_rgGroupTable[ulIndex].leHashHead.Flink;
while(pleGrpNode isnot &(g_rgGroupTable[ulIndex].leHashHead)) { pGroup = CONTAINING_RECORD(pleGrpNode, GROUP, leHashLink);
pleGrpNode = pleGrpNode->Flink;
pleSrcNode = pGroup->leSrcHead.Flink;
while(pleSrcNode isnot &pGroup->leSrcHead) { //
// We look at the SOURCE without taking the lock, because
// the source can not be deleted without removing it from the
// group list, which can not happen since we have the group
// bucket locked as writer
//
pSource = CONTAINING_RECORD(pleSrcNode, SOURCE, leGroupLink);
pleSrcNode = pleSrcNode->Flink;
//
// The TimeOut and CreateTime can be looked at without
// a lock, but the LastActivity should be read only with
// the lock held. However, we shall take the chance and
// not use a lock
//
if(pSource->llTimeOut isnot 0) { //
// Timeout value has been supplied, lets use that
//
llTime = llCurrentTime - pSource->llCreateTime;
if((llCurrentTime > pSource->llCreateTime) and (llTime < pSource->llTimeOut)) { continue; }
Trace(TMR, TRACE, ("McastTimerRoutine: %d.%d.%d.%d %d.%d.%d.%d entry being removed due to user supplied timeout\n", PRINT_IPADDR(pGroup->dwGroup), PRINT_IPADDR(pSource->dwSource))); } else { //
// Otherwise, just do this based on activity
//
llTime = llCurrentTime - pSource->llLastActivity;
if((llCurrentTime > pSource->llLastActivity) and (llTime < SECS_TO_TICKS(INACTIVITY_PERIOD))) { continue; }
Trace(TMR, TRACE, ("McastTimerRoutine: %d.%d.%d.%d %d.%d.%d.%d entry being removed due to inactiviy\n", PRINT_IPADDR(pGroup->dwGroup), PRINT_IPADDR(pSource->dwSource))); }
//
// Otherwise we need to delete the source, and complete an
// IRP back to the router manager
//
if(ulMsgIndex is 0) { RtAssert(!pCopy);
pCopy = ExAllocateFromNPagedLookasideList(&g_llMsgBlocks);
if(pCopy is NULL) { continue; }
pCopy->inMessage.dwEvent = IPMCAST_DELETE_MFE_MSG;
pMsg = &(pCopy->inMessage.immMfe);
pMsg->ulNumMfes = 0; }
pMsg->ulNumMfes++;
pMsg->idmMfe[ulMsgIndex].dwGroup = pGroup->dwGroup; pMsg->idmMfe[ulMsgIndex].dwSource = pSource->dwSource; pMsg->idmMfe[ulMsgIndex].dwSrcMask = pSource->dwSrcMask;
ulMsgIndex++;
ulMsgIndex %= NUM_DEL_MFES;
if(ulMsgIndex is 0) { //
// Complete the Irp
//
CompleteNotificationIrp(pCopy);
pCopy = NULL; pMsg = NULL; }
//
// The function needs the SOURCE ref'ed and locked
//
ReferenceSource(pSource);
RtAcquireSpinLockAtDpcLevel(&(pSource->mlLock));
RemoveSource(pGroup->dwGroup, pSource->dwSource, pSource->dwSrcMask, pGroup, pSource);
} }
ExitWriterFromDpcLevel(&g_rgGroupTable[ulIndex].rwlLock);
//
// Done walking this bucket
//
ulIndex++;
ulIndex %= GROUP_TABLE_SIZE; }
//
// The last message may not have been indicated up. See if it needs
// to be completed
//
if(pCopy) { CompleteNotificationIrp(pCopy); }
g_ulNextHashIndex = ulIndex;
liDueTime = RtlEnlargedUnsignedMultiply(TIMER_IN_MILLISECS, SYS_UNITS_IN_ONE_MILLISEC);
liDueTime = RtlLargeIntegerNegate(liDueTime);
KeSetTimerEx(&g_ktTimer, liDueTime, 0, &g_kdTimerDpc);
TraceLeave(TMR, "McastTimerRoutine"); }
#endif
|