diff -r 000000000000 -r 96e5fb8b040d kernel/eka/euser/cbase/ub_act.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/euser/cbase/ub_act.cpp Thu Dec 17 09:24:54 2009 +0200 @@ -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 +#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(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 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 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& oldActiveQ=oldActiveScheduler->iActiveQ; + TPriQue& 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); + }