--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/realtimenetprots/sipfw/SIP/LightWeightTimer/src/TimerManager.cpp Tue Feb 02 01:03:15 2010 +0200
@@ -0,0 +1,472 @@
+// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// Name : timermanager.cpp
+// Part of : LightWeightTimer
+// Version : SIP/4.0
+//
+
+
+
+#include "SipAssert.h"
+#include "TimerManager.h"
+#include "timerrequest.h"
+#include "timerstore.h"
+#include "singletimer.h"
+#include "timerlog.h"
+
+
+// -----------------------------------------------------------------------------
+// CTimerManager::NewL
+// -----------------------------------------------------------------------------
+//
+CTimerManager* CTimerManager::NewL()
+ {
+ CTimerManager* self = CTimerManager::NewLC();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+// -----------------------------------------------------------------------------
+// CTimerManager::NewLC
+// -----------------------------------------------------------------------------
+//
+CTimerManager* CTimerManager::NewLC()
+ {
+ CTimerManager* self = new (ELeave) CTimerManager();
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ return self;
+ }
+
+// -----------------------------------------------------------------------------
+// CTimerManager::CTimerManager
+// -----------------------------------------------------------------------------
+//
+CTimerManager::CTimerManager() :
+ iTimerIdCounter(KReservedTimer),
+ iNowExpiring(EFalse)
+ {
+ }
+
+// -----------------------------------------------------------------------------
+// CTimerManager::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CTimerManager::ConstructL()
+ {
+ iTimerStore = CTimerStore::NewL();
+ iTimer = CSingleTimer::NewL(*this);
+ }
+
+// -----------------------------------------------------------------------------
+// CTimerManager::~CTimerManager
+// -----------------------------------------------------------------------------
+//
+CTimerManager::~CTimerManager()
+ {
+ delete iTimerStore;
+ delete iTimer;
+ }
+
+// -----------------------------------------------------------------------------
+// CTimerManager::StartL
+// -----------------------------------------------------------------------------
+//
+TTimerId
+CTimerManager::StartL(MExpirationHandler* aObserver, TUint aMilliseconds)
+ {
+ __TEST_INVARIANT;
+ __ASSERT_ALWAYS(aObserver, User::Leave(KErrArgument));
+
+ return StartL(aObserver, aMilliseconds, NULL);
+ }
+
+// -----------------------------------------------------------------------------
+// CTimerManager::StartL
+// -----------------------------------------------------------------------------
+//
+TTimerId CTimerManager::StartL(MExpirationHandler* aObserver,
+ TUint aMilliseconds,
+ TAny* aTimerParam)
+ {
+ __TEST_INVARIANT;
+ __ASSERT_ALWAYS(aObserver, User::Leave(KErrArgument));
+
+ TTimerId newTimerId(NewTimerId());
+
+#if defined(WRITE_TIMER_LOG)
+ __SIP_INT_LOG2( "LwTimer StartL (id,duration)", newTimerId, aMilliseconds )
+#endif
+
+ iTimerStore->AddL(aObserver,
+ MillisecToTTime(aMilliseconds),
+ newTimerId,
+ aTimerParam);
+
+ //If iNowExpiring is true, timer can't be set now, as execution is inside
+ //MExpirationHandler::TimerExpiredL. Timer will be set when the control
+ //returns from callback to CTimerManager::TimerExpiredL.
+ if (!iNowExpiring)
+ {
+ CheckIsNewTimerShortestL(newTimerId, aMilliseconds);
+ }
+
+ __TEST_INVARIANT;
+ return newTimerId;
+ }
+
+// -----------------------------------------------------------------------------
+// CTimerManager::Stop
+// User is not allowed to stop the internal timer
+// -----------------------------------------------------------------------------
+//
+TInt CTimerManager::Stop(TTimerId aTimerId)
+ {
+ __TEST_INVARIANT;
+
+#if defined(WRITE_TIMER_LOG)
+ __SIP_INT_LOG1( "LwTimer Stop, timer id", aTimerId)
+#endif
+
+ if (aTimerId == KReservedTimer)
+ {
+ return KErrNotFound;
+ }
+
+ TInt index(0);
+ const CTimerRequest* timerReq = iTimerStore->SearchById(aTimerId, index);
+ if (!timerReq)
+ {
+ return KErrNotFound;
+ }
+
+ if (!iTimerStore->Remove(index))
+ {
+ return KErrNotFound;
+ }
+
+ //If Stop is called from MExpirationHandler::TimerExpiredL, this condition
+ //isn't true, as iTimer has TimerId of the expiring timer which was removed
+ //from iTimerStore. So no need to check iNowExpiring flag now.
+ if (aTimerId == iTimer->TimerId())
+ {
+ //The currently running timer was stopped.
+ iTimer->Cancel();
+
+ TRAPD(err, SetTimerWithShortestValueL());
+ if (err != KErrNone)
+ {
+ return err;
+ }
+ }
+
+ __TEST_INVARIANT;
+ return KErrNone;
+ }
+
+// -----------------------------------------------------------------------------
+// CTimerManager::IsRunning
+// Don't reveal the internal timer to user.
+// -----------------------------------------------------------------------------
+//
+TBool CTimerManager::IsRunning(TTimerId aTimerId) const
+ {
+ __TEST_INVARIANT;
+
+ if (aTimerId == KReservedTimer)
+ {
+ return EFalse;
+ }
+
+ TInt dummyIndex(0);
+ return (iTimerStore->SearchById(aTimerId, dummyIndex) != NULL);
+ }
+
+// -----------------------------------------------------------------------------
+// CTimerManager::ExpiresAfter
+// -----------------------------------------------------------------------------
+//
+TInt CTimerManager::ExpiresAfter(
+ TTimerId aTimerId,
+ TUint& aExpiresAfterInMillisecs) const
+ {
+ __TEST_INVARIANT;
+
+ aExpiresAfterInMillisecs = 0;
+
+ TInt index(0);
+ const CTimerRequest* timerReq = iTimerStore->SearchById(aTimerId, index);
+ if (!timerReq)
+ {
+ return KErrNotFound;
+ }
+
+ TTimeToMillisec(timerReq->ExpirationTime(), aExpiresAfterInMillisecs);
+
+ return KErrNone;
+ }
+
+// -----------------------------------------------------------------------------
+// CTimerManager::TimerExpiredL
+// SearchById can return NULL, e.g. in a following case:
+// - User has set two timers with very similar durations and they are the only
+// currently running timers.
+// - User stops the shorter timer, CTimerManager::Stop uses
+// SetTimerWithShortestValueL but as the remaining timer's expiration is so
+// close to the first timer, CSingleTimer uses CSingleTimer::ExpireImmediately
+//- Before CSingleTimer::RunL has chance to be executed, user stops also the
+// remaining timer, which is removed from CTimerStore.
+//- Soon CSingleTimer::RunL is called and leads here but the expiring timer has
+// already been removed and CTimerStore::SearchById returns NULL.
+// -----------------------------------------------------------------------------
+//
+void CTimerManager::TimerExpiredL(TTimerId aTimerId)
+ {
+ __TEST_INVARIANT;
+ __SIP_ASSERT_LEAVE(aTimerId != KNoSuchTimer, KErrArgument);
+
+ TInt index(0);
+ CTimerRequest* timerReq = iTimerStore->SearchById(aTimerId, index);
+
+ if (timerReq)
+ {
+#if defined(WRITE_TIMER_LOG)
+ __SIP_INT_LOG1( "LwTimer TimerExpiredL id", aTimerId )
+#endif
+ //Store callback and parameter before freeing timerReq
+ MExpirationHandler* notifier = timerReq->Observer();
+ TAny* timerParam = timerReq->TimerParam();
+
+ //Remove expired item BEFORE calling TimerExpiredL.
+ //If user stops the expiring timer withing TimerExpiredL, would crash
+ //as the timer would be used here after TimerExpiredL.
+ iTimerStore->Remove(index);
+
+ //Notifier can be NULL for the internal timer
+ if (notifier)
+ {
+ iNowExpiring = ETrue;
+ notifier->TimerExpiredL(aTimerId, timerParam);
+ iNowExpiring = EFalse;
+ }
+ }
+
+ SetTimerWithShortestValueL();
+
+ __TEST_INVARIANT;
+ }
+
+// -----------------------------------------------------------------------------
+// CTimerManager::LeaveOccurred
+// Do things that were not done in CTimerManager::TimerExpiredL due to leave.
+// Clear iNowExpiring flag and start the next timer.
+// -----------------------------------------------------------------------------
+//
+TInt CTimerManager::LeaveOccurred()
+ {
+ __TEST_INVARIANT;
+
+ iNowExpiring = EFalse;
+ TRAPD(err, SetTimerWithShortestValueL());
+
+ __TEST_INVARIANT;
+ return err;
+ }
+
+// -----------------------------------------------------------------------------
+// CTimerManager::NewTimerId
+// -----------------------------------------------------------------------------
+//
+TTimerId CTimerManager::NewTimerId()
+ {
+ __TEST_INVARIANT;
+
+ iTimerIdCounter++;
+ if (iTimerIdCounter == KNoSuchTimer || iTimerIdCounter == KReservedTimer)
+ {
+ iTimerIdCounter = KReservedTimer + 1;
+ }
+
+ __TEST_INVARIANT;
+ return iTimerIdCounter;
+ }
+
+// -----------------------------------------------------------------------------
+// CTimerManager::MillisecToTTime
+// -----------------------------------------------------------------------------
+//
+TTime CTimerManager::MillisecToTTime(TUint aMilliseconds) const
+ {
+ __TEST_INVARIANT;
+
+ TTime expirationTime;
+ expirationTime.HomeTime();
+
+ TTimeIntervalSeconds sec = aMilliseconds/1000;
+ expirationTime += sec;
+
+ TTimeIntervalMicroSeconds us = (TInt64)(aMilliseconds % 1000) * 1000;
+ expirationTime += us;
+
+ return expirationTime;
+ }
+
+// -----------------------------------------------------------------------------
+// CTimerManager::TTimeToMillisec
+// -----------------------------------------------------------------------------
+//
+TBool CTimerManager::TTimeToMillisec(TTime aTime, TUint& aMilliseconds) const
+ {
+ __TEST_INVARIANT;
+
+ TTime now;
+ now.HomeTime();
+
+ TTimeIntervalSeconds deltaSeconds(0);
+ if (aTime.SecondsFrom(now, deltaSeconds) != KErrNone)
+ {
+ return EFalse;
+ }
+
+ TTimeIntervalMicroSeconds deltaMicrosecs = aTime.MicroSecondsFrom(now);
+
+ if (deltaSeconds.Int() < 0 || deltaMicrosecs.Int64() < 0)
+ {
+ //Timer should've already expired. Expire now. Can happen in debugger or
+ //if there are so many short timers they can't be handled fast enough.
+ aMilliseconds = 0;
+ return ETrue;
+ }
+
+ // Set a value anyway but it should not be used for timer if EFalse is
+ // returned
+ aMilliseconds = deltaSeconds.Int() * 1000;
+
+ //"+ 1" is the worst case for the millisecond part
+ if ((deltaSeconds.Int() + 1) > CSingleTimer::KMaxTimerAfterDuration / 1000)
+ {
+ return EFalse;
+ }
+
+ TInt64 milliseconds = (deltaMicrosecs.Int64()/1000) % 1000;
+ //As milliseconds is always 0..999, the low 32 bits are enough
+ aMilliseconds += I64LOW(milliseconds);
+
+ return ETrue;
+ }
+
+// -----------------------------------------------------------------------------
+// CTimerManager::CheckIsNewTimerShortestL
+// If duration is too long for CSingleTimer::SetAfter, simulate it by chaining
+// many shorter timers together. RTimer::At is avoided as it may end with
+// KErrAbort ~23 minutes after setting it.
+// -----------------------------------------------------------------------------
+//
+void CTimerManager::CheckIsNewTimerShortestL(TTimerId aTimerId,
+ TUint aMilliseconds)
+ {
+ __TEST_INVARIANT;
+
+ TTimerId shortestTimerId(0);
+ TTime shortestExpirationTime;
+
+ if (iTimerStore->ShortestTimer(shortestTimerId, shortestExpirationTime))
+ {
+ if (shortestTimerId == aTimerId)
+ {
+ //The new timer is shorter than any of the existing, stop iTimer and
+ //start it with the new expiration time.
+ iTimer->Cancel();
+
+ if (aMilliseconds <= CSingleTimer::KMaxTimerAfterDuration)
+ {
+ iTimer->SetAfter(aMilliseconds, aTimerId);
+ }
+ else
+ {
+ SetInternalTimerL();
+ }
+ }
+ }
+ else
+ {
+ //There must be at least one timer (the one just created).
+ __ASSERT_DEBUG(EFalse,
+ User::Panic(_L("TimerMgr:CheckIsNewTimerShortestL no timers"),
+ KErrNotFound));
+ }
+
+ __TEST_INVARIANT;
+ }
+
+// -----------------------------------------------------------------------------
+// CTimerManager::SetTimerWithShortestValueL
+// -----------------------------------------------------------------------------
+//
+void CTimerManager::SetTimerWithShortestValueL()
+ {
+ __TEST_INVARIANT;
+ __SIP_ASSERT_LEAVE(!iTimer->IsActive(), KErrNotReady);
+
+ TTimerId timerId(0);
+ TTime expirationTime;
+
+ if (iTimerStore->ShortestTimer(timerId, expirationTime))
+ {
+ TUint milliseconds(0);
+
+ if (TTimeToMillisec(expirationTime, milliseconds))
+ {
+ iTimer->SetAfter(milliseconds, timerId);
+ }
+ else
+ {
+ SetInternalTimerL();
+ }
+ }
+
+#if defined(WRITE_TIMER_LOG)
+ __SIP_INT_LOG1( "LwTimer SetTimerWithShortestValueL id", timerId )
+#endif
+
+ __TEST_INVARIANT;
+ }
+
+// -----------------------------------------------------------------------------
+// CTimerManager::SetInternalTimerL
+// -----------------------------------------------------------------------------
+//
+void CTimerManager::SetInternalTimerL() const
+ {
+ __TEST_INVARIANT;
+
+ iTimerStore->AddL(NULL,
+ MillisecToTTime(CSingleTimer::KInternalTimerDuration),
+ KReservedTimer,
+ NULL);
+ iTimer->SetAfter(CSingleTimer::KInternalTimerDuration, KReservedTimer);
+ }
+
+// -----------------------------------------------------------------------------
+// CTimerManager::__DbgTestInvariant
+// -----------------------------------------------------------------------------
+//
+
+void CTimerManager::__DbgTestInvariant() const
+ {
+ if (!iTimerStore || !iTimer)
+ {
+ User::Invariant();
+ }
+ }