381 lines
9.5 KiB
C
381 lines
9.5 KiB
C
/********************************************************************/
|
||
/** 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 );
|
||
}
|