259 lines
5.2 KiB
C
259 lines
5.2 KiB
C
|
/*
|
||
|
|
||
|
Copyright (c) 1998, Microsoft Corporation, all rights reserved
|
||
|
|
||
|
Description:
|
||
|
|
||
|
History:
|
||
|
|
||
|
*/
|
||
|
|
||
|
#include "timer_.h"
|
||
|
|
||
|
LONG g_TimerLockUninit = 0;
|
||
|
/*
|
||
|
|
||
|
Returns:
|
||
|
Win 32 error
|
||
|
|
||
|
Notes:
|
||
|
Its a good idea to always call RasDhcpTimerUninitialize after calling
|
||
|
RasDhcpTimerInitialize, even if RasDhcpTimerInitialize failed.
|
||
|
|
||
|
*/
|
||
|
|
||
|
DWORD
|
||
|
RasDhcpTimerInitialize(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
DWORD dwErr = NO_ERROR;
|
||
|
|
||
|
g_TimerLockUninit = 0;
|
||
|
RasDhcpTimerShutdown = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||
|
|
||
|
if (NULL == RasDhcpTimerShutdown)
|
||
|
{
|
||
|
dwErr = GetLastError();
|
||
|
goto LEnd;
|
||
|
}
|
||
|
|
||
|
Status = RtlCreateTimerQueue(&RasDhcpTimerQueueHandle);
|
||
|
|
||
|
if (STATUS_SUCCESS != Status)
|
||
|
{
|
||
|
RasDhcpTimerQueueHandle = NULL;
|
||
|
dwErr = Status;
|
||
|
TraceHlp("RtlCreateTimerQueue failed and returned %d", dwErr);
|
||
|
goto LEnd;
|
||
|
}
|
||
|
|
||
|
RasDhcpTimerPrevTime = time(NULL);
|
||
|
Status = RtlCreateTimer(RasDhcpTimerQueueHandle, &RasDhcpTimerHandle,
|
||
|
RasDhcpTimerFunc, NULL, 0, TIMER_PERIOD,
|
||
|
WT_EXECUTELONGFUNCTION);
|
||
|
|
||
|
if (STATUS_SUCCESS != Status)
|
||
|
{
|
||
|
dwErr = Status;
|
||
|
TraceHlp("RtlCreateTimer failed and returned %d", dwErr);
|
||
|
goto LEnd;
|
||
|
}
|
||
|
|
||
|
LEnd:
|
||
|
|
||
|
if (NO_ERROR != dwErr)
|
||
|
{
|
||
|
if (NULL != RasDhcpTimerQueueHandle)
|
||
|
{
|
||
|
Status = RtlDeleteTimerQueueEx(RasDhcpTimerQueueHandle, (HANDLE)-1);
|
||
|
RTASSERT(STATUS_SUCCESS == Status);
|
||
|
RasDhcpTimerQueueHandle = NULL;
|
||
|
}
|
||
|
|
||
|
if (NULL != RasDhcpTimerShutdown)
|
||
|
{
|
||
|
CloseHandle(RasDhcpTimerShutdown);
|
||
|
RasDhcpTimerShutdown = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return(dwErr);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
|
||
|
Returns:
|
||
|
VOID
|
||
|
|
||
|
Notes:
|
||
|
RasDhcpTimerUninitialize can be called even if RasDhcpTimerInitialize
|
||
|
failed.
|
||
|
|
||
|
*/
|
||
|
|
||
|
VOID
|
||
|
RasDhcpTimerUninitialize(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
DWORD dwRet;
|
||
|
LONG lPrev = 1;
|
||
|
|
||
|
|
||
|
// Signal the timer thread to shutdown.
|
||
|
lPrev = InterlockedExchangeAdd(&g_TimerLockUninit, 1);
|
||
|
if ( lPrev > 1 )
|
||
|
return;
|
||
|
|
||
|
if (NULL != RasDhcpTimerQueueHandle)
|
||
|
{
|
||
|
RTASSERT(NULL != RasDhcpTimerShutdown);
|
||
|
SetEvent(RasDhcpTimerShutdown);
|
||
|
|
||
|
Status = RtlDeleteTimerQueueEx(RasDhcpTimerQueueHandle, (HANDLE)-1);
|
||
|
RTASSERT(STATUS_SUCCESS == Status);
|
||
|
RasDhcpTimerQueueHandle = NULL;
|
||
|
}
|
||
|
|
||
|
if (NULL != RasDhcpTimerShutdown)
|
||
|
{
|
||
|
CloseHandle(RasDhcpTimerShutdown);
|
||
|
RasDhcpTimerShutdown = NULL;
|
||
|
}
|
||
|
|
||
|
// timer.c didn't alloc the nodes in the linked list.
|
||
|
// So we don't free them here.
|
||
|
RasDhcpTimerListHead = NULL;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
Notes:
|
||
|
|
||
|
*/
|
||
|
|
||
|
VOID
|
||
|
RasDhcpTimerFunc(
|
||
|
IN VOID* pArg1,
|
||
|
IN BOOLEAN fArg2
|
||
|
)
|
||
|
{
|
||
|
TIMERLIST* pTimer;
|
||
|
TIMERLIST* pTmp;
|
||
|
TIMERFUNCTION TimerFunc;
|
||
|
time_t now = time(NULL);
|
||
|
LONG lElapsedTime;
|
||
|
LONG lTime;
|
||
|
|
||
|
if (0 == TryEnterCriticalSection(&RasTimrCriticalSection))
|
||
|
{
|
||
|
// Another thread already owns the critical section
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
lElapsedTime = (LONG)(now - RasDhcpTimerPrevTime);
|
||
|
RasDhcpTimerPrevTime = now;
|
||
|
|
||
|
pTimer = NULL;
|
||
|
|
||
|
while (RasDhcpTimerListHead != NULL)
|
||
|
{
|
||
|
lTime = RasDhcpTimerListHead->tmr_Delta;
|
||
|
|
||
|
if ( lTime > 0)
|
||
|
{
|
||
|
RasDhcpTimerListHead->tmr_Delta -= lElapsedTime;
|
||
|
lElapsedTime -= lTime;
|
||
|
}
|
||
|
|
||
|
if (RasDhcpTimerListHead->tmr_Delta <= 0)
|
||
|
{
|
||
|
pTmp = pTimer;
|
||
|
pTimer = RasDhcpTimerListHead;
|
||
|
RasDhcpTimerListHead = pTimer->tmr_Next;
|
||
|
pTimer->tmr_Next = pTmp;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
while (pTimer != NULL)
|
||
|
{
|
||
|
pTmp = pTimer->tmr_Next;
|
||
|
TimerFunc = pTimer->tmr_TimerFunc;
|
||
|
pTimer->tmr_TimerFunc = NULL;
|
||
|
(*TimerFunc)(RasDhcpTimerShutdown, pTimer);
|
||
|
pTimer = pTmp;
|
||
|
}
|
||
|
|
||
|
LeaveCriticalSection(&RasTimrCriticalSection);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
|
||
|
Returns:
|
||
|
VOID
|
||
|
|
||
|
Notes:
|
||
|
Once the timer thread starts, only it can call RasDhcpTimerSchedule (to
|
||
|
avoid race conditions). The timer thread will call rasDhcpMonitorAddresses
|
||
|
(and hence rasDhcpAllocateAddress), and rasDhcpRenewLease. These functions
|
||
|
will call RasDhcpTimerSchedule. No one else should call these functions or
|
||
|
RasDhcpTimerSchedule. The only exception is RasDhcpInitialize, which can
|
||
|
call RasDhcpTimerSchedule before it creates the timer thread.
|
||
|
|
||
|
*/
|
||
|
|
||
|
VOID
|
||
|
RasDhcpTimerSchedule(
|
||
|
IN TIMERLIST* pNewTimer,
|
||
|
IN LONG DeltaTime,
|
||
|
IN TIMERFUNCTION TimerFunc
|
||
|
)
|
||
|
{
|
||
|
TIMERLIST** ppTimer;
|
||
|
TIMERLIST* pTimer;
|
||
|
|
||
|
pNewTimer->tmr_TimerFunc = TimerFunc;
|
||
|
|
||
|
for (ppTimer = &RasDhcpTimerListHead;
|
||
|
(pTimer = *ppTimer) != NULL;
|
||
|
ppTimer = &pTimer->tmr_Next)
|
||
|
{
|
||
|
if (DeltaTime <= pTimer->tmr_Delta)
|
||
|
{
|
||
|
pTimer->tmr_Delta -= DeltaTime;
|
||
|
break;
|
||
|
}
|
||
|
DeltaTime -= pTimer->tmr_Delta;
|
||
|
}
|
||
|
|
||
|
pNewTimer->tmr_Delta = DeltaTime;
|
||
|
pNewTimer->tmr_Next = *ppTimer;
|
||
|
*ppTimer = pNewTimer;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
Notes:
|
||
|
|
||
|
*/
|
||
|
|
||
|
VOID
|
||
|
RasDhcpTimerRunNow(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
RtlUpdateTimer(RasDhcpTimerQueueHandle, RasDhcpTimerHandle, 0,
|
||
|
TIMER_PERIOD);
|
||
|
}
|