815 lines
21 KiB
C
815 lines
21 KiB
C
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
winstmm.c
|
|
|
|
|
|
Abstract:
|
|
This module contains the timer manager functions
|
|
|
|
|
|
Functions:
|
|
WinsTmmInsertEntry
|
|
TmmThdInitFn
|
|
WinsTmmInit
|
|
HandleReq
|
|
SignalClient
|
|
WinsTmmDeleteReqs
|
|
WinsTmmDeallocReq
|
|
|
|
Portability:
|
|
|
|
This module is portable
|
|
|
|
Author:
|
|
|
|
Pradeep Bahl (PradeepB) Mar-1993
|
|
|
|
Revision History:
|
|
|
|
Modification date Person Description of modification
|
|
----------------- ------- ----------------------------
|
|
--*/
|
|
|
|
/*
|
|
* Includes
|
|
*/
|
|
#include <time.h>
|
|
#include "wins.h"
|
|
#include "nms.h"
|
|
#include "winsevt.h"
|
|
#include "winsmsc.h"
|
|
#include "winstmm.h"
|
|
#include "winsque.h"
|
|
#include "winsthd.h"
|
|
|
|
/*
|
|
* Local Macro Declarations
|
|
*/
|
|
|
|
/*
|
|
* Local Typedef Declarations
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
* Global Variable Definitions
|
|
*/
|
|
|
|
HANDLE WinsTmmHeapHdl; //handle of heap to allocate TMM work items
|
|
// from
|
|
|
|
/*
|
|
* Local Variable Definitions
|
|
*/
|
|
STATIC CRITICAL_SECTION sTmmReqCntCrtSec;
|
|
STATIC DWORD sTmmReqCnt = 0;
|
|
|
|
//
|
|
// This stores the req. id of the request at the top of the queue
|
|
// (i.e. one for which the timer thread is doing a timed wait)
|
|
//
|
|
STATIC DWORD sReqIdOfCurrReq;
|
|
/*
|
|
* Local Function Prototype Declarations
|
|
*/
|
|
STATIC
|
|
DWORD
|
|
TmmThdInitFn(
|
|
LPVOID pParam
|
|
);
|
|
|
|
VOID
|
|
HandleReq(
|
|
OUT LPLONG pDeltaTime
|
|
);
|
|
|
|
VOID
|
|
SignalClient(
|
|
VOID
|
|
);
|
|
|
|
|
|
/* prototypes for functions local to this module go here */
|
|
|
|
|
|
VOID
|
|
WinsTmmInsertEntry(
|
|
PQUE_TMM_REQ_WRK_ITM_T pPassedWrkItm,
|
|
WINS_CLIENT_E Client_e,
|
|
QUE_CMD_TYP_E CmdTyp_e,
|
|
BOOL fResubmit,
|
|
time_t AbsTime,
|
|
DWORD TimeInt,
|
|
PQUE_HD_T pRspQueHd,
|
|
LPVOID pClientCtx,
|
|
DWORD MagicNo,
|
|
PWINSTMM_TIMER_REQ_ACCT_T pSetTimerReqs
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to insert a work item into the Timer Manager's
|
|
request queue (delta queue). It allocates a work item if required
|
|
(if pWrkItm != NULL) and enqueues it in its proper position in
|
|
the delta queue of the TMM thread. It then signals the TMM thread
|
|
if required.
|
|
|
|
Arguments:
|
|
|
|
pWrkItm - work item to queue (if pWrkItm != NULL)
|
|
Client_e - id. of client that submitted the request
|
|
CmdTyp_e - type of command (set timer, modify timer, etc)
|
|
fResubmit - Is it a resubmit
|
|
AbsTime - absolute time (in secs) at which the client needs to be
|
|
notified
|
|
TimeInt - time interval in seconds after which the client needs to
|
|
be notified
|
|
pRspQueHd - Que Head of the queue where the notification needs to be
|
|
queued
|
|
pClientCtx - Client's context that needs to be put in the work item
|
|
pSetTimerReqs - For future extensibility
|
|
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
|
|
Return Value:
|
|
|
|
None
|
|
Error Handling:
|
|
|
|
Called by:
|
|
|
|
Side Effects:
|
|
|
|
Comments:
|
|
None
|
|
--*/
|
|
|
|
{
|
|
|
|
PQUE_TMM_REQ_WRK_ITM_T pWrkItm;
|
|
PQUE_TMM_REQ_WRK_ITM_T pTmp;
|
|
BOOL fInserted = FALSE;
|
|
|
|
UNREFERENCED_PARAMETER(pSetTimerReqs);
|
|
|
|
if (!pPassedWrkItm)
|
|
{
|
|
QueAllocWrkItm(
|
|
WinsTmmHeapHdl,
|
|
sizeof(QUE_TMM_REQ_WRK_ITM_T),
|
|
&pWrkItm
|
|
);
|
|
}
|
|
else
|
|
{
|
|
pWrkItm = pPassedWrkItm;
|
|
}
|
|
|
|
//
|
|
// Put a request id (a monotonically increasing number)
|
|
//
|
|
EnterCriticalSection(&sTmmReqCntCrtSec);
|
|
sTmmReqCnt++;
|
|
LeaveCriticalSection(&sTmmReqCntCrtSec);
|
|
pWrkItm->ReqId = sTmmReqCnt;
|
|
|
|
//
|
|
// If work item was allocated or if it is not a resubmit
|
|
// init the rest of the fields appropriately
|
|
//
|
|
pWrkItm->CmdTyp_e = CmdTyp_e;
|
|
pWrkItm->AbsTime = AbsTime;
|
|
pWrkItm->TimeInt = TimeInt;
|
|
pWrkItm->QueTyp_e = QUE_E_WINSTMQ;
|
|
pWrkItm->RspEvtHdl = pRspQueHd->EvtHdl;
|
|
pWrkItm->pRspQueHd = pRspQueHd;
|
|
pWrkItm->pClientCtx = pClientCtx;
|
|
pWrkItm->Client_e = Client_e;
|
|
pWrkItm->MagicNo = MagicNo;
|
|
|
|
EnterCriticalSection(&QueWinsTmmQueHd.CrtSec);
|
|
try {
|
|
if (IsListEmpty(&QueWinsTmmQueHd.Head))
|
|
{
|
|
InsertTailList(&QueWinsTmmQueHd.Head, &pWrkItm->Head);
|
|
if (!SetEvent(QueWinsTmmQueHd.EvtHdl))
|
|
{
|
|
|
|
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_SIGNAL_TMM_ERR);
|
|
DBGPRINT0(EXC, "Could not signal Tmm Thd\n");
|
|
WINS_RAISE_EXC_M(WINS_EXC_SIGNAL_TMM_ERR);
|
|
}
|
|
fInserted = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// get the address of the first entry in the queue.
|
|
//
|
|
pTmp = (PQUE_TMM_REQ_WRK_ITM_T)QueWinsTmmQueHd.Head.Flink;
|
|
|
|
//
|
|
// Go over the circular linked list until we hit the head
|
|
// of the queue
|
|
//
|
|
while(pTmp != (PQUE_TMM_REQ_WRK_ITM_T)&QueWinsTmmQueHd.Head)
|
|
{
|
|
|
|
//
|
|
// If the list entry has a longer timer than the new entry,
|
|
// insert the new entry before it
|
|
//
|
|
if (pTmp->AbsTime > pWrkItm->AbsTime)
|
|
{
|
|
pWrkItm->Head.Flink = &pTmp->Head;
|
|
pWrkItm->Head.Blink = pTmp->Head.Blink;
|
|
pTmp->Head.Blink->Flink = &pWrkItm->Head;
|
|
pTmp->Head.Blink = &pWrkItm->Head;
|
|
fInserted = TRUE;
|
|
|
|
//
|
|
// The element has been inserted. Let us break out
|
|
// of the loop
|
|
//
|
|
break;
|
|
}
|
|
pTmp = (PQUE_TMM_REQ_WRK_ITM_T)pTmp->Head.Flink;
|
|
}
|
|
|
|
}
|
|
//
|
|
// If the entry was not inserted (i.e. all entries in the queue have
|
|
// a shorter expiry than our entry), insert the entry at the
|
|
// end of the list
|
|
//
|
|
if (!fInserted)
|
|
{
|
|
InsertTailList(&QueWinsTmmQueHd.Head, &pWrkItm->Head);
|
|
}
|
|
|
|
//
|
|
// If this is the top most entry in the queue and there is
|
|
// at least one more entry in the queue, signal the TMM
|
|
// thread so that it can start a timer for it. If the above
|
|
// is not true, relax (either the TMM thread has already been
|
|
// signaled (if this is the only item in the queue) or it does not
|
|
// need to be signaled (this is not the top-most item in the queue).
|
|
//
|
|
if (
|
|
(pWrkItm->Head.Blink == &QueWinsTmmQueHd.Head)
|
|
&&
|
|
(pWrkItm->Head.Flink != &QueWinsTmmQueHd.Head)
|
|
)
|
|
{
|
|
if (!SetEvent(QueWinsTmmQueHd.EvtHdl))
|
|
{
|
|
|
|
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_SIGNAL_TMM_ERR);
|
|
DBGPRINT0(EXC, "Could not signal Tmm Thd\n");
|
|
WINS_RAISE_EXC_M(WINS_EXC_SIGNAL_TMM_ERR);
|
|
}
|
|
}
|
|
} // end of try ..
|
|
|
|
finally {
|
|
LeaveCriticalSection(&QueWinsTmmQueHd.CrtSec);
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
WinsTmmInit(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This is the function that initializes the timer manager
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
Init in nms.c
|
|
Side Effects:
|
|
A timer thread is created
|
|
Comments:
|
|
None
|
|
--*/
|
|
|
|
{
|
|
|
|
|
|
STATUS RetStat;
|
|
|
|
//
|
|
// Initialize the critical section guarding the counter for
|
|
// Tmm requests
|
|
//
|
|
InitializeCriticalSection(&sTmmReqCntCrtSec);
|
|
|
|
/*
|
|
* Create heap for allocating name challenge work items
|
|
*/
|
|
DBGPRINT0(HEAP_CRDL, "WinsTmmInit: Tmm. Chl. heap\n");
|
|
WinsTmmHeapHdl = WinsMscHeapCreate(
|
|
0, /*to have mutual exclusion */
|
|
TMM_INIT_HEAP_SIZE
|
|
);
|
|
|
|
InitializeListHead(&QueWinsTmmQueHd.Head);
|
|
|
|
|
|
//
|
|
//
|
|
// Create the timer thread. This function will
|
|
// initialize the critical section and the Evt handle passed
|
|
// to it
|
|
//
|
|
RetStat = WinsMscSetUpThd(
|
|
&QueWinsTmmQueHd, //queue head
|
|
TmmThdInitFn, //init function
|
|
NULL, // no param
|
|
&WinsThdPool.TimerThds[0].ThdHdl,
|
|
&WinsThdPool.TimerThds[0].ThdId
|
|
);
|
|
|
|
if (RetStat == WINS_SUCCESS)
|
|
{
|
|
WinsThdPool.TimerThds[0].fTaken = TRUE;
|
|
WinsThdPool.ThdCount++; //increment the thread count
|
|
}
|
|
else
|
|
{
|
|
WINS_RAISE_EXC_M(WINS_EXC_FAILURE);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
DWORD
|
|
TmmThdInitFn(
|
|
LPVOID pParam
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This is the top-most function of the TMM thread
|
|
|
|
Arguments:
|
|
pParam - Param to the top most function (not used)
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
|
|
Return Value:
|
|
|
|
Success status codes -- WINS_SUCCESS
|
|
Error status codes -- WINS_FAILURE
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
WinsTmmInit
|
|
|
|
Side Effects:
|
|
|
|
Comments:
|
|
None
|
|
--*/
|
|
|
|
{
|
|
|
|
LONG DeltaTime;
|
|
BOOL fSignaled;
|
|
|
|
UNREFERENCED_PARAMETER(pParam);
|
|
|
|
try {
|
|
while(TRUE)
|
|
{
|
|
WinsMscWaitInfinite(QueWinsTmmQueHd.EvtHdl);
|
|
|
|
while(!IsListEmpty(&QueWinsTmmQueHd.Head))
|
|
{
|
|
HandleReq(&DeltaTime);
|
|
|
|
if (DeltaTime != 0)
|
|
{
|
|
//
|
|
// Do a timed wait until either the timer expires
|
|
// or the event is signaled.
|
|
//
|
|
WinsMscWaitTimed(
|
|
QueWinsTmmQueHd.EvtHdl,
|
|
DeltaTime * 1000, //convert to millisecs
|
|
&fSignaled
|
|
);
|
|
|
|
//
|
|
// If signaled (interrupte from the wait), it means
|
|
// that there is a more urgent request in the timer
|
|
// queue.
|
|
//
|
|
if (fSignaled)
|
|
{
|
|
HandleReq(&DeltaTime);
|
|
}
|
|
else //timer expired
|
|
{
|
|
SignalClient();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SignalClient();
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
DBGPRINT0(EXC,
|
|
"TmmThdInitFn: Timer Thread encountered an exception\n");
|
|
WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_TMM_EXC);
|
|
ExitThread(WINS_FAILURE);
|
|
|
|
}
|
|
|
|
//
|
|
// We should never reach here
|
|
//
|
|
ASSERT(0);
|
|
return(WINS_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
HandleReq(
|
|
OUT LPLONG pDeltaTime
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function is called to handle a timer request. The function
|
|
is called when the Timer thread is signaled.
|
|
|
|
Arguments:
|
|
pDeltaTime - Time Interval to wait for before signaling the client
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
TmmThdInitFn
|
|
|
|
Side Effects:
|
|
|
|
Comments:
|
|
None
|
|
--*/
|
|
|
|
{
|
|
|
|
time_t AbsTime;
|
|
time_t CurrTime;
|
|
QUE_CMD_TYP_E CmdTyp_e;
|
|
|
|
|
|
(void)time(&CurrTime);
|
|
EnterCriticalSection(&QueWinsTmmQueHd.CrtSec);
|
|
|
|
//
|
|
// If list is empty, return.
|
|
//
|
|
if (IsListEmpty(&QueWinsTmmQueHd.Head))
|
|
{
|
|
*pDeltaTime = 0;
|
|
LeaveCriticalSection(&QueWinsTmmQueHd.CrtSec);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Retrieve the absolute time corresponding to the
|
|
// first entry in the timer queue.
|
|
//
|
|
AbsTime = ((PQUE_TMM_REQ_WRK_ITM_T)
|
|
(QueWinsTmmQueHd.Head.Flink))->AbsTime;
|
|
CmdTyp_e = ((PQUE_TMM_REQ_WRK_ITM_T)
|
|
(QueWinsTmmQueHd.Head.Flink))->CmdTyp_e;
|
|
|
|
ASSERT(CmdTyp_e == QUE_E_CMD_SET_TIMER);
|
|
|
|
//
|
|
// Store the request id of the request that we will wait on
|
|
// in the STATIC
|
|
//
|
|
sReqIdOfCurrReq = ((PQUE_TMM_REQ_WRK_ITM_T)
|
|
(QueWinsTmmQueHd.Head.Flink))->ReqId;
|
|
LeaveCriticalSection(&QueWinsTmmQueHd.CrtSec);
|
|
|
|
switch(CmdTyp_e)
|
|
{
|
|
case(QUE_E_CMD_SET_TIMER):
|
|
*pDeltaTime = (LONG)(AbsTime - CurrTime);
|
|
|
|
//
|
|
// It is possible that we might have a small
|
|
// negative value here, just because of the
|
|
// time it took to process the request.
|
|
//
|
|
if (*pDeltaTime < 0)
|
|
{
|
|
*pDeltaTime = 0;
|
|
}
|
|
break;
|
|
case(QUE_E_CMD_MODIFY_TIMER):
|
|
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_SFT_ERR);
|
|
DBGPRINT0(ERR, "Not supported yet\n");
|
|
WINS_RAISE_EXC_M(WINS_EXC_FATAL_ERR);
|
|
break;
|
|
case(QUE_E_CMD_CANCEL_TIMER):
|
|
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_SFT_ERR);
|
|
DBGPRINT0(ERR, "Not supported yet\n");
|
|
WINS_RAISE_EXC_M(WINS_EXC_FATAL_ERR);
|
|
break;
|
|
default:
|
|
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_SFT_ERR);
|
|
DBGPRINT1(EXC, "Wierd: Invalid Request. CmdType is (%d), \n", CmdTyp_e);
|
|
WINS_RAISE_EXC_M(WINS_EXC_FATAL_ERR);
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
SignalClient(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function is called to notify the client that its
|
|
timer request has expired.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
TmmThdInitFn
|
|
|
|
Side Effects:
|
|
|
|
Comments:
|
|
None
|
|
--*/
|
|
|
|
{
|
|
PQUE_TMM_REQ_WRK_ITM_T pWrkItm;
|
|
|
|
FUTURES("Optimize to signal all clients whose requests have expired")
|
|
EnterCriticalSection(&QueWinsTmmQueHd.CrtSec);
|
|
pWrkItm = (PQUE_TMM_REQ_WRK_ITM_T)RemoveHeadList(&QueWinsTmmQueHd.Head);
|
|
|
|
//
|
|
// If the top of the queue has a different work item than the
|
|
// one we were doing a timed wait for, it means that the there has
|
|
// been a queue purge (see WinsTmmDeleteEntry. Simply return.
|
|
//
|
|
if (sReqIdOfCurrReq != pWrkItm->ReqId)
|
|
{
|
|
LeaveCriticalSection(&QueWinsTmmQueHd.CrtSec);
|
|
return;
|
|
}
|
|
LeaveCriticalSection(&QueWinsTmmQueHd.CrtSec);
|
|
|
|
pWrkItm->CmdTyp_e = QUE_E_CMD_TIMER_EXPIRED;
|
|
|
|
//
|
|
// Insert into client's queue
|
|
//
|
|
QueInsertWrkItm(
|
|
&pWrkItm->Head,
|
|
0, //not used -- change to an enumrator val
|
|
pWrkItm->pRspQueHd
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
WinsTmmDeleteReqs(
|
|
WINS_CLIENT_E Client_e
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function is called to delete all set timer requests submitted
|
|
by a client
|
|
|
|
Arguments:
|
|
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
|
|
Return Value:
|
|
|
|
None
|
|
Error Handling:
|
|
|
|
Called by:
|
|
Reconfig (in rplpull.c)
|
|
Side Effects:
|
|
|
|
Comments:
|
|
In the future, enhance this function so that it delete requests
|
|
based on other criteria
|
|
|
|
--*/
|
|
{
|
|
|
|
PQUE_TMM_REQ_WRK_ITM_T pTmp;
|
|
PQUE_TMM_REQ_WRK_ITM_T pMemToDealloc;
|
|
BOOL fFirstEntry = FALSE;
|
|
|
|
EnterCriticalSection(&QueWinsTmmQueHd.CrtSec);
|
|
try {
|
|
|
|
if (!IsListEmpty(&QueWinsTmmQueHd.Head))
|
|
{
|
|
//
|
|
// get the address of the first entry in the queue.
|
|
//
|
|
pTmp = (PQUE_TMM_REQ_WRK_ITM_T)QueWinsTmmQueHd.Head.Flink;
|
|
|
|
//
|
|
// We loop until we get to the head of the list (the linked
|
|
// list is a circular list)
|
|
//
|
|
while(pTmp != (PQUE_TMM_REQ_WRK_ITM_T)&QueWinsTmmQueHd.Head)
|
|
{
|
|
|
|
//
|
|
// If the entry was queued by the client, get rid of
|
|
// it
|
|
//
|
|
if (pTmp->Client_e == Client_e)
|
|
{
|
|
//
|
|
// If this is the first entry in the queue, it
|
|
// means that the timer thread is doing a
|
|
// wait on it. Signal it.
|
|
//
|
|
if (
|
|
!fFirstEntry
|
|
&&
|
|
(pTmp->Head.Blink == &QueWinsTmmQueHd.Head)
|
|
)
|
|
{
|
|
fFirstEntry = TRUE;
|
|
}
|
|
|
|
|
|
// if (pTmp->Head.Flink == &QueWinsTmmQueHd.Head)
|
|
if (fFirstEntry)
|
|
{
|
|
if (!SetEvent(QueWinsTmmQueHd.EvtHdl))
|
|
{
|
|
|
|
WINSEVT_LOG_M(
|
|
WINS_FAILURE,
|
|
WINS_EVT_SIGNAL_TMM_ERR
|
|
);
|
|
DBGPRINT0(EXC,
|
|
"Could not signal Tmm for canceling a request\n");
|
|
WINS_RAISE_EXC_M(WINS_EXC_SIGNAL_TMM_ERR);
|
|
}
|
|
}
|
|
|
|
//
|
|
// unlink the request
|
|
//
|
|
pTmp->Head.Flink->Blink = pTmp->Head.Blink;
|
|
pTmp->Head.Blink->Flink = pTmp->Head.Flink;
|
|
pMemToDealloc = pTmp;
|
|
pTmp = (PQUE_TMM_REQ_WRK_ITM_T)pTmp->Head.Flink;
|
|
|
|
//
|
|
// Dealloc the dequeued work item
|
|
//
|
|
WinsTmmDeallocReq(pMemToDealloc);
|
|
}
|
|
else
|
|
{
|
|
pTmp = (PQUE_TMM_REQ_WRK_ITM_T)pTmp->Head.Flink;
|
|
}
|
|
}
|
|
}
|
|
} // end of try block
|
|
except(EXCEPTION_EXECUTE_HANDLER) {
|
|
DBGPRINT1(EXC, "WinsTmmDeleteReqs: Got exception (%x)\n",
|
|
(DWORD)GetExceptionCode());
|
|
WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_TMM_EXC);
|
|
}
|
|
LeaveCriticalSection(&QueWinsTmmQueHd.CrtSec);
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
__inline
|
|
VOID
|
|
WinsTmmDeallocReq(
|
|
PQUE_TMM_REQ_WRK_ITM_T pWrkItm
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function is called to deallocate a timer request work item
|
|
|
|
Arguments:
|
|
|
|
pWrkItm - Work Item
|
|
|
|
Externals Used:
|
|
WinsTmmHeapHdl
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
RplPullInit
|
|
|
|
Side Effects:
|
|
|
|
Comments:
|
|
None
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// deallocate the work item
|
|
//
|
|
QueDeallocWrkItm(
|
|
WinsTmmHeapHdl,
|
|
pWrkItm
|
|
);
|
|
|
|
return;
|
|
|
|
}
|