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 );
|
|||
|
}
|