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