You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
468 lines
12 KiB
468 lines
12 KiB
// Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved
|
|
/*---------------------------------------------------------
|
|
Filename: timer.cpp
|
|
Written By: B.Rajeev
|
|
----------------------------------------------------------*/
|
|
|
|
#include "precomp.h"
|
|
#include "common.h"
|
|
#include "sync.h"
|
|
#include "timer.h"
|
|
#include "message.h"
|
|
#include "dummy.h"
|
|
|
|
#include "flow.h"
|
|
#include "frame.h"
|
|
#include "ssent.h"
|
|
#include "idmap.h"
|
|
#include "opreg.h"
|
|
|
|
#include "session.h"
|
|
|
|
SnmpClThreadObject *Timer :: g_timerThread = NULL ;
|
|
UINT Timer :: g_SnmpWmTimer = SNMP_WM_TIMER ;
|
|
|
|
// static CriticalSection and CMap
|
|
CriticalSection Timer::timer_CriticalSection;
|
|
TimerMapping Timer::timer_mapping;
|
|
|
|
TimerEventId Timer :: next_timer_event_id = ILLEGAL_TIMER_EVENT_ID+1 ;
|
|
Window *SnmpTimerObject :: window = NULL ;
|
|
CMap <UINT_PTR,UINT_PTR,SnmpTimerObject *,SnmpTimerObject *> SnmpTimerObject :: timerMap ;
|
|
|
|
SnmpClThreadObject :: SnmpClThreadObject () : SnmpThreadObject ( "SnmpCl" )
|
|
{
|
|
}
|
|
|
|
void SnmpClThreadObject :: Initialise ()
|
|
{
|
|
}
|
|
|
|
void SnmpClThreadObject :: Uninitialise ()
|
|
{
|
|
delete SnmpTimerObject :: window ;
|
|
SnmpTimerObject :: window = NULL ;
|
|
delete this ;
|
|
}
|
|
|
|
SnmpClTrapThreadObject :: SnmpClTrapThreadObject () : SnmpThreadObject ( "SnmpClTrapThread" )
|
|
{
|
|
}
|
|
|
|
void SnmpClTrapThreadObject :: Initialise ()
|
|
{
|
|
DebugMacro4(
|
|
|
|
SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
|
|
|
|
__FILE__,__LINE__,
|
|
L"SnmpClTrapThreadObject::Initialise: Initialised!!\n"
|
|
|
|
) ;
|
|
)
|
|
}
|
|
|
|
void SnmpClTrapThreadObject :: Uninitialise ()
|
|
{
|
|
DebugMacro4(
|
|
|
|
SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
|
|
|
|
__FILE__,__LINE__,
|
|
L"SnmpClTrapThreadObject::Uninitialise: About to destroy trap thread\n"
|
|
|
|
) ;
|
|
)
|
|
delete this ;
|
|
|
|
DebugMacro4(
|
|
|
|
SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
|
|
|
|
__FILE__,__LINE__,
|
|
L"SnmpClTrapThreadObject::Uninitialise: Trap thread destroyed!!\n"
|
|
|
|
) ;
|
|
)
|
|
}
|
|
|
|
|
|
Timer::Timer(SnmpImpSession &session)
|
|
{
|
|
Timer::session = &session;
|
|
}
|
|
|
|
BOOL Timer::CreateCriticalSection()
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
void Timer::DestroyCriticalSection()
|
|
{
|
|
}
|
|
|
|
BOOL Timer::InitializeStaticComponents()
|
|
{
|
|
return CreateCriticalSection();
|
|
}
|
|
|
|
void Timer::DestroyStaticComponents()
|
|
{
|
|
DestroyCriticalSection();
|
|
}
|
|
|
|
// generates and returns a new event id
|
|
// associates the pair (event_id, waiting_message)
|
|
// creates the timer event
|
|
TimerEventId Timer::SetTimerEvent(UINT timeout_value)
|
|
{
|
|
TimerEventId suggested_event_id = next_timer_event_id++;
|
|
if ( suggested_event_id == ILLEGAL_TIMER_EVENT_ID )
|
|
suggested_event_id = next_timer_event_id++;
|
|
|
|
// let the dummy session receive the window messages for timer events
|
|
TimerEventId event_id =
|
|
SnmpSetTimer( session->m_SessionWindow.GetWindowHandle(), suggested_event_id,
|
|
timeout_value, NULL );
|
|
|
|
if ( (event_id == ILLEGAL_TIMER_EVENT_ID) ||
|
|
(event_id != suggested_event_id) )
|
|
throw GeneralException(Snmp_Error, Snmp_Local_Error,__FILE__,__LINE__);
|
|
|
|
return event_id;
|
|
}
|
|
|
|
// generates and returns a new event id
|
|
// associates the pair (event_id, waiting_message)
|
|
// creates the timer event
|
|
void Timer::SetMessageTimerEvent(WaitingMessage &waiting_message)
|
|
{
|
|
CriticalSectionLock session_lock(session->session_CriticalSection);
|
|
|
|
if ( !session_lock.GetLock(INFINITE) )
|
|
return; // no use throwing exception
|
|
|
|
TimerEventId event_id = session->timer_event_id;
|
|
// register the timer event in both the instance CMap and the global CMap
|
|
waiting_message_mapping.AddTail ( &waiting_message ) ;
|
|
|
|
session_lock.UnLock();
|
|
|
|
CriticalSectionLock timer_lock(Timer::timer_CriticalSection);
|
|
|
|
if ( !timer_lock.GetLock(INFINITE) )
|
|
throw GeneralException ( Snmp_Error , Snmp_Local_Error,__FILE__,__LINE__ ) ;
|
|
|
|
timer_mapping[event_id] = this;
|
|
|
|
timer_lock.UnLock();
|
|
|
|
}
|
|
|
|
// Removes the association (event_id, waiting_message)
|
|
// and also kills the registered timer event
|
|
void Timer::CancelMessageTimer(WaitingMessage &waiting_message,TimerEventId event_id)
|
|
{
|
|
CriticalSectionLock session_lock(session->session_CriticalSection);
|
|
|
|
if ( !session_lock.GetLock(INFINITE) )
|
|
return; // no use throwing exception
|
|
|
|
// remove the timer event from the instance CMap
|
|
|
|
POSITION t_Position = waiting_message_mapping.GetHeadPosition () ;
|
|
while ( t_Position )
|
|
{
|
|
POSITION t_OldPosition = t_Position ;
|
|
WaitingMessage *t_Message = waiting_message_mapping.GetNext ( t_Position ) ;
|
|
if ( t_Message == & waiting_message )
|
|
{
|
|
waiting_message_mapping.RemoveAt(t_OldPosition);
|
|
break ;
|
|
}
|
|
}
|
|
|
|
session_lock.UnLock();
|
|
|
|
DebugMacro4(
|
|
|
|
SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
|
|
|
|
__FILE__,__LINE__,
|
|
L"Cancelled Message TimerEvent %d\n", event_id
|
|
) ;
|
|
)
|
|
|
|
}
|
|
|
|
|
|
// Removes the association (event_id, waiting_message)
|
|
// and also kills the registered timer event
|
|
void Timer::CancelTimer(TimerEventId event_id)
|
|
{
|
|
CriticalSectionLock timer_lock(Timer::timer_CriticalSection);
|
|
|
|
if ( !timer_lock.GetLock(INFINITE) )
|
|
throw GeneralException ( Snmp_Error , Snmp_Local_Error,__FILE__,__LINE__ ) ;
|
|
|
|
// remove the timer event from the global CMap
|
|
timer_mapping.RemoveKey(event_id);
|
|
|
|
timer_lock.UnLock();
|
|
|
|
SnmpKillTimer(NULL, event_id);
|
|
|
|
DebugMacro4(
|
|
|
|
SnmpDebugLog :: s_SnmpDebugLog->WriteFileAndLine (
|
|
|
|
__FILE__,__LINE__,
|
|
L"Cancelled TimerEvent %d\n", event_id
|
|
) ;
|
|
)
|
|
}
|
|
|
|
// it determines the corresponding Timer and calls
|
|
// its TimerEventNotification with the appropriate parameters
|
|
void CALLBACK Timer::HandleGlobalEvent(HWND hWnd ,UINT message,
|
|
UINT_PTR idEvent, DWORD dwTime)
|
|
{
|
|
CriticalSectionLock timer_lock(Timer::timer_CriticalSection);
|
|
|
|
if ( !timer_lock.GetLock(INFINITE) )
|
|
throw GeneralException ( Snmp_Error , Snmp_Local_Error,__FILE__,__LINE__ ) ;
|
|
|
|
Timer *timer;
|
|
TimerEventId event_id = idEvent;
|
|
BOOL found = timer_mapping.Lookup(event_id, timer);
|
|
|
|
timer_lock.UnLock();
|
|
|
|
// if no such timer event, return
|
|
if ( !found )
|
|
return;
|
|
|
|
// let the timer handle the event
|
|
timer->TimerEventNotification(event_id);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// used by the event handler to notify the timer event.
|
|
// it must notify the corresponding waiting message
|
|
void Timer::TimerEventNotification(TimerEventId event_id)
|
|
{
|
|
CriticalSectionLock session_lock(session->session_CriticalSection);
|
|
|
|
if ( !session_lock.GetLock(INFINITE) )
|
|
return; // no use throwing exception
|
|
|
|
WaitingMessage *waiting_message;
|
|
|
|
// identify the waiting message corresponding to
|
|
// the event_id. if no such event, ignore it
|
|
|
|
POSITION t_Position = waiting_message_mapping.GetHeadPosition () ;
|
|
while ( t_Position )
|
|
{
|
|
waiting_message = waiting_message_mapping.GetNext ( t_Position ) ;
|
|
// notify the waiting message of the event
|
|
waiting_message->TimerNotification();
|
|
}
|
|
|
|
// session_lock.UnLock(); The lock may be released at this point
|
|
}
|
|
|
|
// remove all the (timer_event_id, timer) associations
|
|
// from the static mapping data structure
|
|
Timer::~Timer(void)
|
|
{
|
|
WaitingMessage *waiting_message;
|
|
|
|
POSITION current = waiting_message_mapping.GetHeadPosition();
|
|
|
|
while ( current != NULL )
|
|
{
|
|
waiting_message = waiting_message_mapping.GetNext(current);
|
|
|
|
TimerEventId event_id = waiting_message->GetTimerEventId () ;
|
|
|
|
CriticalSectionLock timer_lock(Timer::timer_CriticalSection);
|
|
|
|
if ( !timer_lock.GetLock(INFINITE) )
|
|
throw GeneralException ( Snmp_Error , Snmp_Local_Error,__FILE__,__LINE__ ) ;
|
|
|
|
timer_mapping.RemoveKey ( event_id );
|
|
|
|
timer_lock.UnLock();
|
|
|
|
SnmpKillTimer(NULL, event_id );
|
|
}
|
|
|
|
waiting_message_mapping.RemoveAll();
|
|
}
|
|
|
|
SnmpTimerObject :: SnmpTimerObject (
|
|
|
|
HWND hWndArg, // handle of window for timer messages
|
|
UINT_PTR timerIdArg, // timer identifier
|
|
UINT elapsedArg, // time-out value
|
|
TIMERPROC lpTimerFuncArg // address of timer procedure
|
|
|
|
) : hWnd ( hWndArg ) ,
|
|
timerId ( timerIdArg ) ,
|
|
lpTimerFunc ( lpTimerFuncArg )
|
|
{
|
|
if ( ! window )
|
|
window = new Window ;
|
|
|
|
timerId = SetTimer (
|
|
|
|
window->GetWindowHandle(),
|
|
timerId ,
|
|
elapsedArg ,
|
|
lpTimerFunc
|
|
) ;
|
|
|
|
CriticalSectionLock session_lock(Timer::timer_CriticalSection);
|
|
|
|
if ( !session_lock.GetLock(INFINITE) )
|
|
throw GeneralException ( Snmp_Error , Snmp_Local_Error,__FILE__,__LINE__ ) ;
|
|
|
|
if ( timerId )
|
|
{
|
|
timerMap [ timerId ] = this ;
|
|
}
|
|
else
|
|
throw GeneralException ( Snmp_Error , Snmp_Local_Error,__FILE__,__LINE__ ) ;
|
|
}
|
|
|
|
SnmpTimerObject :: ~SnmpTimerObject ()
|
|
{
|
|
CriticalSectionLock session_lock(Timer::timer_CriticalSection);
|
|
|
|
if ( !session_lock.GetLock(INFINITE) )
|
|
throw GeneralException ( Snmp_Error , Snmp_Local_Error,__FILE__,__LINE__ ) ;
|
|
|
|
timerMap.RemoveKey ( timerId );
|
|
|
|
if (window)
|
|
{
|
|
KillTimer ( window->GetWindowHandle () , timerId ) ;
|
|
}
|
|
}
|
|
|
|
void SnmpTimerObject :: TimerNotification ( HWND hWnd , UINT timerId )
|
|
{
|
|
:: WaitPostMessage ( hWnd , Timer :: g_SnmpWmTimer , timerId , 0 ) ;
|
|
}
|
|
|
|
SnmpSetTimerObject :: SnmpSetTimerObject (
|
|
|
|
HWND hWndArg, // handle of window for timer messages
|
|
UINT_PTR nIDEventArg, // timer identifier
|
|
UINT uElapseArg, // time-out value
|
|
TIMERPROC lpTimerFuncArg // address of timer procedure
|
|
|
|
) : hWnd ( hWndArg ) ,
|
|
timerId ( nIDEventArg ) ,
|
|
elapsedTime ( uElapseArg ) ,
|
|
lpTimerFunc ( lpTimerFuncArg )
|
|
{
|
|
}
|
|
|
|
SnmpSetTimerObject :: ~SnmpSetTimerObject ()
|
|
{
|
|
}
|
|
|
|
void SnmpSetTimerObject :: Process ()
|
|
{
|
|
SnmpTimerObject *object = new SnmpTimerObject (
|
|
|
|
hWnd ,
|
|
timerId ,
|
|
elapsedTime ,
|
|
lpTimerFunc
|
|
) ;
|
|
|
|
Complete () ;
|
|
}
|
|
|
|
SnmpKillTimerObject :: SnmpKillTimerObject (
|
|
|
|
HWND hWndArg , // handle of window that installed timer
|
|
UINT_PTR uIDEventArg // timer identifier
|
|
|
|
) : hWnd ( hWndArg ) ,
|
|
timerId ( uIDEventArg ) ,
|
|
status ( TRUE )
|
|
{
|
|
}
|
|
|
|
void SnmpKillTimerObject :: Process ()
|
|
{
|
|
CriticalSectionLock session_lock(Timer::timer_CriticalSection);
|
|
|
|
if ( !session_lock.GetLock(INFINITE) )
|
|
throw GeneralException ( Snmp_Error , Snmp_Local_Error,__FILE__,__LINE__ ) ;
|
|
|
|
SnmpTimerObject *object ;
|
|
if ( SnmpTimerObject :: timerMap.Lookup ( timerId , object ) )
|
|
{
|
|
delete object ;
|
|
}
|
|
else
|
|
{
|
|
status = FALSE ;
|
|
}
|
|
|
|
Complete () ;
|
|
}
|
|
|
|
UINT_PTR SnmpSetTimer (
|
|
|
|
HWND hWnd, // handle of window for timer messages
|
|
UINT_PTR nIDEvent, // timer identifier
|
|
UINT uElapse, // time-out value,
|
|
TIMERPROC lpTimerFunc // address of timer procedure
|
|
)
|
|
{
|
|
SnmpSetTimerObject object ( hWnd , nIDEvent , uElapse , lpTimerFunc ) ;
|
|
Timer :: g_timerThread->ScheduleTask ( object ) ;
|
|
object.Exec () ;
|
|
if ( object.Wait () )
|
|
{
|
|
Timer :: g_timerThread->ReapTask ( object ) ;
|
|
return object.GetTimerId () ;
|
|
}
|
|
else
|
|
{
|
|
Timer :: g_timerThread->ReapTask ( object ) ;
|
|
return FALSE ;
|
|
}
|
|
}
|
|
|
|
BOOL SnmpKillTimer (
|
|
|
|
HWND hWnd, // handle of window that installed timer
|
|
UINT_PTR uIDEvent // timer identifier
|
|
)
|
|
{
|
|
SnmpKillTimerObject object ( hWnd , uIDEvent ) ;
|
|
|
|
Timer :: g_timerThread->ScheduleTask ( object ) ;
|
|
|
|
object.Exec () ;
|
|
if ( object.Wait () )
|
|
{
|
|
Timer :: g_timerThread->ReapTask ( object ) ;
|
|
return object.GetStatus () ;
|
|
}
|
|
else
|
|
{
|
|
Timer :: g_timerThread->ReapTask ( object ) ;
|
|
return FALSE ;
|
|
}
|
|
}
|
|
|