329 lines
7.7 KiB
C
329 lines
7.7 KiB
C
|
/*++
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
|