diff -r c16e04725da3 -r 5c4486441ae6 keepalive/flextimer/server/engine/src/flextimercontainer.cpp --- /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 + +// 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 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 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 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 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 ( 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& aCandidateList, + TTime& aCurrentTime ) + { + OstTraceExt3( TRACE_INTERNAL, + CFLEXTIMERCONTAINER_SIMPLEALGORITHM, + "CFlexTimerContainer::SimpleAlgorithm;" + "this=%x;aCandidateList=%x;aCurrentTime=%Ld;", + ( TUint )this, + ( TUint )&aCandidateList, + aCurrentTime.Int64() ); + + TSglQueIter 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& aCandidateList ) + { + TSglQueIter listIter( iTimerList ); + TSglQueIter 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& aCandidateList ) + { + OstTraceExt2( TRACE_INTERNAL, + CFLEXTIMERCONTAINER_EXPIRETIMERS, + "CFlexTimerContainer::ExpireTimers;this=%x;candidateList=%x", + ( TUint )this, + ( TUint )&aCandidateList ); + + TSglQueIter 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; + } + + + + + +