windows-nt/Source/XPSP1/NT/net/rras/ipx/sap/timermgr.c

329 lines
7.7 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
net\routing\ipx\sap\timermgr.c
Abstract:
Timer queue manager for SAP agent.
Author:
Vadim Eydelman 05-15-1995
Revision History:
--*/
#include "sapp.h"
// Timer queues and associated synchronization
typedef struct _TIMER_QUEUES {
LIST_ENTRY hrQueue; // Hi-res quueue (msec)
LIST_ENTRY lrQueue; // Lo-res queue (sec)
HANDLE timer; // NT timer signalled when
// one or more items in the
// timer queue have expired
CRITICAL_SECTION lock; // Protection
} TIMER_QUEUES, *PTIMER_QUEUES;
TIMER_QUEUES TimerQueues;
/*++
*******************************************************************
C r e a t e T i m e r Q u e u e
Routine Description:
Allocates resources for timer queue
Arguments:
wakeObject - sync object, to be signalled when
timer manager needs a shot process its timer queue
Return Value:
NO_ERROR - resources were allocated successfully
other - reason of failure (windows error code)
*******************************************************************
--*/
DWORD
IpxSapCreateTimerQueue (
HANDLE *wakeObject
) {
DWORD status;
status = NtCreateTimer (&TimerQueues.timer, TIMER_ALL_ACCESS,
NULL, NotificationTimer);
if (NT_SUCCESS (status)) {
*wakeObject = TimerQueues.timer;
InitializeCriticalSection (&TimerQueues.lock);
InitializeListHead (&TimerQueues.hrQueue);
InitializeListHead (&TimerQueues.lrQueue);
return NO_ERROR;
}
else
Trace (DEBUG_FAILURES, "File: %s, line %ld."
" Failed to create timer (nts:%lx).",
__FILE__, __LINE__, status);
return status;
}
/*++
*******************************************************************
E x p i r e T i m e r Q u e u e
Routine Description:
Expires (completes) all requests in timer queue
Arguments:
None
Return Value:
None
*******************************************************************
--*/
VOID
ExpireTimerQueue (
void
) {
BOOLEAN res;
Trace (DEBUG_TIMER, "Expiring timer queue.");
EnterCriticalSection (&TimerQueues.lock);
while (!IsListEmpty (&TimerQueues.hrQueue)) {
PTM_PARAM_BLOCK treq = CONTAINING_RECORD (TimerQueues.hrQueue.Flink,
TM_PARAM_BLOCK,
link);
RemoveEntryList (&treq->link);
ProcessCompletedTimerRequest (treq);
}
while (!IsListEmpty (&TimerQueues.lrQueue)) {
PTM_PARAM_BLOCK treq = CONTAINING_RECORD (TimerQueues.lrQueue.Flink,
TM_PARAM_BLOCK,
link);
RemoveEntryList (&treq->link);
ProcessCompletedTimerRequest (treq);
}
LeaveCriticalSection (&TimerQueues.lock);
}
/*++
*******************************************************************
E x p i r e L R R e q u s t s
Routine Description:
Expires (completes) Low Resolution timer requests
that return true from expiration check routine
Arguments:
context - context to pass to expiration check routine
Return Value:
None
*******************************************************************
--*/
VOID
ExpireLRRequests (
PVOID context
) {
BOOLEAN res;
PLIST_ENTRY cur;
Trace (DEBUG_TIMER, "Expire LR timer request call with context %08lx.", context);
EnterCriticalSection (&TimerQueues.lock);
cur = TimerQueues.lrQueue.Flink;
while (cur!=&TimerQueues.lrQueue) {
PTM_PARAM_BLOCK treq = CONTAINING_RECORD (cur,
TM_PARAM_BLOCK,
link);
cur = cur->Flink;
if ((treq->ExpirationCheckProc!=NULL)
&& (*treq->ExpirationCheckProc)(treq, context)) {
RemoveEntryList (&treq->link);
ProcessCompletedTimerRequest (treq);
}
}
LeaveCriticalSection (&TimerQueues.lock);
}
/*++
*******************************************************************
D e l e t e T i m e r Q u e u e
Routine Description:
Release all resources associated with timer queue
Arguments:
None
Return Value:
NO_ERROR - operation completed OK
*******************************************************************
--*/
VOID
IpxSapDeleteTimerQueue (
void
) {
NtClose (TimerQueues.timer);
DeleteCriticalSection (&TimerQueues.lock);
}
/*++
*******************************************************************
P r o c e s s T i m e r Q u e u e
Routine Description:
Process timer queues and moves expired requests to completion queue
This routine should be called when wake object is signalled
Arguments:
None
Return Value:
None
*******************************************************************
--*/
VOID
ProcessTimerQueue (
void
) {
ULONG curTime = GetTickCount ();
ULONG dueTime = curTime+MAXULONG/2;
LONGLONG timeout;
DWORD status;
EnterCriticalSection (&TimerQueues.lock);
while (!IsListEmpty (&TimerQueues.hrQueue)) {
PTM_PARAM_BLOCK treq = CONTAINING_RECORD (TimerQueues.hrQueue.Flink,
TM_PARAM_BLOCK,
link);
if (IsLater(curTime,treq->dueTime)) {
RemoveEntryList (&treq->link);
ProcessCompletedTimerRequest (treq);
}
else {
dueTime = treq->dueTime;
break;
}
}
while (!IsListEmpty (&TimerQueues.lrQueue)) {
PTM_PARAM_BLOCK treq = CONTAINING_RECORD (TimerQueues.lrQueue.Flink,
TM_PARAM_BLOCK,
link);
if (IsLater(curTime,treq->dueTime)) {
RemoveEntryList (&treq->link);
ProcessCompletedTimerRequest (treq);
}
else {
if (IsLater(dueTime,treq->dueTime))
dueTime = treq->dueTime;
break;
}
}
timeout = ((LONGLONG)(dueTime-curTime))*(-10000);
status = NtSetTimer (TimerQueues.timer,
(PLARGE_INTEGER)&timeout,
NULL, NULL, FALSE, 0, NULL);
ASSERTMSG ("Could not set timer ", NT_SUCCESS (status));
LeaveCriticalSection (&TimerQueues.lock);
}
/*++
*******************************************************************
A d d H R T i m e r R e q u e s t
Routine Description:
Enqueue request for hi-res timer (delay in order of msec)
Arguments:
treq - timer parameter block: dueTime field must be set
Return Value:
None
*******************************************************************
--*/
VOID
AddHRTimerRequest (
PTM_PARAM_BLOCK treq
) {
PLIST_ENTRY cur;
EnterCriticalSection (&TimerQueues.lock);
cur = TimerQueues.hrQueue.Blink;
while (cur!=&TimerQueues.hrQueue) {
PTM_PARAM_BLOCK node = CONTAINING_RECORD (cur, TM_PARAM_BLOCK, link);
if (IsLater(treq->dueTime,node->dueTime))
break;
cur = cur->Blink;
}
InsertHeadList (cur, &treq->link);
if (cur==&TimerQueues.hrQueue) {
ULONG delay = treq->dueTime-GetTickCount ();
LONGLONG timeout = (delay>MAXULONG/2) ? 0 : ((LONGLONG)delay*(-10000));
DWORD status = NtSetTimer (TimerQueues.timer,
(PLARGE_INTEGER)&timeout,
NULL, NULL, FALSE, 0, NULL);
ASSERTMSG ("Could not set timer ", NT_SUCCESS (status));
}
LeaveCriticalSection (&TimerQueues.lock);
}
/*++
*******************************************************************
A d d L R T i m e r R e q u e s t
Routine Description:
Enqueue request for lo-res timer (delay in order of sec)
Arguments:
treq - timer parameter block: dueTime field must be set
Return Value:
None
*******************************************************************
--*/
VOID
AddLRTimerRequest (
PTM_PARAM_BLOCK treq
) {
PLIST_ENTRY cur;
RoundUpToSec (treq->dueTime);
EnterCriticalSection (&TimerQueues.lock);
cur = TimerQueues.lrQueue.Blink;
while (cur!=&TimerQueues.lrQueue) {
PTM_PARAM_BLOCK node = CONTAINING_RECORD (cur, TM_PARAM_BLOCK, link);
if (IsLater(treq->dueTime,node->dueTime))
break;
cur = cur->Blink;
}
InsertHeadList (cur, &treq->link);
if ((cur==&TimerQueues.lrQueue)
&& IsListEmpty (&TimerQueues.hrQueue)) {
ULONG delay = treq->dueTime-GetTickCount ();
LONGLONG timeout = (delay>MAXULONG/2) ? 0 : ((LONGLONG)delay*(-10000));
DWORD status = NtSetTimer (TimerQueues.timer,
(PLARGE_INTEGER)&timeout,
NULL, NULL, FALSE, 0, NULL);
ASSERTMSG ("Could not set timer ", NT_SUCCESS (status));
}
LeaveCriticalSection (&TimerQueues.lock);
}