|
|
/********************************************************************/ /** Copyright(c) 1989 Microsoft Corporation. **/ /********************************************************************/
//***
//
// Filename: timer.c
//
// Description: All timer queue related funtions live here.
//
// History:
// Nov 11,1993. NarenG Created original version.
//
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h> // needed for winbase.h
#include <windows.h> // Win32 base API's
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <lmcons.h>
#include <rasman.h>
#include <mprlog.h>
#include <rasppp.h>
#include <pppcp.h>
#include <ppp.h>
#include <util.h>
#include <worker.h>
#include <timer.h>
//**
//
// Call: MakeTimeoutWorkItem
//
// Returns: PCB_WORK_ITEM * - Pointer to the timeout work item
// NULL - On any error.
//
// Description:
//
PCB_WORK_ITEM * MakeTimeoutWorkItem( IN DWORD dwPortId, IN HPORT hPort, IN DWORD Protocol, IN DWORD Id, IN BOOL fAuthenticator, IN TIMER_EVENT_TYPE EventType ) { PCB_WORK_ITEM * pWorkItem = (PCB_WORK_ITEM *) LOCAL_ALLOC( LPTR, sizeof( PCB_WORK_ITEM ) );
if ( pWorkItem == (PCB_WORK_ITEM *)NULL ) { LogPPPEvent( ROUTERLOG_NOT_ENOUGH_MEMORY, 0 );
return( NULL ); }
pWorkItem->dwPortId = dwPortId; pWorkItem->Id = Id; pWorkItem->hPort = hPort; pWorkItem->Protocol = Protocol; pWorkItem->fAuthenticator = fAuthenticator; pWorkItem->TimerEventType = EventType; pWorkItem->Process = ProcessTimeout;
return( pWorkItem ); }
//**
//
// Call: TimerTick
//
// Returns: None.
//
// Description: Called each second if there are elements in the timeout queue.
//
VOID TimerTick( OUT BOOL * pfQueueEmpty ) { TIMER_EVENT * pTimerEvent; TIMER_EVENT * pTimerEventTmp;
if ( ( pTimerEvent = TimerQ.pQHead ) == (TIMER_EVENT*)NULL ) { *pfQueueEmpty = TRUE;
return; }
*pfQueueEmpty = FALSE;
//
// Decrement time on the first element
//
if ( pTimerEvent->Delta > 0 ) { (pTimerEvent->Delta)--;
return; }
//
// Now run through and remove all completed (delta 0) elements.
//
while ( (pTimerEvent != (TIMER_EVENT*)NULL) && (pTimerEvent->Delta == 0) ) { pTimerEvent = pTimerEvent->pNext; }
if ( pTimerEvent == (TIMER_EVENT*)NULL ) { pTimerEvent = TimerQ.pQHead;
TimerQ.pQHead = (TIMER_EVENT*)NULL;
} else { pTimerEvent->pPrev->pNext = (TIMER_EVENT*)NULL;
pTimerEvent->pPrev = (TIMER_EVENT*)NULL;
pTimerEventTmp = TimerQ.pQHead;
TimerQ.pQHead = pTimerEvent;
pTimerEvent = pTimerEventTmp; }
//
// Now make a timeout work item and put it in the work item Q for all the
// items with delta == 0
//
while( pTimerEvent != (TIMER_EVENT*)NULL ) {
PCB_WORK_ITEM * pWorkItem = MakeTimeoutWorkItem( pTimerEvent->dwPortId, pTimerEvent->hPort, pTimerEvent->Protocol, pTimerEvent->Id, pTimerEvent->fAuthenticator, pTimerEvent->EventType );
if ( pWorkItem == ( PCB_WORK_ITEM *)NULL ) { LogPPPEvent( ROUTERLOG_NOT_ENOUGH_MEMORY, GetLastError() ); } else { InsertWorkItemInQ( pWorkItem ); }
if ( pTimerEvent->pNext == (TIMER_EVENT *)NULL ) { LOCAL_FREE( pTimerEvent );
pTimerEvent = (TIMER_EVENT*)NULL; } else { pTimerEvent = pTimerEvent->pNext;
LOCAL_FREE( pTimerEvent->pPrev ); }
}
}
//**
//
// Call: InsertInTimerQ
//
// Returns: NO_ERROR - Success
// return from GetLastError() - Failure
//
// Description: Adds a timeout element into the delta queue. If the Timer is not
// started it is started. Since there is a LocalAlloc() call here -
// this may fail in which case it will simply not insert it in the
// queue and the request will never timeout. BAP passes in an HCONN in
// hPort.
//
DWORD InsertInTimerQ( IN DWORD dwPortId, IN HPORT hPort, IN DWORD Id, IN DWORD Protocol, IN BOOL fAuthenticator, IN TIMER_EVENT_TYPE EventType, IN DWORD Timeout ) { TIMER_EVENT * pLastEvent; TIMER_EVENT * pTimerEventWalker; TIMER_EVENT * pTimerEvent = (TIMER_EVENT *)LOCAL_ALLOC( LPTR, sizeof(TIMER_EVENT));
if ( pTimerEvent == (TIMER_EVENT *)NULL ) { PppLog( 1, "InsertInTimerQ failed: out of memory" );
return( GetLastError() ); }
PppLog( 2, "InsertInTimerQ called portid=%d,Id=%d,Protocol=%x," "EventType=%d,fAuth=%d", dwPortId, Id, Protocol, EventType, fAuthenticator );
pTimerEvent->dwPortId = dwPortId; pTimerEvent->Id = Id; pTimerEvent->Protocol = Protocol; pTimerEvent->hPort = hPort; pTimerEvent->EventType = EventType; pTimerEvent->fAuthenticator = fAuthenticator; for ( pTimerEventWalker = TimerQ.pQHead, pLastEvent = pTimerEventWalker;
( pTimerEventWalker != NULL ) && ( pTimerEventWalker->Delta < Timeout );
pLastEvent = pTimerEventWalker, pTimerEventWalker = pTimerEventWalker->pNext ) { Timeout -= pTimerEventWalker->Delta; }
//
// Insert before pTimerEventWalker. If pTimerEventWalker is NULL then
// we insert at the end of the list.
//
if ( pTimerEventWalker == (TIMER_EVENT*)NULL ) { //
// If the list was empty
//
if ( TimerQ.pQHead == (TIMER_EVENT*)NULL ) { TimerQ.pQHead = pTimerEvent; pTimerEvent->pNext = (TIMER_EVENT *)NULL; pTimerEvent->pPrev = (TIMER_EVENT *)NULL;
//
// Wake up thread since the Q is not empty any longer
//
SetEvent( TimerQ.hEventNonEmpty ); } else { pLastEvent->pNext = pTimerEvent; pTimerEvent->pPrev = pLastEvent; pTimerEvent->pNext = (TIMER_EVENT*)NULL; } } else if ( pTimerEventWalker == TimerQ.pQHead ) { //
// Insert before the first element
//
pTimerEvent->pNext = TimerQ.pQHead; TimerQ.pQHead->pPrev = pTimerEvent; TimerQ.pQHead->Delta -= Timeout; pTimerEvent->pPrev = (TIMER_EVENT*)NULL; TimerQ.pQHead = pTimerEvent; } else {
//
// Insert middle element
//
pTimerEvent->pNext = pLastEvent->pNext; pLastEvent->pNext = pTimerEvent; pTimerEvent->pPrev = pLastEvent; pTimerEventWalker->pPrev = pTimerEvent; pTimerEventWalker->Delta -= Timeout; }
pTimerEvent->Delta = Timeout;
return( NO_ERROR ); }
//**
//
// Call: RemoveFromTimerQ
//
// Returns: None.
//
// Description: Will remove a timeout event for a certain Id,hPort combination
// from the delta Q.
//
VOID RemoveFromTimerQ( IN DWORD dwPortId, IN DWORD Id, IN DWORD Protocol, IN BOOL fAuthenticator, IN TIMER_EVENT_TYPE EventType ) { TIMER_EVENT * pTimerEvent;
PppLog( 2, "RemoveFromTimerQ called portid=%d,Id=%d,Protocol=%x," "EventType=%d,fAuth=%d", dwPortId, Id, Protocol, EventType, fAuthenticator );
for ( pTimerEvent = TimerQ.pQHead;
( pTimerEvent != (TIMER_EVENT *)NULL ) && ( ( pTimerEvent->EventType != EventType ) || ( pTimerEvent->dwPortId != dwPortId ) || ( ( pTimerEvent->EventType == TIMER_EVENT_TIMEOUT ) && ( ( pTimerEvent->Id != Id ) || ( pTimerEvent->Protocol != Protocol ) || ( pTimerEvent->fAuthenticator != fAuthenticator ) ) ) ); pTimerEvent = pTimerEvent->pNext );
//
// If event was not found simply return.
//
if ( pTimerEvent == (TIMER_EVENT *)NULL ) { return; }
//
// If this is the first element to be removed
//
if ( pTimerEvent == TimerQ.pQHead ) { TimerQ.pQHead = pTimerEvent->pNext;
if ( TimerQ.pQHead != (TIMER_EVENT *)NULL ) { TimerQ.pQHead->pPrev = (TIMER_EVENT*)NULL; TimerQ.pQHead->Delta += pTimerEvent->Delta; } } else if ( pTimerEvent->pNext == (TIMER_EVENT*)NULL ) { //
// If this was the last element to be removed
//
pTimerEvent->pPrev->pNext = (TIMER_EVENT*)NULL; } else { pTimerEvent->pNext->Delta += pTimerEvent->Delta; pTimerEvent->pPrev->pNext = pTimerEvent->pNext; pTimerEvent->pNext->pPrev = pTimerEvent->pPrev; }
LOCAL_FREE( pTimerEvent ); }
|