keepalive/flextimer/server/engine/src/flextimercontainer.cpp
changeset 32 5c4486441ae6
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/keepalive/flextimer/server/engine/src/flextimercontainer.cpp	Mon May 24 20:51:35 2010 +0300
@@ -0,0 +1,459 @@
+/*
+ * Copyright (c) 2010 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
+ *
+ * Description:
+ * This class contains implementation of CFlexTimerContainer.
+ *
+ */
+
+// System include files
+#include <hal.h>
+
+// User include files
+#include "flextimercommon.h"
+#include "flextimercontainer.h"
+#include "flextimeritem.h"
+#include "mflextimerservicecb.h"
+#include "OstTraceDefinitions.h"
+#ifdef OST_TRACE_COMPILER_IN_USE
+#include "flextimercontainerTraces.h"
+#endif
+
+
+
+// This literal is only used by __ASSERT_DEBUG macro. Therefore, to prevent 
+// unnacessary warnings, it is not compiled into release builds.
+#ifdef _DEBUG
+static const TInt KCBNullPointer = 1;
+_LIT( KCBNullPointerDescriptor, "FlexTimerService CB is NULL." );
+#endif
+
+// ---------------------------------------------------------------------------
+// NewL
+// ---------------------------------------------------------------------------
+//
+CFlexTimerContainer* CFlexTimerContainer::NewL()
+    {
+    CFlexTimerContainer* self = new (ELeave) CFlexTimerContainer();
+    
+    OstTrace1( TRACE_INTERNAL,
+        CFLEXTIMERCONTAINER_NEWL,
+        "CFlexTimerContainer::NewL;this=%x",
+        ( TUint )self );
+    
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// destructor
+// If the list is not empty when coming here something has already gone wrong.
+// Lets just delete the timers and forget Timeout() calling
+// ---------------------------------------------------------------------------
+//
+CFlexTimerContainer::~CFlexTimerContainer()
+    {
+    CFlexTimerItem* item = NULL;
+    
+    OstTrace1(
+        TRACE_INTERNAL,
+        DUP1_CFLEXTIMERCONTAINER_CFLEXTIMERCONTAINER,
+        "CFlexTimerContainer::~CFlexTimerContainer;this=%x",
+        ( TUint )this );
+
+    while ( !iTimerList.IsEmpty() )
+        {
+        item = iTimerList.First();
+        iTimerList.Remove( *item );
+        delete item;
+        }
+    }
+// ---------------------------------------------------------------------------
+// Make new timer and add it to list. On purpose do not make sanity checks. 
+// Invalid(in the past) timers are found later.
+// ---------------------------------------------------------------------------
+//
+void CFlexTimerContainer::AddTimerL(
+    const TTimeIntervalMicroSeconds& aWinStartInterval,
+    const TTimeIntervalMicroSeconds& aWinEndInterval,
+    TBool aCancelAtSystemTimeChange,
+    const MFlexTimerServiceCB* aFlexTimerServiceCB )
+    {
+    OstTraceExt5( TRACE_INTERNAL,
+        CFLEXTIMERCONTAINER_ADDTIMERL,
+        "CFlexTimerContainer::AddTimerL;this=%x;"
+        "aWinStartInterval=%Ld;"
+        "aWinEndInterval=%Ld;"
+        "aCancelAtSystemTimeChange=%u;"
+        "aFlexTimerServiceCB=%x",
+        ( TUint )this,
+        aWinStartInterval.Int64(),
+        aWinEndInterval.Int64(),
+        aCancelAtSystemTimeChange,
+        ( TUint )aFlexTimerServiceCB );
+    
+    __ASSERT_DEBUG( aFlexTimerServiceCB,
+            User::Panic( KCBNullPointerDescriptor, KCBNullPointer ) );
+
+    // Before creating new flextimer timeout item, the interval times are
+    // converted to absolute tick based time used by the engine.
+    TTime winAbsStart( IntervalToAbsoluteTime( aWinStartInterval ) );
+    TTime winAbsEnd( IntervalToAbsoluteTime( aWinEndInterval ) );
+    
+    CFlexTimerItem* newItem = CFlexTimerItem::NewL( winAbsStart,
+        winAbsEnd,
+        aCancelAtSystemTimeChange,
+        aFlexTimerServiceCB );
+
+    iTimerList.AddLast( *newItem );
+    }
+// ---------------------------------------------------------------------------
+// Loop through list and if timer containing same CB that is given as a
+// parameter is found, remove timer. If no timer found just return error code.
+// ---------------------------------------------------------------------------
+//
+TInt CFlexTimerContainer::RemoveTimer(
+    const MFlexTimerServiceCB* aFlexTimerServiceCB )
+    {
+    OstTraceExt2( TRACE_INTERNAL,
+        CFLEXTIMERCONTAINER_REMOVETIMER,
+        "CFlexTimerContainer::RemoveTimer;this=%x;aFlexTimerServiceCB=%x",
+        ( TUint )this,
+        ( TUint )aFlexTimerServiceCB );
+
+    __ASSERT_DEBUG( aFlexTimerServiceCB,
+        User::Panic( KCBNullPointerDescriptor, KCBNullPointer ) );
+    
+    TSglQueIter<CFlexTimerItem> listIter( iTimerList );
+    CFlexTimerItem* item = NULL;
+
+    listIter.SetToFirst();
+    // Iter++ makes iterator to point to next element if one exists.
+    // Otherwise NULL.
+    while ( (item = listIter++) != NULL )
+        {
+        if ( item->GetCB() == aFlexTimerServiceCB )
+            {
+            iTimerList.Remove( *item );
+            delete item;
+            return KErrNone;
+            }
+        }
+    return KErrNotFound;
+    }
+// ---------------------------------------------------------------------------
+// Loop through timers and find time/timer that must expire next
+// Calculate time left to that moment and return it. 
+// ---------------------------------------------------------------------------
+//
+TBool CFlexTimerContainer::GetNextTimeout(
+    TTimeIntervalMicroSeconds& aNextTimeoutDelay )
+    {
+    TSglQueIter<CFlexTimerItem> listIter( iTimerList );
+    TTime currentAbsoluteTime( 0 );
+    CFlexTimerItem* item = NULL;
+    TTime tempTime( 0 );
+    TTime nextTimeout( 0 );
+
+    GetCurrentTime( currentAbsoluteTime );
+    // Take first item as a reference value.
+    listIter.SetToFirst();
+    item = listIter++;
+    if ( item )
+        {
+        item->GetMaxAbsoluteTime( nextTimeout );
+        }
+
+    // Find the timer that needs to expire next, and set nextTimeout to the
+    // time, when the timer needs to expire.
+    while ( (item = listIter++) != NULL )
+        {
+        item->GetMaxAbsoluteTime( tempTime );
+        if ( tempTime < nextTimeout )
+            {
+            nextTimeout = tempTime;
+            }
+        }
+    // Calculate difference between now -> min timeout time. If in past,
+    // return zero interval
+    aNextTimeoutDelay = nextTimeout.MicroSecondsFrom( currentAbsoluteTime );
+    if ( aNextTimeoutDelay < TTimeIntervalMicroSeconds( 0 ) )
+        {
+        aNextTimeoutDelay = 0;
+        }
+    
+    OstTraceExt2( TRACE_INTERNAL,
+        CFLEXTIMERCONTAINER_GETNEXTTIMEOUT,
+        "CFlexTimerContainer::GetNextTimeout;this=%x;aNextTimeoutDelay=%Ld",
+        ( TUint )this,
+        aNextTimeoutDelay.Int64() );
+    
+    return !iTimerList.IsEmpty();
+    }
+// ---------------------------------------------------------------------------
+// Excecute selected algorithms and finally fire all timers in candidate list.
+// ---------------------------------------------------------------------------
+//
+void CFlexTimerContainer::FireTimers( TFlexTimerAlgorithm aAlgorithmToBeUsed )
+    {
+    OstTraceExt2( TRACE_INTERNAL,
+        CFLEXTIMERCONTAINER_FIRETIMERS,
+        "CFlexTimerContainer::FireTimers;this=%x;aAlgorithmToBeUsed=%x",
+        ( TUint )this,
+        ( TUint )aAlgorithmToBeUsed );
+
+    TSglQue<CFlexTimerItem> candidateList( _FOFF( CFlexTimerItem, iLink ) );
+
+    TTime currentAbsoluteTime( 0 );
+
+    GetCurrentTime( currentAbsoluteTime );
+    
+    // Simple algorithm is always executed
+    SimpleAlgorithm( candidateList, currentAbsoluteTime );
+
+    if ( EFlexTimerAlgorithmLatestPossible == aAlgorithmToBeUsed )
+        {
+        LatestPossibleAlgorithm( candidateList );
+        }
+    ExpireTimers( candidateList );
+    }
+
+//
+// ---------------------------------------------------------------------------
+// Loop through timer list, call abort to timer if it is abortable.
+// Then remove timer from list and delete it.
+// ---------------------------------------------------------------------------
+//
+void CFlexTimerContainer::AbortTimersDueToTimeChange( TInt aReason )
+    {
+    OstTraceExt2( TRACE_INTERNAL,
+        CFLEXTIMERCONTAINER_ABORTTIMERSDUETOTIMECHANGE,
+        "CFlexTimerContainer::AbortTimersDueToTimeChange;this=%x;aReason=%d",
+        ( TUint )this,
+        aReason );
+
+    TSglQueIter<CFlexTimerItem> listIter( iTimerList );
+    CFlexTimerItem* item = NULL;
+    listIter.SetToFirst();
+    
+    // Go through all timers and check if the timer has 
+    // AbortAtSystemTimeChange flag set, if so, abort the timer.
+    while ( (item = listIter++) != NULL )
+        {
+        if ( item->IsAbortedAtSystemTimeChange() )
+            {
+            item->GetCB()->Abort( aReason );
+            iTimerList.Remove( *item );
+            delete item;
+            }
+        }
+    }
+// ---------------------------------------------------------------------------
+// Constructor for CFlexTimerContainer
+// ---------------------------------------------------------------------------
+//
+CFlexTimerContainer::CFlexTimerContainer() :
+    iTimerList( _FOFF( CFlexTimerItem, iLink ) ),
+    iLastTicks( 0 ),
+    iCurrentAbsoluteTime( 0 )    
+    {
+    OstTrace1( TRACE_INTERNAL,
+        CFLEXTIMERCONTAINER_CFLEXTIMERCONTAINER,
+        "CFlexTimerContainer::CFlexTimerContainer;this=%x",
+        ( TUint )this );
+    TInt err;
+    
+    // Get system tick length for converting tics to microseconds.
+    err = HAL::Get( HAL::ESystemTickPeriod, iTickPeriod );
+    
+    __ASSERT_ALWAYS(
+        err == KErrNone,
+        User::Panic(
+            KFlexTimerContainerPanicCat,
+            static_cast <TInt> ( EFlexTimerContainerNoTickPeriod ) ) );
+    }
+// ---------------------------------------------------------------------------
+// Loops through timer list and moves all timers that can be fired to
+// candidate list. Can be fired means that minimum time is reached. Note that
+// if we are late for some reason (very likely if someone has win size zero),
+// candidate list can now contain timers that are late (max time passed).
+// ---------------------------------------------------------------------------
+//
+void CFlexTimerContainer::SimpleAlgorithm(
+    TSglQue<CFlexTimerItem>& aCandidateList,
+    TTime& aCurrentTime )
+    {
+    OstTraceExt3( TRACE_INTERNAL,
+        CFLEXTIMERCONTAINER_SIMPLEALGORITHM,
+        "CFlexTimerContainer::SimpleAlgorithm;"
+        "this=%x;aCandidateList=%x;aCurrentTime=%Ld;",
+        ( TUint )this,
+        ( TUint )&aCandidateList,
+        aCurrentTime.Int64() );
+
+    TSglQueIter<CFlexTimerItem> listIter( iTimerList );
+    CFlexTimerItem* item = NULL;
+    TTime minTime( 0 );
+
+    listIter.SetToFirst();
+    // Iter++ makes iterator to point to next element if one exists.
+    // Otherwise NULL.
+    while ( (item = listIter++) != NULL )
+        {
+        item->GetMinAbsoluteTime( minTime );
+        if ( minTime <= aCurrentTime )
+            {
+            OstTraceExt2( TRACE_INTERNAL,
+                DUP1_CFLEXTIMERCONTAINER_SIMPLEALGORITHM,
+                "CFlexTimerContainer::SimpleAlgorithm - Adding item;"
+                "this=%x;item=%x",
+                ( TUint )this,
+                ( TUint )item );
+            // Remove from candidate list needs to be done before the
+            // item is added to back to iTimerList, because the lists
+            // use the same iLink member.
+            iTimerList.Remove( *item );
+            
+            // This timer can be timeouted, add it to timeout candidate list.
+            // The list is called candidate list, because the content of the
+            // list may be pruned by passing it to other algorithms for furher
+            // prosessing.
+            aCandidateList.AddLast( *item );
+            }
+        }
+    }
+
+//
+// ---------------------------------------------------------------------------
+// Loops through dropped list and candidate list and find timers where:
+// dropped timers right side of the window is earlier than candidate timers
+// right side of the window i.e. Candidate can be fired later with dropped
+// timer, without additional timer firings
+// ---------------------------------------------------------------------------
+//
+void CFlexTimerContainer::LatestPossibleAlgorithm(
+    TSglQue<CFlexTimerItem>& aCandidateList )
+    {   
+    TSglQueIter<CFlexTimerItem> listIter( iTimerList );
+    TSglQueIter<CFlexTimerItem> candidateListIter( aCandidateList );
+    CFlexTimerItem* droppedItem = NULL;
+    CFlexTimerItem* candidateItem = NULL;
+    TTime droppedMaxTime( 0 );
+    TTime candidateMaxTime( 0 );
+    
+    OstTraceExt2( TRACE_INTERNAL,
+        CFLEXTIMERCONTAINER_LATESTPOSSIBLEALGORITHM,
+        "CFlexTimerContainer::LatestPossibleAlgorithm;"
+        "this=%x;aCandidateList=%x",
+        ( TUint )this,
+        ( TUint )&aCandidateList );
+    
+    listIter.SetToFirst();
+    candidateListIter.SetToFirst();
+            
+    droppedItem = listIter++;
+    
+    if ( droppedItem != NULL )
+        {
+        // Initiliaze next dropped timeout time to some value.
+        droppedItem->GetMaxAbsoluteTime( droppedMaxTime );
+
+        // Loop through dropped timers and find the dropped timer that will have
+        // shortest time to its timeout.
+        while ( (droppedItem = listIter++) != NULL )
+            {
+            droppedItem->GetMaxAbsoluteTime( candidateMaxTime );
+            if ( droppedMaxTime > candidateMaxTime )
+                {
+                droppedMaxTime = candidateMaxTime;
+                }
+            }
+
+        // Loop through candidate timers
+        while ( (candidateItem = candidateListIter++) != NULL )
+            {
+            candidateItem->GetMaxAbsoluteTime( candidateMaxTime );
+            // If candidate can be fired together with dropped timer ->
+            // don't fire candidate yet.
+            if ( droppedMaxTime <= candidateMaxTime )
+                {
+                OstTraceExt2( TRACE_INTERNAL,
+                    DUP1_CFLEXTIMERCONTAINER_LATESTPOSSIBLEALGORITHM,
+                    "CFlexTimerContainer::LatestPossibleAlgorithm -"
+                    " Removing item;this=%x;candidateItem=%x",
+                    ( TUint )this,
+                    ( TUint )candidateItem );
+
+                // Remove from candidate list needs to be done before the
+                // item is added to back to iTimerList, because the lists
+                // use the same iLink member.
+                aCandidateList.Remove( *candidateItem );
+                // Add to first so we don't handle this again.
+                iTimerList.AddFirst( *candidateItem );
+                }
+            }
+        }
+    }
+// ---------------------------------------------------------------------------
+// Loops through candidate list and calls timeout to all timers.
+// Then removes timer from list and deletes it. 
+// ---------------------------------------------------------------------------
+//
+void CFlexTimerContainer::ExpireTimers(
+    TSglQue<CFlexTimerItem>& aCandidateList )
+    {
+    OstTraceExt2( TRACE_INTERNAL,
+        CFLEXTIMERCONTAINER_EXPIRETIMERS,
+        "CFlexTimerContainer::ExpireTimers;this=%x;candidateList=%x",
+        ( TUint )this,
+        ( TUint )&aCandidateList );
+
+    TSglQueIter<CFlexTimerItem> candidateListIter( aCandidateList );
+    CFlexTimerItem* item = NULL;
+
+    candidateListIter.SetToFirst();
+    // Iter++ makes iterator to point to next element if one exists.
+    // Otherwise NULL.
+    while ( (item = candidateListIter++) != NULL )
+        {
+        item->GetCB()->Timeout();
+        aCandidateList.Remove( *item );
+        delete item;
+        }
+    }
+// ---------------------------------------------------------------------------
+// Get current time return current time in FlexTimer engine time base. This
+// time base is begins from the first call to GetCurrentTime and it is base on
+// system ticks.
+// ---------------------------------------------------------------------------
+//
+void CFlexTimerContainer::GetCurrentTime( TTime& aAbsoluteTime )
+    {
+    TUint32 currentTicks = User::TickCount();
+
+    // Accumulate current absolute time with the time passed since last
+    // update. Both currentTicks and iLastTicks are unsigned int types, thus
+    // "currentTicks - iLastTicks" will handle also the case currentTicks
+    // overflows.
+    iCurrentAbsoluteTime += TicksToAbsoluteTime( currentTicks
+            - iLastTicks );
+        
+    iLastTicks = currentTicks;
+    
+    // N.B. Even though the time is is returned as TTime, this time has own
+    // time base. (See function description)
+    aAbsoluteTime = iCurrentAbsoluteTime;
+    }
+
+
+
+
+
+