os/kernelhwsrv/kernel/eka/euser/cbase/ub_act.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
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".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // e32\euser\cbase\ub_act.cpp
    15 // 
    16 //
    17 
    18 #include "ub_std.h"
    19 #include "us_data.h"
    20 
    21 #ifdef __SMP__
    22 #include <e32atomics.h>
    23 #endif
    24 
    25 
    26 
    27 #pragma warning( disable : 4705 )	// statement has no effect
    28 EXPORT_C CActive::CActive(TInt aPriority)
    29 /**
    30 Constructs the active object with the specified priority.
    31 
    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.
    35 
    36 @param aPriority An integer specifying the priority of this active object.
    37                  CActive::TPriority defines a standard set of priorities.
    38 */
    39 	{
    40 	iLink.iPriority=aPriority;
    41 	}
    42 #pragma warning( default : 4705 )
    43 
    44 
    45 
    46 
    47 EXPORT_C CActive::~CActive()
    48 /**
    49 Frees resources prior to destruction.
    50 
    51 Specifically, it removes this active object from the active scheduler's
    52 list of active objects.
    53 
    54 Typically, a derived class calls Cancel() in its destructor.
    55 
    56 @panic E32USER-CBase 40 if the active object has an outstanding request when
    57        the destructor is called,
    58 
    59 @see CActive::Cancel
    60 */
    61 	{
    62 	__ASSERT_ALWAYS(!(iStatus.iFlags&TRequestStatus::EActive),Panic(EReqStillActiveOnDestruct));
    63 	if (IsAdded())
    64 		iLink.Deque();
    65 	}
    66 
    67 
    68 
    69 
    70 EXPORT_C void CActive::Cancel()
    71 /**
    72 Cancels the wait for completion of an outstanding request.
    73 
    74 If there is no request outstanding, then the function does nothing.
    75 
    76 If there is an outstanding request, the function:
    77 
    78 1. calls the active object's DoCancel() function, provided by
    79    the derived class to implement cancellation of the request.
    80 
    81 2. waits for the cancelled request to complete; this must complete as fast as
    82    possible.
    83 
    84 3. marks the active object's request as complete (i.e. the request is no longer
    85    outstanding).
    86 
    87 @see CActive::DoCancel
    88 @see CActive::IsActive
    89 @see CActive::~CActive
    90 @see User::WaitForRequest
    91 */
    92 	{
    93 	if (iStatus.iFlags&TRequestStatus::EActive)
    94 		{
    95 		DoCancel();
    96 		User::WaitForRequest(iStatus);
    97     	iStatus.iFlags&=~(TRequestStatus::EActive | TRequestStatus::ERequestPending); //iActive=EFalse;
    98 		}
    99 	}
   100 
   101 
   102 
   103 
   104 EXPORT_C void CActive::Deque()
   105 /**
   106 Removes the active object from the active scheduler's list of active objects.
   107 
   108 Before being removed from the active scheduler's list, the function cancels
   109 any outstanding request.
   110 
   111 @see CActive::Cancel
   112 */
   113 	{
   114 	__ASSERT_ALWAYS(IsAdded(),Panic(EActiveNotAdded));
   115 	Cancel();
   116 	iLink.Deque();
   117 	iLink.iNext=NULL; // Must do this or object cannot be re-queued
   118 	}
   119 
   120 
   121 
   122 
   123 EXPORT_C void CActive::SetActive()
   124 /**
   125 Indicates that the active object has issued a request and that
   126 it is now outstanding.
   127 
   128 Derived classes must call this function after issuing a request.
   129 
   130 A request is automatically marked as complete (i.e. it is no longer
   131 outstanding) by:
   132 
   133 1. the active scheduler, immediately before it calls the active object's RunL()
   134    function.
   135 
   136 or
   137 
   138 2. the active object within the implementation of the Cancel() function.
   139 
   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.
   146 
   147 @see CActive::IsActive
   148 @see CActive::RunL
   149 @see CActive::Cancel
   150 
   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
   153        scheduler.
   154 */
   155 	{
   156 	__ASSERT_ALWAYS(!(iStatus.iFlags&TRequestStatus::EActive),Panic(EReqAlreadyActive));
   157 	__ASSERT_ALWAYS(IsAdded(),Panic(EActiveNotAdded));
   158 	iStatus.iFlags|=TRequestStatus::EActive;
   159 	}
   160 
   161 
   162 
   163 
   164 EXPORT_C void CActive::SetPriority(TInt aPriority)
   165 /**
   166 Sets the priority of the active object.
   167 
   168 @param aPriority An integer specifying the new priority of this active object.
   169                  CActive::TPriority defines a standard set of priorities.
   170 
   171 @panic E32USER-CBase 50 if this function is called while a request
   172        is outstanding.
   173 */
   174 	{
   175 	__ASSERT_ALWAYS(!(iStatus.iFlags&TRequestStatus::EActive),Panic(ESetPriorityActive));
   176 	iLink.iPriority=aPriority;
   177 	if (IsAdded())
   178 		{
   179 		Deque();
   180 		iLink.iNext=NULL; // Make this not added
   181 		CActiveScheduler::Add(this);
   182 		}
   183 	}
   184 
   185 
   186 
   187 
   188 EXPORT_C TInt CActive::RunError(TInt aError)
   189 /**
   190 Handles a leave occurring in the request completion event handler RunL().
   191 
   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.
   195 
   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.
   199 
   200 The default implementation simply returns the leave code.
   201 
   202 Note that if the active scheduler is to handle the error, a suitably derived
   203 CActiveScheduler::Error() function must be supplied.
   204 
   205 @param aError The leave code
   206 
   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.
   211 
   212 @see CActiveScheduler::Error
   213 */
   214 	{
   215 	return aError;
   216 	}
   217 
   218 
   219 
   220 
   221 /**
   222 Extension function
   223 
   224 
   225 */
   226 EXPORT_C TInt CActive::Extension_(TUint aExtensionId, TAny*& a0, TAny* a1)
   227 	{
   228 	return CBase::Extension_(aExtensionId, a0, a1);
   229 	}
   230 
   231 
   232 
   233 
   234 EXPORT_C CIdle* CIdle::New(TInt aPriority)
   235 /**
   236 Allocates and initialises an Idle time active object and adds it to the active
   237 scheduler.
   238 
   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.
   243 
   244 @return Pointer to the new Idle time active object, or NULL if the object could
   245         not be created.
   246 */
   247 	{
   248 	CIdle *pI=new CIdle(aPriority);
   249 	if (pI!=NULL)
   250 		CActiveScheduler::Add(pI);
   251 	return(pI);
   252 	}
   253 
   254 
   255 
   256 
   257 EXPORT_C CIdle* CIdle::NewL(TInt aPriority)
   258 /**
   259 Allocates and initialises an Idle time active object, adds it to the active
   260 scheduler, but leaves on failure.
   261 
   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.
   266 
   267 @return Pointer to the new Idle time active object.
   268 */
   269 	{
   270 	CIdle *pI=new(ELeave) CIdle(aPriority);
   271 	CActiveScheduler::Add(pI);
   272 	return(pI);
   273 	}
   274 
   275 
   276 
   277 
   278 
   279 EXPORT_C CIdle::CIdle(TInt aPriority)
   280 	: CActive(aPriority)
   281 /**
   282 Protected constructor taking a priority value.
   283 
   284 Sets this active object's priority value.
   285 
   286 @param aPriority The active object priority value.
   287 */
   288 	{}
   289 
   290 
   291 
   292 
   293 EXPORT_C CIdle::~CIdle()
   294 /**
   295 Frees resources prior to destruction.
   296 
   297 Specifically, it cancels any outstanding request.
   298 */
   299 	{
   300 	Cancel();
   301 	}
   302 
   303 
   304 
   305 
   306 EXPORT_C void CIdle::Start(TCallBack aCallBack)
   307 /**
   308 Starts the background task.
   309 
   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
   312 to run.
   313 
   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
   317 handled.
   318 
   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.
   321 
   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.
   324 
   325 @param aCallBack A callback object encapsulating a function which is called
   326                  when no higher priority active object is ready to run.
   327 */
   328 	{
   329 	iCallBack=aCallBack;
   330 	iStatus=KRequestPending;
   331 	TRequestStatus *pS=(&iStatus);
   332 	User::RequestComplete(pS,0);
   333 	SetActive();
   334 	}
   335 
   336 
   337 
   338 
   339 EXPORT_C void CIdle::RunL()
   340 /**
   341 Handles this idle active object's request completion event.
   342 
   343 It is called when nothing of a higher priority can be scheduled.
   344 
   345 @see CActive::RunL
   346 */
   347 	{
   348 	if (iCallBack.CallBack())
   349 		Start(iCallBack);
   350 	}
   351 
   352 
   353 
   354 
   355 EXPORT_C void CIdle::DoCancel()
   356 /**
   357 Implements the cancellation of an outstanding request.
   358 
   359 This function is called by the active object's Cancel() function.
   360 
   361 @see CActive::DoCancel
   362 */
   363 	{
   364 	}
   365 
   366 
   367 
   368 
   369 EXPORT_C void CAsyncOneShot::Call()
   370 /**
   371 Queues this active object to be run once.
   372 
   373 @panic E32USER-CBase 2 In debug builds only, if this active object has not
   374        already been added to the active scheduler.
   375 */
   376 	{
   377 	__ASSERT_DEBUG(IsAdded(),Panic(ECAsyncOneShotNotAdded));
   378 	TRequestStatus *pS=(&iStatus);
   379 	iStatus = KRequestPending;
   380 	SetActive();
   381 	iThread.RequestComplete(pS,0);
   382 	}
   383 
   384 
   385 
   386 
   387 EXPORT_C void CAsyncOneShot::DoCancel()
   388 /**
   389 Implements cancellation of an outstanding request.
   390 
   391 The class provides an empty implementation.
   392 
   393 This is called by the destructor.
   394 */
   395 	{
   396 	// Empty
   397 	}
   398 
   399 
   400 
   401 
   402 EXPORT_C CAsyncOneShot::CAsyncOneShot(TInt aPriority)
   403 	:CActive(aPriority)
   404 /**
   405 Constructor taking a priority value.
   406 
   407 Specifically, the constructor:
   408 
   409 1. sets this active object's priority value
   410 
   411 2. opens a handle to the current thread to ensure that the thread cannot be
   412    closed until this CAsyncOneShot object is destroyed
   413 
   414 3. adds this active object to the current active scheduler.
   415 
   416 @param aPriority The active object priority value. CActive::TPriority defines
   417                  a standard set of priorities.
   418 
   419 @panic E32USER-CBase 93 if the attempt to open a handle to the current thread
   420        fails.
   421 */
   422 	{
   423 	Setup();
   424 	}
   425 
   426 
   427 
   428 
   429 void CAsyncOneShot::Setup()
   430 //
   431 // ensures that we are added to the Scheduler.
   432 //
   433 	{
   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));
   439 
   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);
   445 	}
   446 
   447 
   448 
   449 
   450 EXPORT_C CAsyncOneShot::~CAsyncOneShot()
   451 /**
   452 Frees resources prior to destruction.
   453 
   454 Specifically, it closes the handle to the current thread.
   455 
   456 @see CActive::~CActive
   457 */
   458 	{
   459 	Cancel();
   460 	iThread.Close();
   461 	}
   462 
   463 
   464 
   465 
   466 EXPORT_C CAsyncCallBack::CAsyncCallBack(TInt aPriority)
   467 	: CAsyncOneShot(aPriority), iCallBack(NULL)
   468 /**
   469 Constructor taking a priority value.
   470 
   471 Specifically, the constructor sets this active object's priority value through
   472 a call to the base class constructor in its ctor list.
   473 
   474 No call back is set, which means that it must be set subsequently through
   475 a call to the Set() function.
   476 
   477 @param aPriority The active object priority value. CActive::TPriority defines
   478                  a standard set of priorities.
   479 
   480 @see CAsyncCallBack::Set
   481 */
   482 	{
   483 	}
   484 
   485 
   486 
   487 
   488 EXPORT_C CAsyncCallBack::CAsyncCallBack(const TCallBack& aCallBack, TInt aPriority)
   489 	: CAsyncOneShot(aPriority), iCallBack(aCallBack)
   490 /**
   491 Constructor taking a priority value and a callback.
   492 
   493 Specifically, the constructor:
   494 
   495 1. sets this active object's priority value through a call to the base class
   496    constructor in its ctor list
   497 
   498 2. sets the callback; the function encapsulated by the callback is called when
   499    this active object is scheduled to run.
   500 
   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.
   506 */
   507 	{
   508 	}
   509 
   510 
   511 
   512 
   513 EXPORT_C CAsyncCallBack::~CAsyncCallBack()
   514 /**
   515 Destructor.
   516 */
   517 	{
   518 	}
   519 
   520 
   521 
   522 
   523 EXPORT_C void CAsyncCallBack::CallBack()
   524 /**
   525 Queues this active object to be run, if it is not already queued.
   526 */
   527 	{
   528 	if (!IsActive())
   529 		Call();
   530 	}
   531 
   532 
   533 
   534 
   535 EXPORT_C void CAsyncCallBack::Set(const TCallBack& aCallBack)
   536 /**
   537 Sets the call back.
   538 
   539 @param aCallBack A reference to a callback object encapsulating a function
   540                  which is called when this active object is ready to run.
   541 
   542 @panic E32USER-CBase 1 if the active object is currently active.
   543 */
   544 	{
   545 	__ASSERT_ALWAYS(!IsActive(), Panic(ECAsyncCBIsActive));
   546 	iCallBack = aCallBack;
   547 	}
   548 
   549 
   550 
   551 
   552 void CAsyncCallBack::RunL()
   553 /**
   554 Calls the callback function.
   555 
   556 @see TCallBack::CallBack
   557 */
   558 	{
   559 	iCallBack.CallBack();
   560 	}
   561 
   562 
   563 
   564 
   565 struct CActiveScheduler::TLoop
   566 	{
   567 	TLoop* iNext;
   568 	CActiveScheduler::TLoopOwner* iOwner;
   569 	TCallBack iCallback;
   570 	TInt iExitCode;
   571 	};
   572 
   573 CActiveScheduler::TLoopOwner* const KLoopNoOwner=reinterpret_cast<CActiveScheduler::TLoopOwner*>(1);
   574 CActiveScheduler::TLoopOwner* const KLoopInactive=0;
   575 
   576 
   577 
   578 
   579 EXPORT_C CActiveSchedulerWait::CActiveSchedulerWait()
   580 /**
   581 Default constructor.
   582 */
   583 	{}
   584 
   585 
   586 
   587 
   588 
   589 EXPORT_C CActiveSchedulerWait::~CActiveSchedulerWait()
   590 /**
   591 Ensures that the attached scheduler loop, and all nested loops, are stopped
   592 prior to destruction.
   593 
   594 @see AsyncStop()
   595 */
   596 	{
   597 	if (IsStarted())
   598 		AsyncStop();
   599 	}
   600 
   601 
   602 
   603 
   604 EXPORT_C void CActiveSchedulerWait::Start()
   605 /**
   606 Starts a new wait loop under the control of the current active scheduler.
   607 
   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.
   612 
   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.
   617 
   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.
   620 
   621 @see CActiveSchedulerWait::AsyncStop
   622 @see CActiveSchedulerWait::IsStarted
   623 @see CActiveScheduler::Start
   624 @see CActiveScheduler::Halt
   625 */
   626 	{
   627 	__ASSERT_ALWAYS(!IsStarted(), Panic(EActiveSchedulerWaitAlreadyStarted));		// can only start a CActiveSchedulerWait if it isn't already started
   628 	CActiveScheduler::Start(&iLoop);
   629 	}
   630 
   631 
   632 
   633 
   634 EXPORT_C void CActiveSchedulerWait::AsyncStop()
   635 /**
   636 Stops the scheduling loop owned by this object.
   637 
   638 Note that the corresponding call to Start() only returns once all nested
   639 scheduler loops have stopped.
   640 
   641 @panic E32USER-CBase 92 if the wait object has not been started.
   642 */
   643 	{
   644 	AsyncStop(TCallBack());
   645 	}
   646 
   647 
   648 
   649 
   650 EXPORT_C void CActiveSchedulerWait::AsyncStop(const TCallBack& aCallMeWhenStopped)
   651 /**
   652 Stops the scheduling loop owned by this object, specifying a callback.
   653 
   654 This version of AsyncStop() provides a callback which is invoked immediately
   655 after the scheduler loop actually stops before the corresponding call
   656 to Start() returns.
   657 
   658 Note that the corresponding call to Start() only returns once all nested
   659 scheduler loops have stopped.
   660 
   661 @param aCallMeWhenStopped The callback to invoke when the scheduler loop exits.
   662 
   663 @panic E32USER-CBase 92 if the wait object has not been started.
   664  */
   665 	{
   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());
   669 
   670 	loop->iCallback = aCallMeWhenStopped;
   671 	loop->iOwner = KLoopInactive;			// disconnect from owner
   672 	iLoop = 0;
   673 	}
   674 
   675 
   676 
   677 
   678 EXPORT_C TBool CActiveSchedulerWait::CanStopNow() const
   679 /**
   680 Reports whether stopping will have immediate effect.
   681 
   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.
   686 
   687 @return Boolean indicating if the scheduling loop would stop immediately.
   688 
   689 @panic E32USER-CBase 92 if the wait object has not been started.
   690 
   691 @see CActiveSchedulerWait::Start
   692 @see CActiveSchedulerWait::AsyncStop
   693 */
   694  	{
   695 	__ASSERT_ALWAYS(IsStarted(), Panic(EActiveSchedulerWaitNotStarted));		// Scheduler must be running
   696 	for (CActiveScheduler::TLoop* loop=GetActiveScheduler()->iStack; loop; loop=loop->iNext)
   697 		{
   698 		if (loop==iLoop)
   699 			return ETrue;
   700 		if (loop->iOwner != KLoopInactive)
   701 			break;
   702 		}
   703 	return EFalse;
   704 	}
   705 
   706 
   707 
   708 EXPORT_C CActiveScheduler::CActiveScheduler()
   709 	: iActiveQ(_FOFF(CActive,iLink))
   710 /**
   711 Constructs an active scheduler.
   712 
   713 After construction, the scheduler should be installed.
   714 
   715 @see CActiveScheduler::Install
   716 */
   717 	{}
   718 
   719 
   720 
   721 
   722 EXPORT_C CActiveScheduler::~CActiveScheduler()
   723 /**
   724 Frees resources prior to destruction.
   725 
   726 Specifically, it removes all active objects from the active scheduler's list
   727 of active objects.
   728 
   729 An active scheduler should only be destroyed when the top-level call to Start()
   730 has returned.
   731 
   732 @see CActiveScheduler::Start
   733 @see CActiveScheduler::Stop
   734 */
   735 	{
   736 	while (!iActiveQ.IsEmpty())
   737 		iActiveQ.First()->Deque();
   738 	if (GetActiveScheduler()==this)
   739 		SetActiveScheduler(NULL);
   740 	}
   741 
   742 
   743 
   744 
   745 EXPORT_C void CActiveScheduler::Install(CActiveScheduler *aManager)
   746 /**
   747 Installs the specified active scheduler as the current active scheduler.
   748 
   749 The installed active scheduler now handles events for this thread.
   750 
   751 The current active scheduler can be uninstalled by passing a NULL pointer.
   752 
   753 @param aManager A pointer to the active scheduler to be installed.
   754                 If this is NULL, the current active scheduler is uninstalled.
   755 
   756 @panic E32USER-CBase 43 if If there is already an installed active scheduler.
   757 */
   758 	{
   759 	if (aManager!=NULL)
   760 		__ASSERT_ALWAYS(GetActiveScheduler()==NULL,Panic(EReqManagerAlreadyExists));
   761 	SetActiveScheduler(aManager);
   762 	}
   763 
   764 
   765 
   766 
   767 EXPORT_C void CActiveScheduler::Add(CActive *aRequest)
   768 /**
   769 Adds the specified active object to the current active scheduler.
   770 
   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.
   773 
   774 @param aRequest Pointer to the active object to be added.
   775 
   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
   780        active scheduler.
   781 
   782 @see CActive::Deque
   783 */
   784 	{
   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);
   790 	}
   791 
   792 
   793 
   794 
   795 EXPORT_C void CActiveScheduler::WaitForAnyRequest()
   796 /**
   797 Wait for an asynchronous request to complete.
   798 
   799 The default implementation just calls User::WaitForAnyRequest().
   800 
   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().
   804 
   805 @see User::WaitForAnyRequest
   806 */
   807 	{
   808 	User::WaitForAnyRequest();
   809 	}
   810 
   811 
   812 
   813 
   814 EXPORT_C void CActiveScheduler::Start()
   815 /**
   816 Starts a new wait loop under the control of the current active scheduler.
   817 
   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.
   822 
   823 While Start() is executing, user code runs only:
   824 
   825 1. in the RunL() function of active objects known to the current active scheduler
   826 
   827 2. in the RunError() function of an active object that leaves from its RunL()
   828 
   829 3. in the current active scheduler’s Error() function, if an active object’s
   830    RunError() returns an error code.
   831 
   832 Start() returns only when a corresponding Stop() or Halt() is issued.
   833 
   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
   836 used instead.
   837 
   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.)
   841 
   842 @panic E32USER-CBase 44 if the thread does not have an active
   843        scheduler installed.
   844 
   845 @see CActiveScheduler::Stop
   846 @see CActiveScheduler::Halt
   847 @see CActive::RunL
   848 @see CActive::RunError
   849 @see CActiveScheduler::Error
   850 @see CActiveSchedulerWait
   851 */
   852 	{
   853 	Start(KLoopNoOwner);
   854 	}
   855 
   856 
   857 
   858 
   859 void CActiveScheduler::Start(TLoopOwner* aOwner)
   860 /**
   861 @internalComponent
   862 
   863 Start a new nesting level
   864 */
   865 	{
   866 	CActiveScheduler* pS=GetActiveScheduler();
   867 	__ASSERT_ALWAYS(pS!=NULL, Panic(EReqManagerDoesNotExist));
   868 
   869 	// Instantiate the local loop control
   870 	TLoop loop;
   871 	loop.iOwner=aOwner;
   872 	if (aOwner != KLoopNoOwner)
   873 		*aOwner=&loop;
   874 	loop.iNext=pS->iStack;
   875 	pS->iStack=&loop;
   876 	loop.iExitCode=0;
   877 
   878 	// Run the scheduler loop
   879 #if 1
   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));
   885 	if (r!=KErrNone)
   886 		{
   887 		loop.iExitCode = r;
   888 		TLoopOwner* owner=loop.iOwner;
   889 		if (TUint(owner) > TUint(KLoopNoOwner))
   890 			*owner = NULL;
   891 		}
   892 #else	// fixme
   893 #ifdef _DEBUG
   894 	// catch old-style bad behaviour - leaving from Error()
   895 	TRAPD(r,pS->Run(loop.iOwner));
   896 	__ASSERT_DEBUG(r==KErrNone,User::Invariant());
   897 #else
   898 	pS->Run(loop.iOwner);
   899 #endif
   900 #endif
   901 
   902 	pS->iStack=loop.iNext;
   903 	loop.iCallback.CallBack();
   904 	// propagate the exit-code via a leave (yuck, but blame BAFL & co.)
   905 	if (loop.iExitCode)
   906 		User::Leave(loop.iExitCode);
   907 	}
   908 
   909 /*
   910 @internalComponent
   911 
   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.
   914  */
   915 void DummyFunc(TAny* /*aPtr*/)
   916 	{}
   917 
   918 
   919 #ifdef __LEAVE_EQUALS_THROW__
   920 /**
   921 @internalComponent
   922 
   923 Start dispatching request completions.
   924 
   925 Stop when aLoop becomes 'Inactive'
   926 
   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.
   932 */
   933 void CActiveScheduler::Run(TLoopOwner* const volatile& aLoop)
   934 	{
   935 	CActive * volatile curr_obj = 0;
   936 	TBool leaveException = EFalse;
   937 	TInt exceptionReason = 0;
   938 	do
   939 		{
   940 		try	{
   941 			__WIN32SEHTRAP
   942 			TTrapHandler* t = User::MarkCleanupStack();
   943 			
   944 #ifdef _DEBUG
   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;
   949 
   950 			if(pH!=NULL) // test whether there's a CleanupTrapHandler installed
   951 				{
   952 				CCleanup& ccleanup =pH->Cleanup();
   953 				//Store pointer as need the scope of ccleanup increased
   954 				cleanupPtr = &ccleanup; 
   955 				cleanupBundle.iCleanupPtr = cleanupPtr;
   956 				
   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)));
   960 				
   961 				DoRunL(aLoop, curr_obj, &cleanupBundle);
   962 
   963 				//Dummy Int must (will) be at the top
   964 				//Cleanup our stack
   965 				cleanupPtr->Pop(1);
   966 				} 
   967 			else // no cleanup stack installed
   968 				{
   969 				DoRunL(aLoop, curr_obj, NULL);
   970 				}
   971 			
   972 #else
   973 			DoRunL(aLoop, curr_obj, NULL);
   974 #endif
   975 			
   976 			User::UnMarkCleanupStack(t);
   977 			__WIN32SEHUNTRAP
   978 			return;
   979 			}
   980 		catch (XLeaveException& l)
   981 			{
   982 			Exec::LeaveEnd();
   983 			leaveException = ETrue;
   984 			exceptionReason = l.Reason();
   985 			}
   986 		catch (...)
   987 			{
   988 			User::Invariant();
   989 			}
   990 
   991 		if (leaveException)
   992 			{
   993 			if (exceptionReason != KErrNone)
   994 				{
   995 				TInt r = curr_obj->RunError(exceptionReason);
   996 				if (r != KErrNone)
   997 					Error(r);
   998 				}
   999 			leaveException = EFalse;
  1000 			}
  1001 
  1002 		} while (aLoop != KLoopInactive);
  1003 	}
  1004 
  1005 #else
  1006 
  1007 /**
  1008 @internalComponent
  1009 
  1010 Start dispatching request completions.
  1011 
  1012 Stop when aLoop becomes 'Inactive'
  1013 
  1014 This version uses the original implementation of TRAP/Leave.
  1015 */
  1016 void CActiveScheduler::Run(TLoopOwner* const volatile& aLoop)
  1017 	{
  1018 	CActive * volatile curr_obj = 0;
  1019 	do
  1020 		{
  1021 		// explicitly expand the TRAPD macro here to enable single-step debugging
  1022 		// of the scheduler loop
  1023 		TInt r;
  1024 		TTrap trap;
  1025 		if (trap.Trap(r)==0)
  1026 			{
  1027 #ifdef _DEBUG
  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;
  1032 
  1033 			if(pH!=NULL) // test whether there's a CleanupTrapHandler installed
  1034 				{
  1035 				CCleanup& ccleanup =pH->Cleanup();
  1036 				//Store pointer as need the scope of ccleanup increased
  1037 				cleanupPtr = &ccleanup; 
  1038 				cleanupBundle.iCleanupPtr = cleanupPtr;
  1039 				
  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)));
  1043 				
  1044 				DoRunL(aLoop, curr_obj, &cleanupBundle);
  1045 
  1046 				//Dummy Int must (will) be at the top
  1047 				//Cleanup our stack
  1048 				cleanupPtr->Pop(1);
  1049 				} 
  1050 			else // no cleanup stack installed
  1051 				{
  1052 				DoRunL(aLoop, curr_obj, NULL);
  1053 				}
  1054 #else
  1055 			DoRunL(aLoop, curr_obj, NULL);
  1056 #endif
  1057 			
  1058 			TTrap::UnTrap();
  1059 			return;		// exit level
  1060 			}
  1061 		if (r != KErrNone)
  1062 			{
  1063 			r = curr_obj->RunError(r);
  1064 			if (r != KErrNone)
  1065 				Error(r);
  1066 			}
  1067 		} while (aLoop != KLoopInactive);
  1068 	}
  1069 #endif
  1070 
  1071 #ifndef __CACTIVESCHEDULER_MACHINE_CODED__
  1072 /**
  1073 @internalComponent
  1074 
  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.
  1078 
  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.
  1081 */
  1082 #ifdef _DEBUG
  1083 void CActiveScheduler::DoRunL(TLoopOwner* const volatile& aLoop, CActive* volatile & aCurrentObj, TCleanupBundle* aCleanupBundlePtr)
  1084 #else
  1085 void CActiveScheduler::DoRunL(TLoopOwner* const volatile& aLoop, CActive* volatile & aCurrentObj, TCleanupBundle* /*aCleanupBundlePtr*/)
  1086 #endif
  1087 	{
  1088 	TDblQueIter<CActive> q(iActiveQ);
  1089 	do
  1090 		{
  1091 		WaitForAnyRequest();
  1092 		q.SetToFirst();
  1093 		CActive* pR;
  1094 		do
  1095 			{
  1096 			pR=q++;
  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);
  1103 #ifdef __SMP__
  1104 		__e32_memory_barrier();
  1105 #endif
  1106 		pR->iStatus.iFlags&=~(TRequestStatus::EActive | TRequestStatus::ERequestPending); //pR->iActive=EFalse;
  1107 		aCurrentObj = pR;
  1108 		pR->RunL();
  1109 
  1110 #ifdef _DEBUG
  1111 		if(aCleanupBundlePtr!=NULL)
  1112 			{
  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);
  1117 			}
  1118 #endif
  1119 
  1120 		} while (aLoop != KLoopInactive);
  1121 	return;		// exit level
  1122 	}
  1123 
  1124 #else
  1125 
  1126 extern "C" void PanicStrayEvent()
  1127 	{
  1128 	Panic(EReqStrayEvent);
  1129 	}
  1130 #endif
  1131 
  1132 
  1133 
  1134 
  1135 EXPORT_C void CActiveScheduler::Stop()
  1136 /**
  1137 Stops the wait loop started by the most recent call to Start().
  1138 
  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.
  1142 
  1143 It will not stop a wait loop started by a call
  1144 to CActiveSchedulerWait::Start().
  1145 
  1146 Stop() may also be called from Error().
  1147 
  1148 Note that stopping a nested wait loop is deprecated using this functionality,
  1149 use a CActiveSchedulerWait object instead.
  1150 
  1151 @see CActiveSchedulerWait::Start
  1152 @see CActive::RunL
  1153 @see CActiveSchedulerWait::Error
  1154 @see CActiveSchedulerWait::AsyncStop
  1155 */
  1156 	{
  1157 	CActiveScheduler *pS=GetActiveScheduler();
  1158 	__ASSERT_ALWAYS(pS!=NULL,Panic(EReqManagerDoesNotExist));
  1159 
  1160 	for (CActiveScheduler::TLoop* loop=pS->iStack; loop; loop=loop->iNext)
  1161 		{
  1162 		if (loop->iOwner == KLoopNoOwner)
  1163 			{
  1164 			loop->iOwner=KLoopInactive;
  1165 			return;
  1166 			}
  1167 		}
  1168 	Panic(EReqTooManyStops);
  1169 	}
  1170 
  1171 
  1172 
  1173 
  1174 EXPORT_C void CActiveScheduler::Halt(TInt aExitCode) const
  1175 /**
  1176 Unilaterally terminates the current scheduler loop.
  1177 
  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.
  1182 
  1183 @param aExitCode If non-zero, the reason code reported by Start().
  1184 */
  1185 	{
  1186 	CActiveScheduler::TLoop* loop=iStack;
  1187 	__ASSERT_ALWAYS(loop!=NULL,Panic(EReqTooManyStops));
  1188 	TLoopOwner* owner=loop->iOwner;
  1189 	if (TUint(owner) > TUint(KLoopNoOwner))
  1190 		*owner = NULL;
  1191 	loop->iOwner = KLoopInactive;			// disconnect from owner
  1192 	loop->iExitCode = aExitCode;
  1193 	}
  1194 
  1195 
  1196 
  1197 
  1198 EXPORT_C TInt CActiveScheduler::StackDepth() const
  1199 /**
  1200 Gets the current number of nested wait loops.
  1201 
  1202 @return The number of nested calls to Start().
  1203 */
  1204 	{
  1205 	TInt depth=0;
  1206 	for (CActiveScheduler::TLoop* loop=iStack; loop; loop=loop->iNext)
  1207 		++depth;
  1208 	return depth;
  1209 	}
  1210 
  1211 
  1212 
  1213 
  1214 EXPORT_C CActiveScheduler* CActiveScheduler::Current()
  1215 /**
  1216 Gets a pointer to the currently installed active scheduler.
  1217 
  1218 @return A pointer to the active scheduler which is currently installed.
  1219 */
  1220 	{
  1221 	return GetActiveScheduler();
  1222 	}
  1223 
  1224 
  1225 
  1226 
  1227 EXPORT_C void CActiveScheduler::Error(TInt /*aError*/) const
  1228 /**
  1229 Handles the result of a leave occurring in an active object’s RunL()
  1230 function.
  1231 
  1232 An active scheduler always invokes an active object’s RunL()
  1233 function under a trap harness.
  1234 
  1235 The default implementation must be replaced.
  1236 
  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.
  1241 
  1242 @param aError The leave code propagated from the active object’s RunL() function
  1243 
  1244 @panic E32USER-CBase 47 if the default implementation is invoked.
  1245 
  1246 @see CActive::RunL
  1247 @see CActiveScheduler::Stop
  1248 @see CActiveScheduler::Halt
  1249 */
  1250 	{
  1251 	Panic(EReqActiveObjectLeave);
  1252 	}
  1253 
  1254 
  1255 
  1256 
  1257 EXPORT_C TBool CActiveScheduler::RunIfReady(TInt& aError, TInt aMinimumPriority)
  1258 /**
  1259 @deprecated
  1260 
  1261 Causes the RunL() function of at most one pending active object of priority
  1262 aMinimumPriority or greater to be run.
  1263 
  1264 @param aError Error returned by called active object.
  1265 @param aMinimumPriority Minimum priority of active object to run.
  1266 
  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.
  1269 */
  1270 	{
  1271 	aError=KErrNone;
  1272 	CActiveScheduler* pS=GetActiveScheduler();
  1273 	if (pS!=NULL)
  1274 		{
  1275 		TDblQueIter<CActive> iterator(pS->iActiveQ);
  1276 		for (CActive* active=iterator++; (active!=NULL) && (active->Priority()>=aMinimumPriority); active=iterator++)
  1277 			{
  1278 			if (active->IsActive() && (active->iStatus!=KRequestPending))
  1279 				{
  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);
  1284 				return ETrue;
  1285 				}
  1286 			}
  1287 		}
  1288 	return EFalse;
  1289 	}
  1290 
  1291 
  1292 
  1293 
  1294 EXPORT_C CActiveScheduler* CActiveScheduler::Replace(CActiveScheduler* aNewActiveScheduler)
  1295 /**
  1296 Allows the current active scheduler to be replaced, while retaining its active
  1297 objects.
  1298 
  1299 @param aNewActiveScheduler The new active scheduler.
  1300 
  1301 @return Previous active scheduler.
  1302 */
  1303 	{
  1304 	__ASSERT_ALWAYS(aNewActiveScheduler!=NULL, Panic(EReqManagerDoesNotExist));
  1305 	CActiveScheduler* oldActiveScheduler=GetActiveScheduler();
  1306 	__ASSERT_ALWAYS(aNewActiveScheduler!=oldActiveScheduler, Panic(EActiveSchedulerReplacingSelf));
  1307 	if (oldActiveScheduler!=NULL)
  1308 		{
  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())
  1313 			{
  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);
  1319 			}
  1320 		}
  1321 	SetActiveScheduler(aNewActiveScheduler);
  1322 	return oldActiveScheduler;
  1323 	}
  1324 
  1325 
  1326 
  1327 
  1328 EXPORT_C void CActiveScheduler::OnStarting()
  1329 /**
  1330 @removed
  1331 
  1332 Dummy EXPORT for Binary Compatibility reasons.
  1333 This method is never called.
  1334 */
  1335 	{
  1336 	}
  1337 
  1338 
  1339 
  1340 
  1341 EXPORT_C void CActiveScheduler::OnStopping()
  1342 /**
  1343 @removed
  1344 
  1345 Dummy EXPORT for Binary Compatibility reasons.
  1346 This method is never called.
  1347 */
  1348 	{
  1349 	}
  1350 
  1351 
  1352 
  1353 EXPORT_C void CActiveScheduler::Reserved_1()
  1354 /**
  1355 @internalComponent
  1356 
  1357 Dummy EXPORT for Binary Compatibility reasons.
  1358 */
  1359 	{
  1360 	}
  1361 
  1362 
  1363 
  1364 EXPORT_C void CActiveScheduler::Reserved_2()
  1365 /**
  1366 @internalComponent
  1367 
  1368 Dummy EXPORT for Binary Compatibility reasons.
  1369 */
  1370 	{
  1371 	}
  1372 
  1373 
  1374 /**
  1375 Extension function
  1376 
  1377 
  1378 */
  1379 EXPORT_C TInt CActiveScheduler::Extension_(TUint aExtensionId, TAny*& a0, TAny* a1)
  1380 	{
  1381 	return CBase::Extension_(aExtensionId, a0, a1);
  1382 	}