First public contribution.
1 // Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // e32\euser\cbase\ub_act.cpp
22 #include <e32atomics.h>
27 #pragma warning( disable : 4705 ) // statement has no effect
28 EXPORT_C CActive::CActive(TInt aPriority)
30 Constructs the active object with the specified priority.
32 Derived classes must define and implement a constructor through which the
33 priority can be specified. A typical implementation calls this active object
34 constructor through a constructor initialization list.
36 @param aPriority An integer specifying the priority of this active object.
37 CActive::TPriority defines a standard set of priorities.
40 iLink.iPriority=aPriority;
42 #pragma warning( default : 4705 )
47 EXPORT_C CActive::~CActive()
49 Frees resources prior to destruction.
51 Specifically, it removes this active object from the active scheduler's
52 list of active objects.
54 Typically, a derived class calls Cancel() in its destructor.
56 @panic E32USER-CBase 40 if the active object has an outstanding request when
57 the destructor is called,
62 __ASSERT_ALWAYS(!(iStatus.iFlags&TRequestStatus::EActive),Panic(EReqStillActiveOnDestruct));
70 EXPORT_C void CActive::Cancel()
72 Cancels the wait for completion of an outstanding request.
74 If there is no request outstanding, then the function does nothing.
76 If there is an outstanding request, the function:
78 1. calls the active object's DoCancel() function, provided by
79 the derived class to implement cancellation of the request.
81 2. waits for the cancelled request to complete; this must complete as fast as
84 3. marks the active object's request as complete (i.e. the request is no longer
87 @see CActive::DoCancel
88 @see CActive::IsActive
89 @see CActive::~CActive
90 @see User::WaitForRequest
93 if (iStatus.iFlags&TRequestStatus::EActive)
96 User::WaitForRequest(iStatus);
97 iStatus.iFlags&=~(TRequestStatus::EActive | TRequestStatus::ERequestPending); //iActive=EFalse;
104 EXPORT_C void CActive::Deque()
106 Removes the active object from the active scheduler's list of active objects.
108 Before being removed from the active scheduler's list, the function cancels
109 any outstanding request.
114 __ASSERT_ALWAYS(IsAdded(),Panic(EActiveNotAdded));
117 iLink.iNext=NULL; // Must do this or object cannot be re-queued
123 EXPORT_C void CActive::SetActive()
125 Indicates that the active object has issued a request and that
126 it is now outstanding.
128 Derived classes must call this function after issuing a request.
130 A request is automatically marked as complete (i.e. it is no longer
133 1. the active scheduler, immediately before it calls the active object's RunL()
138 2. the active object within the implementation of the Cancel() function.
140 E32USER-CBase 46 panics may occur if an active object is set active but
141 no request is made on its TRequestStatus, or vice-versa. This panic happens
142 no earlier than the next time that the active scheduler assesses which
143 objects are ready to run, and may happen much later. This panic is termed
144 a 'stray event' because it indicates that some entity has sent an event
145 to the active scheduler thread, but this thread is not in a state ready to handle it.
147 @see CActive::IsActive
151 @panic E32USER-CBase 42 if this active object is already active
152 @panic E32USER-CBase 49 if this active object has not been added to the active
156 __ASSERT_ALWAYS(!(iStatus.iFlags&TRequestStatus::EActive),Panic(EReqAlreadyActive));
157 __ASSERT_ALWAYS(IsAdded(),Panic(EActiveNotAdded));
158 iStatus.iFlags|=TRequestStatus::EActive;
164 EXPORT_C void CActive::SetPriority(TInt aPriority)
166 Sets the priority of the active object.
168 @param aPriority An integer specifying the new priority of this active object.
169 CActive::TPriority defines a standard set of priorities.
171 @panic E32USER-CBase 50 if this function is called while a request
175 __ASSERT_ALWAYS(!(iStatus.iFlags&TRequestStatus::EActive),Panic(ESetPriorityActive));
176 iLink.iPriority=aPriority;
180 iLink.iNext=NULL; // Make this not added
181 CActiveScheduler::Add(this);
188 EXPORT_C TInt CActive::RunError(TInt aError)
190 Handles a leave occurring in the request completion event handler RunL().
192 The active scheduler calls this function if this active object's RunL()
193 function leaves. This gives this active object the opportunity to perform
194 any necessary cleanup.
196 A derived class implementation should handle the leave and return KErrNone.
197 Returning any other value results in the active scheduler function
198 CActiveScheduler::Error() being called.
200 The default implementation simply returns the leave code.
202 Note that if the active scheduler is to handle the error, a suitably derived
203 CActiveScheduler::Error() function must be supplied.
205 @param aError The leave code
207 @return The default implementation returns aError. A derived class
208 implementation should return KErrNone, if it handles the leave;
209 otherwise it should return any suitable value to cause the handling
210 of the error to be propagated back to the active scheduler.
212 @see CActiveScheduler::Error
226 EXPORT_C TInt CActive::Extension_(TUint aExtensionId, TAny*& a0, TAny* a1)
228 return CBase::Extension_(aExtensionId, a0, a1);
234 EXPORT_C CIdle* CIdle::New(TInt aPriority)
236 Allocates and initialises an Idle time active object and adds it to the active
239 @param aPriority An integer specifying the priority of this active object.
240 It must be lower than that of all other active objects on
241 the active scheduler.
242 The value CActive::TPriority::EPriorityIdle is recommended.
244 @return Pointer to the new Idle time active object, or NULL if the object could
248 CIdle *pI=new CIdle(aPriority);
250 CActiveScheduler::Add(pI);
257 EXPORT_C CIdle* CIdle::NewL(TInt aPriority)
259 Allocates and initialises an Idle time active object, adds it to the active
260 scheduler, but leaves on failure.
262 @param aPriority An integer specifying the priority of this active object.
263 It must be lower than that of all other active objects on
264 the active scheduler.
265 The value CActive::TPriority::EPriorityIdle is recommended.
267 @return Pointer to the new Idle time active object.
270 CIdle *pI=new(ELeave) CIdle(aPriority);
271 CActiveScheduler::Add(pI);
279 EXPORT_C CIdle::CIdle(TInt aPriority)
282 Protected constructor taking a priority value.
284 Sets this active object's priority value.
286 @param aPriority The active object priority value.
293 EXPORT_C CIdle::~CIdle()
295 Frees resources prior to destruction.
297 Specifically, it cancels any outstanding request.
306 EXPORT_C void CIdle::Start(TCallBack aCallBack)
308 Starts the background task.
310 The background task is encapsulated in the callback. The function represented
311 by this callback is called every time this Idle time active object is scheduled
314 The callback function should be structured to perform a background task in
315 many increments, i.e. it should voluntarily relinquish control (i.e. return)
316 after a suitable time interval to allow other, higher priority events to be
319 If the callback function has further work to do, it should return a true value.
320 This ensures that the active object is scheduled to run again later.
322 Once the callback function has finally completed its work, it should return
323 a false value. The active object is then no longer scheduled to run.
325 @param aCallBack A callback object encapsulating a function which is called
326 when no higher priority active object is ready to run.
330 iStatus=KRequestPending;
331 TRequestStatus *pS=(&iStatus);
332 User::RequestComplete(pS,0);
339 EXPORT_C void CIdle::RunL()
341 Handles this idle active object's request completion event.
343 It is called when nothing of a higher priority can be scheduled.
348 if (iCallBack.CallBack())
355 EXPORT_C void CIdle::DoCancel()
357 Implements the cancellation of an outstanding request.
359 This function is called by the active object's Cancel() function.
361 @see CActive::DoCancel
369 EXPORT_C void CAsyncOneShot::Call()
371 Queues this active object to be run once.
373 @panic E32USER-CBase 2 In debug builds only, if this active object has not
374 already been added to the active scheduler.
377 __ASSERT_DEBUG(IsAdded(),Panic(ECAsyncOneShotNotAdded));
378 TRequestStatus *pS=(&iStatus);
379 iStatus = KRequestPending;
381 iThread.RequestComplete(pS,0);
387 EXPORT_C void CAsyncOneShot::DoCancel()
389 Implements cancellation of an outstanding request.
391 The class provides an empty implementation.
393 This is called by the destructor.
402 EXPORT_C CAsyncOneShot::CAsyncOneShot(TInt aPriority)
405 Constructor taking a priority value.
407 Specifically, the constructor:
409 1. sets this active object's priority value
411 2. opens a handle to the current thread to ensure that the thread cannot be
412 closed until this CAsyncOneShot object is destroyed
414 3. adds this active object to the current active scheduler.
416 @param aPriority The active object priority value. CActive::TPriority defines
417 a standard set of priorities.
419 @panic E32USER-CBase 93 if the attempt to open a handle to the current thread
429 void CAsyncOneShot::Setup()
431 // ensures that we are added to the Scheduler.
434 // No error checking was done initially. As this function is called from
435 // the c'tor, there is no way to fix it properly without breaking BC. So
436 // we panic if something goes wrong (should only happen in extreme
437 // circumstances if the kernel heap is exhausted or heavily fragmented).
438 __ASSERT_ALWAYS(iThread.Duplicate(RThread()) == KErrNone, Panic(EAsyncOneShotSetupFailed));
440 // Add ourself to the current active scheduler
441 // This is because we might be being used as an inter thread call
442 // we need to make sure that we're on the correct scheduler for
443 // the RThread were going to duplicate.
444 CActiveScheduler::Add(this);
450 EXPORT_C CAsyncOneShot::~CAsyncOneShot()
452 Frees resources prior to destruction.
454 Specifically, it closes the handle to the current thread.
456 @see CActive::~CActive
466 EXPORT_C CAsyncCallBack::CAsyncCallBack(TInt aPriority)
467 : CAsyncOneShot(aPriority), iCallBack(NULL)
469 Constructor taking a priority value.
471 Specifically, the constructor sets this active object's priority value through
472 a call to the base class constructor in its ctor list.
474 No call back is set, which means that it must be set subsequently through
475 a call to the Set() function.
477 @param aPriority The active object priority value. CActive::TPriority defines
478 a standard set of priorities.
480 @see CAsyncCallBack::Set
488 EXPORT_C CAsyncCallBack::CAsyncCallBack(const TCallBack& aCallBack, TInt aPriority)
489 : CAsyncOneShot(aPriority), iCallBack(aCallBack)
491 Constructor taking a priority value and a callback.
493 Specifically, the constructor:
495 1. sets this active object's priority value through a call to the base class
496 constructor in its ctor list
498 2. sets the callback; the function encapsulated by the callback is called when
499 this active object is scheduled to run.
501 @param aCallBack A reference to a callback object encapsulating a function
502 which is called when this active object is ready to run.
503 The constructor takes a copy of this callback object, which
504 means that it can be safely discarded after construction.
505 @param aPriority The active object priority value.
513 EXPORT_C CAsyncCallBack::~CAsyncCallBack()
523 EXPORT_C void CAsyncCallBack::CallBack()
525 Queues this active object to be run, if it is not already queued.
535 EXPORT_C void CAsyncCallBack::Set(const TCallBack& aCallBack)
539 @param aCallBack A reference to a callback object encapsulating a function
540 which is called when this active object is ready to run.
542 @panic E32USER-CBase 1 if the active object is currently active.
545 __ASSERT_ALWAYS(!IsActive(), Panic(ECAsyncCBIsActive));
546 iCallBack = aCallBack;
552 void CAsyncCallBack::RunL()
554 Calls the callback function.
556 @see TCallBack::CallBack
559 iCallBack.CallBack();
565 struct CActiveScheduler::TLoop
568 CActiveScheduler::TLoopOwner* iOwner;
573 CActiveScheduler::TLoopOwner* const KLoopNoOwner=reinterpret_cast<CActiveScheduler::TLoopOwner*>(1);
574 CActiveScheduler::TLoopOwner* const KLoopInactive=0;
579 EXPORT_C CActiveSchedulerWait::CActiveSchedulerWait()
589 EXPORT_C CActiveSchedulerWait::~CActiveSchedulerWait()
591 Ensures that the attached scheduler loop, and all nested loops, are stopped
592 prior to destruction.
604 EXPORT_C void CActiveSchedulerWait::Start()
606 Starts a new wait loop under the control of the current active scheduler.
608 Compared with CActiveScheduler::Start(), this object owns control of
609 the scheduling loop that is started, and that loop can only be stopped
610 by using this objects AsyncStop() function or the CActiveScheduler::Halt()
611 function. Start() only returns when either of thos has occurred.
613 This is the preferred way to start a nested wait loop. Typically, a nested
614 wait loop is used when the handling of a completed event in an active object
615 requires processing further events from the other active objects before it
616 can complete. This is a form of modal processing.
618 @panic E32USER-CBase 44 if the thread does not have an active scheduler installed.
619 @panic E32USER-CBase 91 if this object has already been started.
621 @see CActiveSchedulerWait::AsyncStop
622 @see CActiveSchedulerWait::IsStarted
623 @see CActiveScheduler::Start
624 @see CActiveScheduler::Halt
627 __ASSERT_ALWAYS(!IsStarted(), Panic(EActiveSchedulerWaitAlreadyStarted)); // can only start a CActiveSchedulerWait if it isn't already started
628 CActiveScheduler::Start(&iLoop);
634 EXPORT_C void CActiveSchedulerWait::AsyncStop()
636 Stops the scheduling loop owned by this object.
638 Note that the corresponding call to Start() only returns once all nested
639 scheduler loops have stopped.
641 @panic E32USER-CBase 92 if the wait object has not been started.
644 AsyncStop(TCallBack());
650 EXPORT_C void CActiveSchedulerWait::AsyncStop(const TCallBack& aCallMeWhenStopped)
652 Stops the scheduling loop owned by this object, specifying a callback.
654 This version of AsyncStop() provides a callback which is invoked immediately
655 after the scheduler loop actually stops before the corresponding call
658 Note that the corresponding call to Start() only returns once all nested
659 scheduler loops have stopped.
661 @param aCallMeWhenStopped The callback to invoke when the scheduler loop exits.
663 @panic E32USER-CBase 92 if the wait object has not been started.
666 CActiveScheduler::TLoopOwner loop=iLoop;
667 __ASSERT_ALWAYS(loop, Panic(EActiveSchedulerWaitNotStarted)); // can only stop a CActiveSchedulerWait if it's started
668 __ASSERT_DEBUG(loop->iOwner==&iLoop, User::Invariant());
670 loop->iCallback = aCallMeWhenStopped;
671 loop->iOwner = KLoopInactive; // disconnect from owner
678 EXPORT_C TBool CActiveSchedulerWait::CanStopNow() const
680 Reports whether stopping will have immediate effect.
682 This returns an indication of whether a call to AsyncStop() would be
683 expected to stop the scheduler loop immediately, or whether it will
684 have to wait until nested scheduler loops have stopped. This may alter
685 which version of AsyncStop() you would want to call.
687 @return Boolean indicating if the scheduling loop would stop immediately.
689 @panic E32USER-CBase 92 if the wait object has not been started.
691 @see CActiveSchedulerWait::Start
692 @see CActiveSchedulerWait::AsyncStop
695 __ASSERT_ALWAYS(IsStarted(), Panic(EActiveSchedulerWaitNotStarted)); // Scheduler must be running
696 for (CActiveScheduler::TLoop* loop=GetActiveScheduler()->iStack; loop; loop=loop->iNext)
700 if (loop->iOwner != KLoopInactive)
708 EXPORT_C CActiveScheduler::CActiveScheduler()
709 : iActiveQ(_FOFF(CActive,iLink))
711 Constructs an active scheduler.
713 After construction, the scheduler should be installed.
715 @see CActiveScheduler::Install
722 EXPORT_C CActiveScheduler::~CActiveScheduler()
724 Frees resources prior to destruction.
726 Specifically, it removes all active objects from the active scheduler's list
729 An active scheduler should only be destroyed when the top-level call to Start()
732 @see CActiveScheduler::Start
733 @see CActiveScheduler::Stop
736 while (!iActiveQ.IsEmpty())
737 iActiveQ.First()->Deque();
738 if (GetActiveScheduler()==this)
739 SetActiveScheduler(NULL);
745 EXPORT_C void CActiveScheduler::Install(CActiveScheduler *aManager)
747 Installs the specified active scheduler as the current active scheduler.
749 The installed active scheduler now handles events for this thread.
751 The current active scheduler can be uninstalled by passing a NULL pointer.
753 @param aManager A pointer to the active scheduler to be installed.
754 If this is NULL, the current active scheduler is uninstalled.
756 @panic E32USER-CBase 43 if If there is already an installed active scheduler.
760 __ASSERT_ALWAYS(GetActiveScheduler()==NULL,Panic(EReqManagerAlreadyExists));
761 SetActiveScheduler(aManager);
767 EXPORT_C void CActiveScheduler::Add(CActive *aRequest)
769 Adds the specified active object to the current active scheduler.
771 An active object can be removed from an active scheduler either by
772 destroying the active object or by using its Deque() member function.
774 @param aRequest Pointer to the active object to be added.
776 @panic E32USER-CBase 41 if the active object aRequest has already been added
777 to the current active scheduler.
778 @panic E32USER-CBase 48 if aRequest is NULL.
779 @panic E32USER-CBase 44 if the thread does not have an installed
785 CActiveScheduler *pS=GetActiveScheduler();
786 __ASSERT_ALWAYS(pS!=NULL,Panic(EReqManagerDoesNotExist));
787 __ASSERT_ALWAYS(aRequest,Panic(EReqNull));
788 __ASSERT_ALWAYS(!aRequest->IsAdded(),Panic(EReqAlreadyAdded));
789 pS->iActiveQ.Add(*aRequest);
795 EXPORT_C void CActiveScheduler::WaitForAnyRequest()
797 Wait for an asynchronous request to complete.
799 The default implementation just calls User::WaitForAnyRequest().
801 Derived classes can replace this. Typically, this would be done to implement
802 code for maintaining an outstanding request; this would be followed by a call
803 to User::WaitForAnyRequest().
805 @see User::WaitForAnyRequest
808 User::WaitForAnyRequest();
814 EXPORT_C void CActiveScheduler::Start()
816 Starts a new wait loop under the control of the current active scheduler.
818 At least one active object, with an outstanding request, must be added
819 to the scheduler before the wait loop is started, otherwise no events
820 will occur and the thread will hang, or any events that do occur will be
821 counted as stray signals, raising a panic.
823 While Start() is executing, user code runs only:
825 1. in the RunL() function of active objects known to the current active scheduler
827 2. in the RunError() function of an active object that leaves from its RunL()
829 3. in the current active scheduler’s Error() function, if an active object’s
830 RunError() returns an error code.
832 Start() returns only when a corresponding Stop() or Halt() is issued.
834 Although this can be used to start a nested wait loop, this API is deprecated
835 for that specific functionality, and a CActiveSchedulerWait object should be
838 (Note that a nested wait loop is used when the handling of a completed event
839 in an active object requires the processing of further events from the other
840 active objects before it can complete. This is a form of modal processing.)
842 @panic E32USER-CBase 44 if the thread does not have an active
845 @see CActiveScheduler::Stop
846 @see CActiveScheduler::Halt
848 @see CActive::RunError
849 @see CActiveScheduler::Error
850 @see CActiveSchedulerWait
859 void CActiveScheduler::Start(TLoopOwner* aOwner)
863 Start a new nesting level
866 CActiveScheduler* pS=GetActiveScheduler();
867 __ASSERT_ALWAYS(pS!=NULL, Panic(EReqManagerDoesNotExist));
869 // Instantiate the local loop control
872 if (aOwner != KLoopNoOwner)
874 loop.iNext=pS->iStack;
878 // Run the scheduler loop
880 // FIXME!!! Will support old-style leave-from-Error() transiently
881 // in order to avoid simultaneous integration requirement.
882 // This should be reverted to the conditionally excluded code once
883 // fixes have been made elsewhere
884 TRAPD(r,pS->Run(loop.iOwner));
888 TLoopOwner* owner=loop.iOwner;
889 if (TUint(owner) > TUint(KLoopNoOwner))
894 // catch old-style bad behaviour - leaving from Error()
895 TRAPD(r,pS->Run(loop.iOwner));
896 __ASSERT_DEBUG(r==KErrNone,User::Invariant());
898 pS->Run(loop.iOwner);
902 pS->iStack=loop.iNext;
903 loop.iCallback.CallBack();
904 // propagate the exit-code via a leave (yuck, but blame BAFL & co.)
906 User::Leave(loop.iExitCode);
912 Dummy Function. This is used as a dummy object to put onto the cleanupstack in order
913 to check for imbalance in the CActiveScheduler::DoRunL.
915 void DummyFunc(TAny* /*aPtr*/)
919 #ifdef __LEAVE_EQUALS_THROW__
923 Start dispatching request completions.
925 Stop when aLoop becomes 'Inactive'
927 This version uses the implementation of TRAP/Leave in terms of C++ exceptions.
928 We have to make sure here that we don't call Active Object's RunError() or Active Scheduler's Error()
929 while we are still in exception (within 'catch' brackets), as it can lead to nested-exceptions scenario.
930 It is not fatal by default, but if two nested exceptions are due to OOM condition, RVCT implementation
931 of exception will run out of emergency buffers and terminate the thread.
933 void CActiveScheduler::Run(TLoopOwner* const volatile& aLoop)
935 CActive * volatile curr_obj = 0;
936 TBool leaveException = EFalse;
937 TInt exceptionReason = 0;
942 TTrapHandler* t = User::MarkCleanupStack();
945 //We cache the cleanupstack here do avoid repeated exec calls in DoRunL
946 TCleanupTrapHandler *pH=(TCleanupTrapHandler *)GetTrapHandler();
947 CCleanup* cleanupPtr=NULL;
948 TCleanupBundle cleanupBundle;
950 if(pH!=NULL) // test whether there's a CleanupTrapHandler installed
952 CCleanup& ccleanup =pH->Cleanup();
953 //Store pointer as need the scope of ccleanup increased
954 cleanupPtr = &ccleanup;
955 cleanupBundle.iCleanupPtr = cleanupPtr;
957 //Push a dummy item onto the stack - we check it after the AO's RunL has returned
958 //and we check to make sure its still at the top.
959 ccleanup.PushL(TCleanupItem(DummyFunc, &(cleanupBundle.iDummyInt)));
961 DoRunL(aLoop, curr_obj, &cleanupBundle);
963 //Dummy Int must (will) be at the top
967 else // no cleanup stack installed
969 DoRunL(aLoop, curr_obj, NULL);
973 DoRunL(aLoop, curr_obj, NULL);
976 User::UnMarkCleanupStack(t);
980 catch (XLeaveException& l)
983 leaveException = ETrue;
984 exceptionReason = l.Reason();
993 if (exceptionReason != KErrNone)
995 TInt r = curr_obj->RunError(exceptionReason);
999 leaveException = EFalse;
1002 } while (aLoop != KLoopInactive);
1010 Start dispatching request completions.
1012 Stop when aLoop becomes 'Inactive'
1014 This version uses the original implementation of TRAP/Leave.
1016 void CActiveScheduler::Run(TLoopOwner* const volatile& aLoop)
1018 CActive * volatile curr_obj = 0;
1021 // explicitly expand the TRAPD macro here to enable single-step debugging
1022 // of the scheduler loop
1025 if (trap.Trap(r)==0)
1028 //We cache the cleanupstack here do avoid repeated exec calls in DoRunL
1029 TCleanupTrapHandler *pH=(TCleanupTrapHandler *)GetTrapHandler();
1030 CCleanup* cleanupPtr=NULL;
1031 TCleanupBundle cleanupBundle;
1033 if(pH!=NULL) // test whether there's a CleanupTrapHandler installed
1035 CCleanup& ccleanup =pH->Cleanup();
1036 //Store pointer as need the scope of ccleanup increased
1037 cleanupPtr = &ccleanup;
1038 cleanupBundle.iCleanupPtr = cleanupPtr;
1040 //Push a dummy item onto the stack - we check it after the AO's RunL has returned
1041 //and we check to make sure its still at the top.
1042 ccleanup.PushL(TCleanupItem(DummyFunc, &(cleanupBundle.iDummyInt)));
1044 DoRunL(aLoop, curr_obj, &cleanupBundle);
1046 //Dummy Int must (will) be at the top
1050 else // no cleanup stack installed
1052 DoRunL(aLoop, curr_obj, NULL);
1055 DoRunL(aLoop, curr_obj, NULL);
1059 return; // exit level
1063 r = curr_obj->RunError(r);
1067 } while (aLoop != KLoopInactive);
1071 #ifndef __CACTIVESCHEDULER_MACHINE_CODED__
1075 The inner active scheduler loop. This repeatedly waits for a signal and then
1076 dispatches the highest priority ready active object. The loop terminates either
1077 if one of the RunLs stops the current active scheduler level or leaves.
1079 Stop when aLoop becomes 'Inactive'
1080 @panic EClnCheckFailed 90 This will panic when the RunL has left the cleanup stack in an unbalanced state.
1083 void CActiveScheduler::DoRunL(TLoopOwner* const volatile& aLoop, CActive* volatile & aCurrentObj, TCleanupBundle* aCleanupBundlePtr)
1085 void CActiveScheduler::DoRunL(TLoopOwner* const volatile& aLoop, CActive* volatile & aCurrentObj, TCleanupBundle* /*aCleanupBundlePtr*/)
1088 TDblQueIter<CActive> q(iActiveQ);
1091 WaitForAnyRequest();
1097 __ASSERT_ALWAYS(pR!=NULL,Panic(EReqStrayEvent));
1098 //if the line below panics it's either because you made a request but you haven't
1099 //SetActive the object (pR->iStatus.iFlags&TRequestStatus::EActive==0) or you didn't set the iStatus
1100 //to KRequestPending (pR->iStatus.iFlags&TRequestStatus::ERequestPending==0)
1101 __ASSERT_DEBUG(!(pR->iStatus.iFlags&TRequestStatus::EActive)==!(pR->iStatus.iFlags&TRequestStatus::ERequestPending),Panic(EReqStrayEvent));
1102 } while (!pR->IsActive() || pR->iStatus==KRequestPending);
1104 __e32_memory_barrier();
1106 pR->iStatus.iFlags&=~(TRequestStatus::EActive | TRequestStatus::ERequestPending); //pR->iActive=EFalse;
1111 if(aCleanupBundlePtr!=NULL)
1113 //If the following line panics, the RunL left the
1114 //cleanup stack in an umbalanced state.
1115 TInt* dummyInt = &(aCleanupBundlePtr->iDummyInt);
1116 aCleanupBundlePtr->iCleanupPtr->Check(dummyInt);
1120 } while (aLoop != KLoopInactive);
1121 return; // exit level
1126 extern "C" void PanicStrayEvent()
1128 Panic(EReqStrayEvent);
1135 EXPORT_C void CActiveScheduler::Stop()
1137 Stops the wait loop started by the most recent call to Start().
1139 Typically, this is called by the RunL() of one of the scheduler’s active
1140 objects. When this RunL() finishes, the scheduler’s wait loop terminates,
1141 i.e. it does not wait for the completion of the next request.
1143 It will not stop a wait loop started by a call
1144 to CActiveSchedulerWait::Start().
1146 Stop() may also be called from Error().
1148 Note that stopping a nested wait loop is deprecated using this functionality,
1149 use a CActiveSchedulerWait object instead.
1151 @see CActiveSchedulerWait::Start
1153 @see CActiveSchedulerWait::Error
1154 @see CActiveSchedulerWait::AsyncStop
1157 CActiveScheduler *pS=GetActiveScheduler();
1158 __ASSERT_ALWAYS(pS!=NULL,Panic(EReqManagerDoesNotExist));
1160 for (CActiveScheduler::TLoop* loop=pS->iStack; loop; loop=loop->iNext)
1162 if (loop->iOwner == KLoopNoOwner)
1164 loop->iOwner=KLoopInactive;
1168 Panic(EReqTooManyStops);
1174 EXPORT_C void CActiveScheduler::Halt(TInt aExitCode) const
1176 Unilaterally terminates the current scheduler loop.
1178 This causes the current scheduler loop to stop, whether it was started
1179 using CActiveSchedulerWait::Start() or CActiveScheduler::Start(). It can
1180 also trigger a leave from Start() if an exit code is provided. If the
1181 current level has already been stopped, then this still records the exit code.
1183 @param aExitCode If non-zero, the reason code reported by Start().
1186 CActiveScheduler::TLoop* loop=iStack;
1187 __ASSERT_ALWAYS(loop!=NULL,Panic(EReqTooManyStops));
1188 TLoopOwner* owner=loop->iOwner;
1189 if (TUint(owner) > TUint(KLoopNoOwner))
1191 loop->iOwner = KLoopInactive; // disconnect from owner
1192 loop->iExitCode = aExitCode;
1198 EXPORT_C TInt CActiveScheduler::StackDepth() const
1200 Gets the current number of nested wait loops.
1202 @return The number of nested calls to Start().
1206 for (CActiveScheduler::TLoop* loop=iStack; loop; loop=loop->iNext)
1214 EXPORT_C CActiveScheduler* CActiveScheduler::Current()
1216 Gets a pointer to the currently installed active scheduler.
1218 @return A pointer to the active scheduler which is currently installed.
1221 return GetActiveScheduler();
1227 EXPORT_C void CActiveScheduler::Error(TInt /*aError*/) const
1229 Handles the result of a leave occurring in an active object’s RunL()
1232 An active scheduler always invokes an active object’s RunL()
1233 function under a trap harness.
1235 The default implementation must be replaced.
1237 Any cleanup relevant to the possible causes of leaving should
1238 be performed. If Stop() or Halt() is called from within this function, the
1239 current wait loop terminates. This may be an appropriate response to
1240 catastrophic error conditions.
1242 @param aError The leave code propagated from the active object’s RunL() function
1244 @panic E32USER-CBase 47 if the default implementation is invoked.
1247 @see CActiveScheduler::Stop
1248 @see CActiveScheduler::Halt
1251 Panic(EReqActiveObjectLeave);
1257 EXPORT_C TBool CActiveScheduler::RunIfReady(TInt& aError, TInt aMinimumPriority)
1261 Causes the RunL() function of at most one pending active object of priority
1262 aMinimumPriority or greater to be run.
1264 @param aError Error returned by called active object.
1265 @param aMinimumPriority Minimum priority of active object to run.
1267 @return EFalse if no active object's RunL() function was run, i.e. if there
1268 were no active objects of priority aMinimumPriority or greater pending.
1272 CActiveScheduler* pS=GetActiveScheduler();
1275 TDblQueIter<CActive> iterator(pS->iActiveQ);
1276 for (CActive* active=iterator++; (active!=NULL) && (active->Priority()>=aMinimumPriority); active=iterator++)
1278 if (active->IsActive() && (active->iStatus!=KRequestPending))
1280 active->iStatus.iFlags&=~(TRequestStatus::EActive | TRequestStatus::ERequestPending); //pR->iActive=EFalse;
1281 TRAP(aError, active->RunL());
1282 if (aError!=KErrNone)
1283 aError=active->RunError(aError);
1294 EXPORT_C CActiveScheduler* CActiveScheduler::Replace(CActiveScheduler* aNewActiveScheduler)
1296 Allows the current active scheduler to be replaced, while retaining its active
1299 @param aNewActiveScheduler The new active scheduler.
1301 @return Previous active scheduler.
1304 __ASSERT_ALWAYS(aNewActiveScheduler!=NULL, Panic(EReqManagerDoesNotExist));
1305 CActiveScheduler* oldActiveScheduler=GetActiveScheduler();
1306 __ASSERT_ALWAYS(aNewActiveScheduler!=oldActiveScheduler, Panic(EActiveSchedulerReplacingSelf));
1307 if (oldActiveScheduler!=NULL)
1309 // steal all the CActive objects from oldActiveScheduler (without canceling any of them)
1310 TPriQue<CActive>& oldActiveQ=oldActiveScheduler->iActiveQ;
1311 TPriQue<CActive>& newActiveQ=aNewActiveScheduler->iActiveQ;
1312 while (!oldActiveQ.IsEmpty())
1314 CActive& active=*oldActiveQ.First();
1315 // call the lower-level function active.iLink.Deque() rather than active.Deque()
1316 // as the latter would also call active.Cancel() (which we don't want)
1317 active.iLink.Deque();
1318 newActiveQ.Add(active);
1321 SetActiveScheduler(aNewActiveScheduler);
1322 return oldActiveScheduler;
1328 EXPORT_C void CActiveScheduler::OnStarting()
1332 Dummy EXPORT for Binary Compatibility reasons.
1333 This method is never called.
1341 EXPORT_C void CActiveScheduler::OnStopping()
1345 Dummy EXPORT for Binary Compatibility reasons.
1346 This method is never called.
1353 EXPORT_C void CActiveScheduler::Reserved_1()
1357 Dummy EXPORT for Binary Compatibility reasons.
1364 EXPORT_C void CActiveScheduler::Reserved_2()
1368 Dummy EXPORT for Binary Compatibility reasons.
1379 EXPORT_C TInt CActiveScheduler::Extension_(TUint aExtensionId, TAny*& a0, TAny* a1)
1381 return CBase::Extension_(aExtensionId, a0, a1);