413 lines
8.8 KiB
C
413 lines
8.8 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 "ddm.h"
|
||
#include "timer.h"
|
||
#include <rasppp.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <wchar.h>
|
||
|
||
//
|
||
//
|
||
// Timer queue item
|
||
//
|
||
|
||
typedef struct _TIMER_EVENT_OBJECT
|
||
{
|
||
struct _TIMER_EVENT_OBJECT * pNext;
|
||
|
||
struct _TIMER_EVENT_OBJECT * pPrev;
|
||
|
||
TIMEOUT_HANDLER pfuncTimeoutHandler;
|
||
|
||
HANDLE hObject;
|
||
|
||
DWORD dwDelta; // # of secs. to wait after prev. item
|
||
|
||
} TIMER_EVENT_OBJECT, *PTIMER_EVENT_OBJECT;
|
||
|
||
//
|
||
// Head of timer queue.
|
||
//
|
||
|
||
typedef struct _TIMER_Q
|
||
{
|
||
TIMER_EVENT_OBJECT * pQHead;
|
||
|
||
CRITICAL_SECTION CriticalSection; // Mutual exclusion around timer Q
|
||
|
||
} TIMER_Q, *PTIMER_Q;
|
||
|
||
|
||
static TIMER_Q gblTimerQ; // Timer Queue
|
||
|
||
//**
|
||
//
|
||
// Call: TimerQInitialize
|
||
//
|
||
// Returns: NO_ERROR - Success
|
||
// Non-zero returns - Failure
|
||
//
|
||
// Description: Initializes the gblTimerQ structure
|
||
//
|
||
DWORD
|
||
TimerQInitialize(
|
||
VOID
|
||
)
|
||
{
|
||
//
|
||
// Initialize the global timer queue
|
||
//
|
||
|
||
InitializeCriticalSection( &(gblTimerQ.CriticalSection) );
|
||
|
||
return( NO_ERROR );
|
||
}
|
||
|
||
//**
|
||
//
|
||
// Call: TimerQDelete
|
||
//
|
||
// Returns: NO_ERROR - Success
|
||
// Non-zero returns - Failure
|
||
//
|
||
// Description: Deinitializes the TimerQ
|
||
//
|
||
VOID
|
||
TimerQDelete(
|
||
VOID
|
||
)
|
||
{
|
||
DeleteCriticalSection( &(gblTimerQ.CriticalSection) );
|
||
|
||
ZeroMemory( &gblTimerQ, sizeof( gblTimerQ ) );
|
||
}
|
||
|
||
//**
|
||
//
|
||
// Call: TimerQTick
|
||
//
|
||
// Returns: None.
|
||
//
|
||
// Description: Called each second if there are elements in the timeout queue.
|
||
//
|
||
VOID
|
||
TimerQTick(
|
||
VOID
|
||
)
|
||
{
|
||
TIMER_EVENT_OBJECT * pTimerEvent;
|
||
TIMER_EVENT_OBJECT * pTimerEventTmp;
|
||
|
||
//
|
||
// **** Exclusion Begin ****
|
||
//
|
||
|
||
EnterCriticalSection( &(gblTimerQ.CriticalSection) );
|
||
|
||
|
||
if ( ( pTimerEvent = gblTimerQ.pQHead ) == (TIMER_EVENT_OBJECT*)NULL )
|
||
{
|
||
//
|
||
// *** Exclusion End ***
|
||
//
|
||
|
||
LeaveCriticalSection( &(gblTimerQ.CriticalSection) );
|
||
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Decrement time on the first element
|
||
//
|
||
|
||
if ( pTimerEvent->dwDelta > 0 )
|
||
{
|
||
(pTimerEvent->dwDelta)--;
|
||
|
||
//
|
||
// *** Exclusion End ***
|
||
//
|
||
|
||
LeaveCriticalSection( &(gblTimerQ.CriticalSection) );
|
||
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Now run through and remove all completed (delta 0) elements.
|
||
//
|
||
|
||
while ( ( pTimerEvent != (TIMER_EVENT_OBJECT*)NULL ) &&
|
||
( pTimerEvent->dwDelta == 0 ) )
|
||
{
|
||
pTimerEvent = pTimerEvent->pNext;
|
||
}
|
||
|
||
if ( pTimerEvent == (TIMER_EVENT_OBJECT*)NULL )
|
||
{
|
||
pTimerEvent = gblTimerQ.pQHead;
|
||
|
||
gblTimerQ.pQHead = (TIMER_EVENT_OBJECT*)NULL;
|
||
|
||
}
|
||
else
|
||
{
|
||
pTimerEvent->pPrev->pNext = (TIMER_EVENT_OBJECT*)NULL;
|
||
|
||
pTimerEvent->pPrev = (TIMER_EVENT_OBJECT*)NULL;
|
||
|
||
pTimerEventTmp = gblTimerQ.pQHead;
|
||
|
||
gblTimerQ.pQHead = pTimerEvent;
|
||
|
||
pTimerEvent = pTimerEventTmp;
|
||
}
|
||
|
||
//
|
||
// *** Exclusion End ***
|
||
//
|
||
|
||
LeaveCriticalSection( &(gblTimerQ.CriticalSection) );
|
||
|
||
//
|
||
// Process all the timeout event objects items with delta == 0
|
||
//
|
||
|
||
while( pTimerEvent != (TIMER_EVENT_OBJECT*)NULL )
|
||
{
|
||
pTimerEvent->pfuncTimeoutHandler( pTimerEvent->hObject );
|
||
|
||
if ( pTimerEvent->pNext == (TIMER_EVENT_OBJECT *)NULL )
|
||
{
|
||
LOCAL_FREE( pTimerEvent );
|
||
|
||
pTimerEvent = (TIMER_EVENT_OBJECT*)NULL;
|
||
}
|
||
else
|
||
{
|
||
pTimerEvent = pTimerEvent->pNext;
|
||
|
||
LOCAL_FREE( pTimerEvent->pPrev );
|
||
}
|
||
}
|
||
}
|
||
|
||
//**
|
||
//
|
||
// Call: TimerQInsert
|
||
//
|
||
// 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.
|
||
//
|
||
DWORD
|
||
TimerQInsert(
|
||
IN HANDLE hObject,
|
||
IN DWORD dwTimeout,
|
||
IN TIMEOUT_HANDLER pfuncTimeoutHandler
|
||
)
|
||
{
|
||
TIMER_EVENT_OBJECT * pLastEvent;
|
||
TIMER_EVENT_OBJECT * pTimerEventWalker;
|
||
TIMER_EVENT_OBJECT * pTimerEvent;
|
||
|
||
pTimerEvent = (TIMER_EVENT_OBJECT *)LOCAL_ALLOC( LPTR,
|
||
sizeof(TIMER_EVENT_OBJECT));
|
||
|
||
if ( pTimerEvent == (TIMER_EVENT_OBJECT *)NULL )
|
||
{
|
||
return( GetLastError() );
|
||
}
|
||
|
||
pTimerEvent->hObject = hObject;
|
||
pTimerEvent->pfuncTimeoutHandler = pfuncTimeoutHandler;
|
||
|
||
//
|
||
// **** Exclusion Begin ****
|
||
//
|
||
|
||
EnterCriticalSection( &(gblTimerQ.CriticalSection) );
|
||
|
||
for ( pTimerEventWalker = gblTimerQ.pQHead,
|
||
pLastEvent = pTimerEventWalker;
|
||
|
||
( pTimerEventWalker != NULL ) &&
|
||
( pTimerEventWalker->dwDelta < dwTimeout );
|
||
|
||
pLastEvent = pTimerEventWalker,
|
||
pTimerEventWalker = pTimerEventWalker->pNext
|
||
)
|
||
{
|
||
dwTimeout -= pTimerEventWalker->dwDelta;
|
||
}
|
||
|
||
//
|
||
// Insert before pTimerEventWalker. If pTimerEventWalker is NULL then
|
||
// we insert at the end of the list.
|
||
//
|
||
|
||
if ( pTimerEventWalker == (TIMER_EVENT_OBJECT*)NULL )
|
||
{
|
||
//
|
||
// If the list was empty
|
||
//
|
||
|
||
if ( gblTimerQ.pQHead == (TIMER_EVENT_OBJECT*)NULL )
|
||
{
|
||
gblTimerQ.pQHead = pTimerEvent;
|
||
pTimerEvent->pNext = (TIMER_EVENT_OBJECT *)NULL;
|
||
pTimerEvent->pPrev = (TIMER_EVENT_OBJECT *)NULL;
|
||
|
||
}
|
||
else
|
||
{
|
||
pLastEvent->pNext = pTimerEvent;
|
||
pTimerEvent->pPrev = pLastEvent;
|
||
pTimerEvent->pNext = (TIMER_EVENT_OBJECT*)NULL;
|
||
}
|
||
}
|
||
else if ( pTimerEventWalker == gblTimerQ.pQHead )
|
||
{
|
||
//
|
||
// Insert before the first element
|
||
//
|
||
|
||
pTimerEvent->pNext = gblTimerQ.pQHead;
|
||
gblTimerQ.pQHead->pPrev = pTimerEvent;
|
||
gblTimerQ.pQHead->dwDelta -= dwTimeout;
|
||
pTimerEvent->pPrev = (TIMER_EVENT_OBJECT*)NULL;
|
||
gblTimerQ.pQHead = pTimerEvent;
|
||
}
|
||
else
|
||
{
|
||
|
||
//
|
||
// Insert middle element
|
||
//
|
||
|
||
pTimerEvent->pNext = pLastEvent->pNext;
|
||
pLastEvent->pNext = pTimerEvent;
|
||
pTimerEvent->pPrev = pLastEvent;
|
||
pTimerEventWalker->pPrev = pTimerEvent;
|
||
pTimerEventWalker->dwDelta -= dwTimeout;
|
||
}
|
||
|
||
pTimerEvent->dwDelta = dwTimeout;
|
||
|
||
//
|
||
// *** Exclusion End ***
|
||
//
|
||
|
||
LeaveCriticalSection( &(gblTimerQ.CriticalSection) );
|
||
|
||
return( NO_ERROR );
|
||
}
|
||
|
||
//**
|
||
//
|
||
// Call: TimerQRemove
|
||
//
|
||
// Returns: None.
|
||
//
|
||
// Description: Will remove a timeout event for a certain Id,hPort combination
|
||
// from the delta Q.
|
||
//
|
||
VOID
|
||
TimerQRemove(
|
||
IN HANDLE hObject,
|
||
IN TIMEOUT_HANDLER pfuncTimeoutHandler
|
||
)
|
||
{
|
||
TIMER_EVENT_OBJECT * pTimerEvent;
|
||
|
||
DDM_PRINT( gblDDMConfigInfo.dwTraceId, TRACE_TIMER,
|
||
"TimerQRemove called");
|
||
|
||
//
|
||
// **** Exclusion Begin ****
|
||
//
|
||
|
||
EnterCriticalSection( &(gblTimerQ.CriticalSection) );
|
||
|
||
for ( pTimerEvent = gblTimerQ.pQHead;
|
||
|
||
( pTimerEvent != (TIMER_EVENT_OBJECT *)NULL ) &&
|
||
( ( pTimerEvent->pfuncTimeoutHandler != pfuncTimeoutHandler ) ||
|
||
( pTimerEvent->hObject != hObject ) );
|
||
|
||
pTimerEvent = pTimerEvent->pNext
|
||
);
|
||
|
||
//
|
||
// If event was not found simply return.
|
||
//
|
||
|
||
if ( pTimerEvent == (TIMER_EVENT_OBJECT *)NULL )
|
||
{
|
||
//
|
||
// *** Exclusion End ***
|
||
//
|
||
|
||
LeaveCriticalSection( &(gblTimerQ.CriticalSection) );
|
||
|
||
return;
|
||
}
|
||
|
||
//
|
||
// If this is the first element to be removed
|
||
//
|
||
|
||
if ( pTimerEvent == gblTimerQ.pQHead )
|
||
{
|
||
gblTimerQ.pQHead = pTimerEvent->pNext;
|
||
|
||
if ( gblTimerQ.pQHead != (TIMER_EVENT_OBJECT *)NULL )
|
||
{
|
||
gblTimerQ.pQHead->pPrev = (TIMER_EVENT_OBJECT*)NULL;
|
||
gblTimerQ.pQHead->dwDelta += pTimerEvent->dwDelta;
|
||
}
|
||
}
|
||
else if ( pTimerEvent->pNext == (TIMER_EVENT_OBJECT*)NULL )
|
||
{
|
||
//
|
||
// If this was the last element to be removed
|
||
//
|
||
|
||
pTimerEvent->pPrev->pNext = (TIMER_EVENT_OBJECT*)NULL;
|
||
}
|
||
else
|
||
{
|
||
pTimerEvent->pNext->dwDelta += pTimerEvent->dwDelta;
|
||
pTimerEvent->pPrev->pNext = pTimerEvent->pNext;
|
||
pTimerEvent->pNext->pPrev = pTimerEvent->pPrev;
|
||
}
|
||
|
||
//
|
||
// *** Exclusion End ***
|
||
//
|
||
|
||
LeaveCriticalSection( &(gblTimerQ.CriticalSection) );
|
||
|
||
LOCAL_FREE( pTimerEvent );
|
||
}
|