kernel/eka/euser/cbase/ub_act.cpp
changeset 0 a41df078684a
child 1 cb3e90eb7d89
child 6 0173bcd7697c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/euser/cbase/ub_act.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,1371 @@
+// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "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:
+// e32\euser\cbase\ub_act.cpp
+// 
+//
+
+#include "ub_std.h"
+#include "us_data.h"
+
+#ifdef __SMP__
+#include <e32atomics.h>
+#endif
+
+
+
+#pragma warning( disable : 4705 )	// statement has no effect
+EXPORT_C CActive::CActive(TInt aPriority)
+/**
+Constructs the active object with the specified priority.
+
+Derived classes must define and implement a constructor through which the
+priority can be specified. A typical implementation calls this active object
+constructor through a constructor initialization list.
+
+@param aPriority An integer specifying the priority of this active object.
+                 CActive::TPriority defines a standard set of priorities.
+*/
+	{
+	iLink.iPriority=aPriority;
+	}
+#pragma warning( default : 4705 )
+
+
+
+
+EXPORT_C CActive::~CActive()
+/**
+Frees resources prior to destruction.
+
+Specifically, it removes this active object from the active scheduler's
+list of active objects.
+
+Typically, a derived class calls Cancel() in its destructor.
+
+@panic E32USER-CBase 40 if the active object has an outstanding request when
+       the destructor is called,
+
+@see CActive::Cancel
+*/
+	{
+	__ASSERT_ALWAYS(!(iStatus.iFlags&TRequestStatus::EActive),Panic(EReqStillActiveOnDestruct));
+	if (IsAdded())
+		iLink.Deque();
+	}
+
+
+
+
+EXPORT_C void CActive::Cancel()
+/**
+Cancels the wait for completion of an outstanding request.
+
+If there is no request outstanding, then the function does nothing.
+
+If there is an outstanding request, the function:
+
+1. calls the active object's DoCancel() function, provided by
+   the derived class to implement cancellation of the request.
+
+2. waits for the cancelled request to complete; this must complete as fast as
+   possible.
+
+3. marks the active object's request as complete (i.e. the request is no longer
+   outstanding).
+
+@see CActive::DoCancel
+@see CActive::IsActive
+@see CActive::~CActive
+@see User::WaitForRequest
+*/
+	{
+	if (iStatus.iFlags&TRequestStatus::EActive)
+		{
+		DoCancel();
+		User::WaitForRequest(iStatus);
+    	iStatus.iFlags&=~(TRequestStatus::EActive | TRequestStatus::ERequestPending); //iActive=EFalse;
+		}
+	}
+
+
+
+
+EXPORT_C void CActive::Deque()
+/**
+Removes the active object from the active scheduler's list of active objects.
+
+Before being removed from the active scheduler's list, the function cancels
+any outstanding request.
+
+@see CActive::Cancel
+*/
+	{
+	__ASSERT_ALWAYS(IsAdded(),Panic(EActiveNotAdded));
+	Cancel();
+	iLink.Deque();
+	iLink.iNext=NULL; // Must do this or object cannot be re-queued
+	}
+
+
+
+
+EXPORT_C void CActive::SetActive()
+/**
+Indicates that the active object has issued a request and that
+it is now outstanding.
+
+Derived classes must call this function after issuing a request.
+
+A request is automatically marked as complete (i.e. it is no longer
+outstanding) by:
+
+1. the active scheduler, immediately before it calls the active object's RunL()
+   function.
+
+or
+
+2. the active object within the implementation of the Cancel() function.
+
+@see CActive::IsActive
+@see CActive::RunL
+@see CActive::Cancel
+*/
+	{
+	__ASSERT_ALWAYS(!(iStatus.iFlags&TRequestStatus::EActive),Panic(EReqAlreadyActive));
+	__ASSERT_ALWAYS(IsAdded(),Panic(EActiveNotAdded));
+	iStatus.iFlags|=TRequestStatus::EActive;
+	}
+
+
+
+
+EXPORT_C void CActive::SetPriority(TInt aPriority)
+/**
+Sets the priority of the active object.
+
+@param aPriority An integer specifying the new priority of this active object.
+                 CActive::TPriority defines a standard set of priorities.
+
+@panic E32USER-CBase 50 if this function is called while a request
+       is outstanding.
+*/
+	{
+	__ASSERT_ALWAYS(!(iStatus.iFlags&TRequestStatus::EActive),Panic(ESetPriorityActive));
+	iLink.iPriority=aPriority;
+	if (IsAdded())
+		{
+		Deque();
+		iLink.iNext=NULL; // Make this not added
+		CActiveScheduler::Add(this);
+		}
+	}
+
+
+
+
+EXPORT_C TInt CActive::RunError(TInt aError)
+/**
+Handles a leave occurring in the request completion event handler RunL().
+
+The active scheduler calls this function if this active object's RunL()
+function leaves. This gives this active object the opportunity to perform
+any necessary cleanup.
+
+A derived class implementation should handle the leave and return KErrNone.
+Returning any other value results in the active scheduler function
+CActiveScheduler::Error() being called.
+
+The default implementation simply returns the leave code.
+
+Note that if the active scheduler is to handle the error, a suitably derived
+CActiveScheduler::Error() function must be supplied.
+
+@param aError The leave code
+
+@return The default implementation returns aError. A derived class
+        implementation should return KErrNone, if it handles the leave;
+        otherwise it should return any suitable value to cause the handling
+        of the error to be propagated back to the active scheduler.
+
+@see CActiveScheduler::Error
+*/
+	{
+	return aError;
+	}
+
+
+
+
+/**
+Extension function
+
+
+*/
+EXPORT_C TInt CActive::Extension_(TUint aExtensionId, TAny*& a0, TAny* a1)
+	{
+	return CBase::Extension_(aExtensionId, a0, a1);
+	}
+
+
+
+
+EXPORT_C CIdle* CIdle::New(TInt aPriority)
+/**
+Allocates and initialises an Idle time active object and adds it to the active
+scheduler.
+
+@param aPriority An integer specifying the priority of this active object.
+                 It must be lower than that of all other active objects on
+                 the active scheduler.
+                 The value CActive::TPriority::EPriorityIdle is recommended.
+
+@return Pointer to the new Idle time active object, or NULL if the object could
+        not be created.
+*/
+	{
+	CIdle *pI=new CIdle(aPriority);
+	if (pI!=NULL)
+		CActiveScheduler::Add(pI);
+	return(pI);
+	}
+
+
+
+
+EXPORT_C CIdle* CIdle::NewL(TInt aPriority)
+/**
+Allocates and initialises an Idle time active object, adds it to the active
+scheduler, but leaves on failure.
+
+@param aPriority An integer specifying the priority of this active object.
+                 It must be lower than that of all other active objects on
+                 the active scheduler.
+                 The value CActive::TPriority::EPriorityIdle is recommended.
+
+@return Pointer to the new Idle time active object.
+*/
+	{
+	CIdle *pI=new(ELeave) CIdle(aPriority);
+	CActiveScheduler::Add(pI);
+	return(pI);
+	}
+
+
+
+
+
+EXPORT_C CIdle::CIdle(TInt aPriority)
+	: CActive(aPriority)
+/**
+Protected constructor taking a priority value.
+
+Sets this active object's priority value.
+
+@param aPriority The active object priority value.
+*/
+	{}
+
+
+
+
+EXPORT_C CIdle::~CIdle()
+/**
+Frees resources prior to destruction.
+
+Specifically, it cancels any outstanding request.
+*/
+	{
+	Cancel();
+	}
+
+
+
+
+EXPORT_C void CIdle::Start(TCallBack aCallBack)
+/**
+Starts the background task.
+
+The background task is encapsulated in the callback. The function represented
+by this callback is called every time this Idle time active object is scheduled
+to run.
+
+The callback function should be structured to perform a background task in
+many increments, i.e. it should voluntarily relinquish control (i.e. return)
+after a suitable time interval to allow other, higher priority events to be
+handled.
+
+If the callback function has further work to do, it should return a true value.
+This ensures that the active object is scheduled to run again later.
+
+Once the callback function has finally completed its work, it should return
+a false value. The active object is then no longer scheduled to run.
+
+@param aCallBack A callback object encapsulating a function which is called
+                 when no higher priority active object is ready to run.
+*/
+	{
+	iCallBack=aCallBack;
+	iStatus=KRequestPending;
+	TRequestStatus *pS=(&iStatus);
+	User::RequestComplete(pS,0);
+	SetActive();
+	}
+
+
+
+
+EXPORT_C void CIdle::RunL()
+/**
+Handles this idle active object's request completion event.
+
+It is called when nothing of a higher priority can be scheduled.
+
+@see CActive::RunL
+*/
+	{
+	if (iCallBack.CallBack())
+		Start(iCallBack);
+	}
+
+
+
+
+EXPORT_C void CIdle::DoCancel()
+/**
+Implements the cancellation of an outstanding request.
+
+This function is called by the active object's Cancel() function.
+
+@see CActive::DoCancel
+*/
+	{
+	}
+
+
+
+
+EXPORT_C void CAsyncOneShot::Call()
+/**
+Queues this active object to be run once.
+
+@panic E32USER-CBase 2 In debug builds only, if this active object has not
+       already been added to the active scheduler.
+*/
+	{
+	__ASSERT_DEBUG(IsAdded(),Panic(ECAsyncOneShotNotAdded));
+	TRequestStatus *pS=(&iStatus);
+	iStatus = KRequestPending;
+	SetActive();
+	iThread.RequestComplete(pS,0);
+	}
+
+
+
+
+EXPORT_C void CAsyncOneShot::DoCancel()
+/**
+Implements cancellation of an outstanding request.
+
+The class provides an empty implementation.
+
+This is called by the destructor.
+*/
+	{
+	// Empty
+	}
+
+
+
+
+EXPORT_C CAsyncOneShot::CAsyncOneShot(TInt aPriority)
+	:CActive(aPriority)
+/**
+Constructor taking a priority value.
+
+Specifically, the constructor:
+
+1. sets this active object's priority value
+
+2. opens a handle to the current thread to ensure that the thread cannot be
+   closed until this CAsyncOneShot object is destroyed
+
+3. adds this active object to the current active scheduler.
+
+@param aPriority The active object priority value. CActive::TPriority defines
+                 a standard set of priorities.
+
+@panic E32USER-CBase 93 if the attempt to open a handle to the current thread
+       fails.
+*/
+	{
+	Setup();
+	}
+
+
+
+
+void CAsyncOneShot::Setup()
+//
+// ensures that we are added to the Scheduler.
+//
+	{
+	// No error checking was done initially.  As this function is called from
+	// the c'tor, there is no way to fix it properly without breaking BC.  So
+	// we panic if something goes wrong (should only happen in extreme
+	// circumstances if the kernel heap is exhausted or heavily fragmented).
+	__ASSERT_ALWAYS(iThread.Duplicate(RThread()) == KErrNone, Panic(EAsyncOneShotSetupFailed));
+
+	// Add ourself to the current active scheduler
+	// This is because we might be being used as an inter thread call
+	// we need to make sure that we're on the correct scheduler for
+	// the RThread were going to duplicate.
+	CActiveScheduler::Add(this);
+	}
+
+
+
+
+EXPORT_C CAsyncOneShot::~CAsyncOneShot()
+/**
+Frees resources prior to destruction.
+
+Specifically, it closes the handle to the current thread.
+
+@see CActive::~CActive
+*/
+	{
+	Cancel();
+	iThread.Close();
+	}
+
+
+
+
+EXPORT_C CAsyncCallBack::CAsyncCallBack(TInt aPriority)
+	: CAsyncOneShot(aPriority), iCallBack(NULL)
+/**
+Constructor taking a priority value.
+
+Specifically, the constructor sets this active object's priority value through
+a call to the base class constructor in its ctor list.
+
+No call back is set, which means that it must be set subsequently through
+a call to the Set() function.
+
+@param aPriority The active object priority value. CActive::TPriority defines
+                 a standard set of priorities.
+
+@see CAsyncCallBack::Set
+*/
+	{
+	}
+
+
+
+
+EXPORT_C CAsyncCallBack::CAsyncCallBack(const TCallBack& aCallBack, TInt aPriority)
+	: CAsyncOneShot(aPriority), iCallBack(aCallBack)
+/**
+Constructor taking a priority value and a callback.
+
+Specifically, the constructor:
+
+1. sets this active object's priority value through a call to the base class
+   constructor in its ctor list
+
+2. sets the callback; the function encapsulated by the callback is called when
+   this active object is scheduled to run.
+
+@param aCallBack A reference to a callback object encapsulating a function
+                 which is called when this active object is ready to run.
+                 The constructor takes a copy of this callback object, which
+                 means that it can be safely discarded after construction.
+@param aPriority The active object priority value.
+*/
+	{
+	}
+
+
+
+
+EXPORT_C CAsyncCallBack::~CAsyncCallBack()
+/**
+Destructor.
+*/
+	{
+	}
+
+
+
+
+EXPORT_C void CAsyncCallBack::CallBack()
+/**
+Queues this active object to be run, if it is not already queued.
+*/
+	{
+	if (!IsActive())
+		Call();
+	}
+
+
+
+
+EXPORT_C void CAsyncCallBack::Set(const TCallBack& aCallBack)
+/**
+Sets the call back.
+
+@param aCallBack A reference to a callback object encapsulating a function
+                 which is called when this active object is ready to run.
+
+@panic E32USER-CBase 1 if the active object is currently active.
+*/
+	{
+	__ASSERT_ALWAYS(!IsActive(), Panic(ECAsyncCBIsActive));
+	iCallBack = aCallBack;
+	}
+
+
+
+
+void CAsyncCallBack::RunL()
+/**
+Calls the callback function.
+
+@see TCallBack::CallBack
+*/
+	{
+	iCallBack.CallBack();
+	}
+
+
+
+
+struct CActiveScheduler::TLoop
+	{
+	TLoop* iNext;
+	CActiveScheduler::TLoopOwner* iOwner;
+	TCallBack iCallback;
+	TInt iExitCode;
+	};
+
+CActiveScheduler::TLoopOwner* const KLoopNoOwner=reinterpret_cast<CActiveScheduler::TLoopOwner*>(1);
+CActiveScheduler::TLoopOwner* const KLoopInactive=0;
+
+
+
+
+EXPORT_C CActiveSchedulerWait::CActiveSchedulerWait()
+/**
+Default constructor.
+*/
+	{}
+
+
+
+
+
+EXPORT_C CActiveSchedulerWait::~CActiveSchedulerWait()
+/**
+Ensures that the attached scheduler loop, and all nested loops, are stopped
+prior to destruction.
+
+@see AsyncStop()
+*/
+	{
+	if (IsStarted())
+		AsyncStop();
+	}
+
+
+
+
+EXPORT_C void CActiveSchedulerWait::Start()
+/**
+Starts a new wait loop under the control of the current active scheduler.
+
+Compared with CActiveScheduler::Start(), this object owns control of
+the scheduling loop that is started, and that loop can only be stopped
+by using this objects AsyncStop() function or the CActiveScheduler::Halt()
+function. Start() only returns when either of thos has occurred.
+
+This is the preferred way to start a nested wait loop. Typically, a nested
+wait loop is used when the handling of a completed event in an active object
+requires processing further events from the other active objects before it
+can complete. This is a form of modal processing.
+
+@panic E32USER-CBase 44 if the thread does not have an active scheduler installed.
+@panic E32USER-CBase 91 if this object has already been started.
+
+@see CActiveSchedulerWait::AsyncStop
+@see CActiveSchedulerWait::IsStarted
+@see CActiveScheduler::Start
+@see CActiveScheduler::Halt
+*/
+	{
+	__ASSERT_ALWAYS(!IsStarted(), Panic(EActiveSchedulerWaitAlreadyStarted));		// can only start a CActiveSchedulerWait if it isn't already started
+	CActiveScheduler::Start(&iLoop);
+	}
+
+
+
+
+EXPORT_C void CActiveSchedulerWait::AsyncStop()
+/**
+Stops the scheduling loop owned by this object.
+
+Note that the corresponding call to Start() only returns once all nested
+scheduler loops have stopped.
+
+@panic E32USER-CBase 92 if the wait object has not been started.
+*/
+	{
+	AsyncStop(TCallBack());
+	}
+
+
+
+
+EXPORT_C void CActiveSchedulerWait::AsyncStop(const TCallBack& aCallMeWhenStopped)
+/**
+Stops the scheduling loop owned by this object, specifying a callback.
+
+This version of AsyncStop() provides a callback which is invoked immediately
+after the scheduler loop actually stops before the corresponding call
+to Start() returns.
+
+Note that the corresponding call to Start() only returns once all nested
+scheduler loops have stopped.
+
+@param aCallMeWhenStopped The callback to invoke when the scheduler loop exits.
+
+@panic E32USER-CBase 92 if the wait object has not been started.
+ */
+	{
+	CActiveScheduler::TLoopOwner loop=iLoop;
+	__ASSERT_ALWAYS(loop, Panic(EActiveSchedulerWaitNotStarted));		// can only stop a CActiveSchedulerWait if it's started
+	__ASSERT_DEBUG(loop->iOwner==&iLoop, User::Invariant());
+
+	loop->iCallback = aCallMeWhenStopped;
+	loop->iOwner = KLoopInactive;			// disconnect from owner
+	iLoop = 0;
+	}
+
+
+
+
+EXPORT_C TBool CActiveSchedulerWait::CanStopNow() const
+/**
+Reports whether stopping will have immediate effect.
+
+This returns an indication of whether a call to AsyncStop() would be
+expected to stop the scheduler loop immediately, or whether it will
+have to wait until nested scheduler loops have stopped. This may alter
+which version of AsyncStop() you would want to call.
+
+@return Boolean indicating if the scheduling loop would stop immediately.
+
+@panic E32USER-CBase 92 if the wait object has not been started.
+
+@see CActiveSchedulerWait::Start
+@see CActiveSchedulerWait::AsyncStop
+*/
+ 	{
+	__ASSERT_ALWAYS(IsStarted(), Panic(EActiveSchedulerWaitNotStarted));		// Scheduler must be running
+	for (CActiveScheduler::TLoop* loop=GetActiveScheduler()->iStack; loop; loop=loop->iNext)
+		{
+		if (loop==iLoop)
+			return ETrue;
+		if (loop->iOwner != KLoopInactive)
+			break;
+		}
+	return EFalse;
+	}
+
+
+
+EXPORT_C CActiveScheduler::CActiveScheduler()
+	: iActiveQ(_FOFF(CActive,iLink))
+/**
+Constructs an active scheduler.
+
+After construction, the scheduler should be installed.
+
+@see CActiveScheduler::Install
+*/
+	{}
+
+
+
+
+EXPORT_C CActiveScheduler::~CActiveScheduler()
+/**
+Frees resources prior to destruction.
+
+Specifically, it removes all active objects from the active scheduler's list
+of active objects.
+
+An active scheduler should only be destroyed when the top-level call to Start()
+has returned.
+
+@see CActiveScheduler::Start
+@see CActiveScheduler::Stop
+*/
+	{
+	while (!iActiveQ.IsEmpty())
+		iActiveQ.First()->Deque();
+	if (GetActiveScheduler()==this)
+		SetActiveScheduler(NULL);
+	}
+
+
+
+
+EXPORT_C void CActiveScheduler::Install(CActiveScheduler *aManager)
+/**
+Installs the specified active scheduler as the current active scheduler.
+
+The installed active scheduler now handles events for this thread.
+
+The current active scheduler can be uninstalled by passing a NULL pointer.
+
+@param aManager A pointer to the active scheduler to be installed.
+                If this is NULL, the current active scheduler is uninstalled.
+
+@panic E32USER-CBase 43 if If there is already an installed active scheduler.
+*/
+	{
+	if (aManager!=NULL)
+		__ASSERT_ALWAYS(GetActiveScheduler()==NULL,Panic(EReqManagerAlreadyExists));
+	SetActiveScheduler(aManager);
+	}
+
+
+
+
+EXPORT_C void CActiveScheduler::Add(CActive *aRequest)
+/**
+Adds the specified active object to the current active scheduler.
+
+An active object can be removed from an active scheduler either by
+destroying the active object or by using its Deque() member function.
+
+@param aRequest Pointer to the active object to be added.
+
+@panic E32USER-CBase 41 if the active object aRequest has already been added
+       to the current active scheduler.
+@panic E32USER-CBase 48 if aRequest is NULL.
+@panic E32USER-CBase 44 if the thread does not have an installed
+       active scheduler.
+
+@see CActive::Deque
+*/
+	{
+	CActiveScheduler *pS=GetActiveScheduler();
+	__ASSERT_ALWAYS(pS!=NULL,Panic(EReqManagerDoesNotExist));
+	__ASSERT_ALWAYS(aRequest,Panic(EReqNull));
+	__ASSERT_ALWAYS(!aRequest->IsAdded(),Panic(EReqAlreadyAdded));
+	pS->iActiveQ.Add(*aRequest);
+	}
+
+
+
+
+EXPORT_C void CActiveScheduler::WaitForAnyRequest()
+/**
+Wait for an asynchronous request to complete.
+
+The default implementation just calls User::WaitForAnyRequest().
+
+Derived classes can replace this. Typically, this would be done to implement
+code for maintaining an outstanding request; this would be followed by a call
+to User::WaitForAnyRequest().
+
+@see User::WaitForAnyRequest
+*/
+	{
+	User::WaitForAnyRequest();
+	}
+
+
+
+
+EXPORT_C void CActiveScheduler::Start()
+/**
+Starts a new wait loop under the control of the current active scheduler.
+
+At least one active object, with an outstanding request, must be added
+to the scheduler before the wait loop is started, otherwise no events
+will occur and the thread will hang, or any events that do occur will be
+counted as stray signals, raising a panic.
+
+While Start() is executing, user code runs only:
+
+1. in the RunL() function of active objects known to the current active scheduler
+
+2. in the RunError() function of an active object that leaves from its RunL()
+
+3. in the current active scheduler’s Error() function, if an active object’s
+   RunError() returns an error code.
+
+Start() returns only when a corresponding Stop() or Halt() is issued.
+
+Although this can be used to start a nested wait loop, this API is deprecated
+for that specific functionality, and a CActiveSchedulerWait object should be
+used instead.
+
+(Note that a nested wait loop is used when the handling of a completed event
+ in an active object requires the processing of further events from the other
+ active objects before it can complete. This is a form of modal processing.)
+
+@panic E32USER-CBase 44 if the thread does not have an active
+       scheduler installed.
+
+@see CActiveScheduler::Stop
+@see CActiveScheduler::Halt
+@see CActive::RunL
+@see CActive::RunError
+@see CActiveScheduler::Error
+@see CActiveSchedulerWait
+*/
+	{
+	Start(KLoopNoOwner);
+	}
+
+
+
+
+void CActiveScheduler::Start(TLoopOwner* aOwner)
+/**
+@internalComponent
+
+Start a new nesting level
+*/
+	{
+	CActiveScheduler* pS=GetActiveScheduler();
+	__ASSERT_ALWAYS(pS!=NULL, Panic(EReqManagerDoesNotExist));
+
+	// Instantiate the local loop control
+	TLoop loop;
+	loop.iOwner=aOwner;
+	if (aOwner != KLoopNoOwner)
+		*aOwner=&loop;
+	loop.iNext=pS->iStack;
+	pS->iStack=&loop;
+	loop.iExitCode=0;
+
+	// Run the scheduler loop
+#if 1
+	// FIXME!!! Will support old-style leave-from-Error() transiently
+	// in order to avoid simultaneous integration requirement.
+	// This should be reverted to the conditionally excluded code once
+	// fixes have been made elsewhere
+	TRAPD(r,pS->Run(loop.iOwner));
+	if (r!=KErrNone)
+		{
+		loop.iExitCode = r;
+		TLoopOwner* owner=loop.iOwner;
+		if (TUint(owner) > TUint(KLoopNoOwner))
+			*owner = NULL;
+		}
+#else	// fixme
+#ifdef _DEBUG
+	// catch old-style bad behaviour - leaving from Error()
+	TRAPD(r,pS->Run(loop.iOwner));
+	__ASSERT_DEBUG(r==KErrNone,User::Invariant());
+#else
+	pS->Run(loop.iOwner);
+#endif
+#endif
+
+	pS->iStack=loop.iNext;
+	loop.iCallback.CallBack();
+	// propagate the exit-code via a leave (yuck, but blame BAFL & co.)
+	if (loop.iExitCode)
+		User::Leave(loop.iExitCode);
+	}
+
+/*
+@internalComponent
+
+Dummy Function. This is used as a dummy object to put onto the cleanupstack in order
+to check for imbalance in the CActiveScheduler::DoRunL.
+ */
+void DummyFunc(TAny* /*aPtr*/)
+	{}
+
+
+#ifdef __LEAVE_EQUALS_THROW__
+/**
+@internalComponent
+
+Start dispatching request completions.
+
+Stop when aLoop becomes 'Inactive'
+
+This version uses the implementation of TRAP/Leave in terms of C++ exceptions.
+We have to make sure here that we don't call Active Object's RunError() or Active Scheduler's Error()
+while we are still in exception (within 'catch' brackets), as it can lead to nested-exceptions scenario.
+It is not fatal by default, but if two nested exceptions are due to OOM condition, RVCT implementation
+of exception will run out of emergency buffers and terminate the thread.
+*/
+void CActiveScheduler::Run(TLoopOwner* const volatile& aLoop)
+	{
+	CActive * volatile curr_obj = 0;
+	TBool leaveException = EFalse;
+	TInt exceptionReason = 0;
+	do
+		{
+		try	{
+			__WIN32SEHTRAP
+			TTrapHandler* t = User::MarkCleanupStack();
+			
+#ifdef _DEBUG
+			//We cache the cleanupstack here do avoid repeated exec calls in DoRunL
+			TCleanupTrapHandler *pH=(TCleanupTrapHandler *)GetTrapHandler();
+			CCleanup* cleanupPtr=NULL;
+			TCleanupBundle cleanupBundle;
+
+			if(pH!=NULL) // test whether there's a CleanupTrapHandler installed
+				{
+				CCleanup& ccleanup =pH->Cleanup();
+				//Store pointer as need the scope of ccleanup increased
+				cleanupPtr = &ccleanup; 
+				cleanupBundle.iCleanupPtr = cleanupPtr;
+				
+				//Push a dummy item onto the stack - we check it after the AO's RunL has returned
+				//and we check to make sure its still at the top.
+				ccleanup.PushL(TCleanupItem(DummyFunc, &(cleanupBundle.iDummyInt)));
+				
+				DoRunL(aLoop, curr_obj, &cleanupBundle);
+
+				//Dummy Int must (will) be at the top
+				//Cleanup our stack
+				cleanupPtr->Pop(1);
+				} 
+			else // no cleanup stack installed
+				{
+				DoRunL(aLoop, curr_obj, NULL);
+				}
+			
+#else
+			DoRunL(aLoop, curr_obj, NULL);
+#endif
+			
+			User::UnMarkCleanupStack(t);
+			__WIN32SEHUNTRAP
+			return;
+			}
+		catch (XLeaveException& l)
+			{
+			Exec::LeaveEnd();
+			leaveException = ETrue;
+			exceptionReason = l.Reason();
+			}
+		catch (...)
+			{
+			User::Invariant();
+			}
+
+		if (leaveException)
+			{
+			if (exceptionReason != KErrNone)
+				{
+				TInt r = curr_obj->RunError(exceptionReason);
+				if (r != KErrNone)
+					Error(r);
+				}
+			leaveException = EFalse;
+			}
+
+		} while (aLoop != KLoopInactive);
+	}
+
+#else
+
+/**
+@internalComponent
+
+Start dispatching request completions.
+
+Stop when aLoop becomes 'Inactive'
+
+This version uses the original implementation of TRAP/Leave.
+*/
+void CActiveScheduler::Run(TLoopOwner* const volatile& aLoop)
+	{
+	CActive * volatile curr_obj = 0;
+	do
+		{
+		// explicitly expand the TRAPD macro here to enable single-step debugging
+		// of the scheduler loop
+		TInt r;
+		TTrap trap;
+		if (trap.Trap(r)==0)
+			{
+#ifdef _DEBUG
+			//We cache the cleanupstack here do avoid repeated exec calls in DoRunL
+			TCleanupTrapHandler *pH=(TCleanupTrapHandler *)GetTrapHandler();
+			CCleanup* cleanupPtr=NULL;
+			TCleanupBundle cleanupBundle;
+
+			if(pH!=NULL) // test whether there's a CleanupTrapHandler installed
+				{
+				CCleanup& ccleanup =pH->Cleanup();
+				//Store pointer as need the scope of ccleanup increased
+				cleanupPtr = &ccleanup; 
+				cleanupBundle.iCleanupPtr = cleanupPtr;
+				
+				//Push a dummy item onto the stack - we check it after the AO's RunL has returned
+				//and we check to make sure its still at the top.
+				ccleanup.PushL(TCleanupItem(DummyFunc, &(cleanupBundle.iDummyInt)));
+				
+				DoRunL(aLoop, curr_obj, &cleanupBundle);
+
+				//Dummy Int must (will) be at the top
+				//Cleanup our stack
+				cleanupPtr->Pop(1);
+				} 
+			else // no cleanup stack installed
+				{
+				DoRunL(aLoop, curr_obj, NULL);
+				}
+#else
+			DoRunL(aLoop, curr_obj, NULL);
+#endif
+			
+			TTrap::UnTrap();
+			return;		// exit level
+			}
+		if (r != KErrNone)
+			{
+			r = curr_obj->RunError(r);
+			if (r != KErrNone)
+				Error(r);
+			}
+		} while (aLoop != KLoopInactive);
+	}
+#endif
+
+#ifndef __CACTIVESCHEDULER_MACHINE_CODED__
+/**
+@internalComponent
+
+The inner active scheduler loop. This repeatedly waits for a signal and then
+dispatches the highest priority ready active object. The loop terminates either
+if one of the RunLs stops the current active scheduler level or leaves.
+
+Stop when aLoop becomes 'Inactive'
+@panic EClnCheckFailed 90 This will panic when the RunL has left the cleanup stack in an unbalanced state.
+*/
+#ifdef _DEBUG
+void CActiveScheduler::DoRunL(TLoopOwner* const volatile& aLoop, CActive* volatile & aCurrentObj, TCleanupBundle* aCleanupBundlePtr)
+#else
+void CActiveScheduler::DoRunL(TLoopOwner* const volatile& aLoop, CActive* volatile & aCurrentObj, TCleanupBundle* /*aCleanupBundlePtr*/)
+#endif
+	{
+	TDblQueIter<CActive> q(iActiveQ);
+	do
+		{
+		WaitForAnyRequest();
+		q.SetToFirst();
+		CActive* pR;
+		do
+			{
+			pR=q++;
+			__ASSERT_ALWAYS(pR!=NULL,Panic(EReqStrayEvent));
+			//if the line below panics it's either because you made a request but you haven't
+			//SetActive the object (pR->iStatus.iFlags&TRequestStatus::EActive==0) or you didn't set the iStatus
+			//to KRequestPending (pR->iStatus.iFlags&TRequestStatus::ERequestPending==0)
+			__ASSERT_DEBUG(!(pR->iStatus.iFlags&TRequestStatus::EActive)==!(pR->iStatus.iFlags&TRequestStatus::ERequestPending),Panic(EReqStrayEvent));
+			} while (!pR->IsActive() || pR->iStatus==KRequestPending);
+#ifdef __SMP__
+		__e32_memory_barrier();
+#endif
+		pR->iStatus.iFlags&=~(TRequestStatus::EActive | TRequestStatus::ERequestPending); //pR->iActive=EFalse;
+		aCurrentObj = pR;
+		pR->RunL();
+
+#ifdef _DEBUG
+		if(aCleanupBundlePtr!=NULL)
+			{
+			//If the following line panics, the RunL left the
+			//cleanup stack in an umbalanced state.
+			TInt* dummyInt = &(aCleanupBundlePtr->iDummyInt);
+			aCleanupBundlePtr->iCleanupPtr->Check(dummyInt);
+			}
+#endif
+
+		} while (aLoop != KLoopInactive);
+	return;		// exit level
+	}
+
+#else
+
+extern "C" void PanicStrayEvent()
+	{
+	Panic(EReqStrayEvent);
+	}
+#endif
+
+
+
+
+EXPORT_C void CActiveScheduler::Stop()
+/**
+Stops the wait loop started by the most recent call to Start().
+
+Typically, this is called by the RunL() of one of the scheduler’s active
+objects. When this RunL() finishes, the scheduler’s wait loop terminates,
+i.e. it does not wait for the completion of the next request.
+
+It will not stop a wait loop started by a call
+to CActiveSchedulerWait::Start().
+
+Stop() may also be called from Error().
+
+Note that stopping a nested wait loop is deprecated using this functionality,
+use a CActiveSchedulerWait object instead.
+
+@see CActiveSchedulerWait::Start
+@see CActive::RunL
+@see CActiveSchedulerWait::Error
+@see CActiveSchedulerWait::AsyncStop
+*/
+	{
+	CActiveScheduler *pS=GetActiveScheduler();
+	__ASSERT_ALWAYS(pS!=NULL,Panic(EReqManagerDoesNotExist));
+
+	for (CActiveScheduler::TLoop* loop=pS->iStack; loop; loop=loop->iNext)
+		{
+		if (loop->iOwner == KLoopNoOwner)
+			{
+			loop->iOwner=KLoopInactive;
+			return;
+			}
+		}
+	Panic(EReqTooManyStops);
+	}
+
+
+
+
+EXPORT_C void CActiveScheduler::Halt(TInt aExitCode) const
+/**
+Unilaterally terminates the current scheduler loop.
+
+This causes the current scheduler loop to stop, whether it was started
+using CActiveSchedulerWait::Start() or CActiveScheduler::Start(). It can
+also trigger a leave from Start() if an exit code is provided. If the
+current level has already been stopped, then this still records the exit code.
+
+@param aExitCode If non-zero, the reason code reported by Start().
+*/
+	{
+	CActiveScheduler::TLoop* loop=iStack;
+	__ASSERT_ALWAYS(loop!=NULL,Panic(EReqTooManyStops));
+	TLoopOwner* owner=loop->iOwner;
+	if (TUint(owner) > TUint(KLoopNoOwner))
+		*owner = NULL;
+	loop->iOwner = KLoopInactive;			// disconnect from owner
+	loop->iExitCode = aExitCode;
+	}
+
+
+
+
+EXPORT_C TInt CActiveScheduler::StackDepth() const
+/**
+Gets the current number of nested wait loops.
+
+@return The number of nested calls to Start().
+*/
+	{
+	TInt depth=0;
+	for (CActiveScheduler::TLoop* loop=iStack; loop; loop=loop->iNext)
+		++depth;
+	return depth;
+	}
+
+
+
+
+EXPORT_C CActiveScheduler* CActiveScheduler::Current()
+/**
+Gets a pointer to the currently installed active scheduler.
+
+@return A pointer to the active scheduler which is currently installed.
+*/
+	{
+	return GetActiveScheduler();
+	}
+
+
+
+
+EXPORT_C void CActiveScheduler::Error(TInt /*aError*/) const
+/**
+Handles the result of a leave occurring in an active object’s RunL()
+function.
+
+An active scheduler always invokes an active object’s RunL()
+function under a trap harness.
+
+The default implementation must be replaced.
+
+Any cleanup relevant to the possible causes of leaving should
+be performed. If Stop() or Halt() is called from within this function, the
+current wait loop terminates. This may be an appropriate response to
+catastrophic error conditions.
+
+@param aError The leave code propagated from the active object’s RunL() function
+
+@panic E32USER-CBase 47 if the default implementation is invoked.
+
+@see CActive::RunL
+@see CActiveScheduler::Stop
+@see CActiveScheduler::Halt
+*/
+	{
+	Panic(EReqActiveObjectLeave);
+	}
+
+
+
+
+EXPORT_C TBool CActiveScheduler::RunIfReady(TInt& aError, TInt aMinimumPriority)
+/**
+@deprecated
+
+Causes the RunL() function of at most one pending active object of priority
+aMinimumPriority or greater to be run.
+
+@param aError Error returned by called active object.
+@param aMinimumPriority Minimum priority of active object to run.
+
+@return EFalse if no active object's RunL() function was run, i.e. if there
+        were no active objects of priority aMinimumPriority or greater pending.
+*/
+	{
+	aError=KErrNone;
+	CActiveScheduler* pS=GetActiveScheduler();
+	if (pS!=NULL)
+		{
+		TDblQueIter<CActive> iterator(pS->iActiveQ);
+		for (CActive* active=iterator++; (active!=NULL) && (active->Priority()>=aMinimumPriority); active=iterator++)
+			{
+			if (active->IsActive() && (active->iStatus!=KRequestPending))
+				{
+				active->iStatus.iFlags&=~(TRequestStatus::EActive | TRequestStatus::ERequestPending); //pR->iActive=EFalse;
+				TRAP(aError, active->RunL());
+				if (aError!=KErrNone)
+					aError=active->RunError(aError);
+				return ETrue;
+				}
+			}
+		}
+	return EFalse;
+	}
+
+
+
+
+EXPORT_C CActiveScheduler* CActiveScheduler::Replace(CActiveScheduler* aNewActiveScheduler)
+/**
+Allows the current active scheduler to be replaced, while retaining its active
+objects.
+
+@param aNewActiveScheduler The new active scheduler.
+
+@return Previous active scheduler.
+*/
+	{
+	__ASSERT_ALWAYS(aNewActiveScheduler!=NULL, Panic(EReqManagerDoesNotExist));
+	CActiveScheduler* oldActiveScheduler=GetActiveScheduler();
+	__ASSERT_ALWAYS(aNewActiveScheduler!=oldActiveScheduler, Panic(EActiveSchedulerReplacingSelf));
+	if (oldActiveScheduler!=NULL)
+		{
+		// steal all the CActive objects from oldActiveScheduler (without canceling any of them)
+		TPriQue<CActive>& oldActiveQ=oldActiveScheduler->iActiveQ;
+		TPriQue<CActive>& newActiveQ=aNewActiveScheduler->iActiveQ;
+		while (!oldActiveQ.IsEmpty())
+			{
+			CActive& active=*oldActiveQ.First();
+			// call the lower-level function active.iLink.Deque() rather than active.Deque()
+			// as the latter would also call active.Cancel() (which we don't want)
+			active.iLink.Deque();
+			newActiveQ.Add(active);
+			}
+		}
+	SetActiveScheduler(aNewActiveScheduler);
+	return oldActiveScheduler;
+	}
+
+
+
+
+EXPORT_C void CActiveScheduler::OnStarting()
+/**
+@removed
+
+Dummy EXPORT for Binary Compatibility reasons.
+This method is never called.
+*/
+	{
+	}
+
+
+
+
+EXPORT_C void CActiveScheduler::OnStopping()
+/**
+@removed
+
+Dummy EXPORT for Binary Compatibility reasons.
+This method is never called.
+*/
+	{
+	}
+
+
+
+EXPORT_C void CActiveScheduler::Reserved_1()
+/**
+@internalComponent
+
+Dummy EXPORT for Binary Compatibility reasons.
+*/
+	{
+	}
+
+
+
+EXPORT_C void CActiveScheduler::Reserved_2()
+/**
+@internalComponent
+
+Dummy EXPORT for Binary Compatibility reasons.
+*/
+	{
+	}
+
+
+/**
+Extension function
+
+
+*/
+EXPORT_C TInt CActiveScheduler::Extension_(TUint aExtensionId, TAny*& a0, TAny* a1)
+	{
+	return CBase::Extension_(aExtensionId, a0, a1);
+	}