os/graphics/graphicscomposition/surfaceupdate/src/surfaceupdateserver.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
// Copyright (c) 2006-2010 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 "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
//
sl@0
    15
sl@0
    16
#include "surfaceupdateserver.h"
sl@0
    17
sl@0
    18
#include <graphics/compositionsurfaceupdate.h>
sl@0
    19
#include <graphics/extensioncontainer.h>
sl@0
    20
sl@0
    21
#include "surfaceupdate.h"
sl@0
    22
#include "suerror.h"
sl@0
    23
#ifdef TEST_SURFACE_UPDATE
sl@0
    24
#include "surfaceupdatetest.h"
sl@0
    25
#endif
sl@0
    26
sl@0
    27
sl@0
    28
const TUint KDefaultHeapSize=0x10000;
sl@0
    29
sl@0
    30
void *gProvider = NULL;
sl@0
    31
RFastLock gProviderFastLock;
sl@0
    32
sl@0
    33
/**
sl@0
    34
The server maintains session with the clients. 
sl@0
    35
It starts during the initialization of the Content update receiver thread.  
sl@0
    36
*/
sl@0
    37
CSurfaceUpdateServer* CSurfaceUpdateServer::NewL()
sl@0
    38
	{
sl@0
    39
	CSurfaceUpdateServer* server = new (ELeave) CSurfaceUpdateServer(EPriorityStandard);
sl@0
    40
	CleanupStack::PushL(server);
sl@0
    41
	server->ConstructL();
sl@0
    42
	CleanupStack::Pop();
sl@0
    43
	return server;	
sl@0
    44
	}
sl@0
    45
	
sl@0
    46
CSurfaceUpdateServer::CSurfaceUpdateServer(CActive::TPriority aPriority) :
sl@0
    47
	CServer2(aPriority)
sl@0
    48
	{
sl@0
    49
	}
sl@0
    50
	
sl@0
    51
CSurfaceUpdateServer::~CSurfaceUpdateServer()
sl@0
    52
	{
sl@0
    53
	iUpdateReceiver.Close();
sl@0
    54
	iUpdateReceiverPriorityOrder.ResetAndDestroy();
sl@0
    55
	delete iServerProvider;
sl@0
    56
	}	
sl@0
    57
	
sl@0
    58
void CSurfaceUpdateServer::ConstructL()
sl@0
    59
	{
sl@0
    60
	iServerProvider = CSurfaceUpdateServerProvider::NewL(EPriorityStandard, this);
sl@0
    61
	}
sl@0
    62
	
sl@0
    63
/**
sl@0
    64
Assign Content update receiver instance to particular screen. 
sl@0
    65
The following calls of this function will override the previous. 
sl@0
    66
sl@0
    67
@see MSurfaceUpdateServerProvider::Register
sl@0
    68
*/	
sl@0
    69
TInt CSurfaceUpdateServer::Register(TInt aScreen, CBase* aUpdateReceiver, TInt aPriority)
sl@0
    70
	{
sl@0
    71
	if(aScreen < 0)
sl@0
    72
		{
sl@0
    73
		return KErrArgument;
sl@0
    74
		}
sl@0
    75
		
sl@0
    76
	TInt err = KErrNone;
sl@0
    77
	while((iUpdateReceiver.Count() <= aScreen) && (err == KErrNone))
sl@0
    78
		{
sl@0
    79
		err = iUpdateReceiver.Append(NULL);
sl@0
    80
		}
sl@0
    81
	
sl@0
    82
	if(err == KErrNone)
sl@0
    83
		{
sl@0
    84
		TUpdateReceiverPriorityEntry *receiverPriorityEntry = NULL; 
sl@0
    85
		if(!aUpdateReceiver)
sl@0
    86
			{//Client wants to unregister the Content update receiver which has been associated with the given screen number.
sl@0
    87
			MCompositionSurfaceUpdate* receiver = iUpdateReceiver[aScreen];
sl@0
    88
			if(receiver)
sl@0
    89
				{
sl@0
    90
				TInt num = iUpdateReceiverPriorityOrder.Count() - 1;
sl@0
    91
				for(;;)
sl@0
    92
					{//Content update receiver must be in priority list, therefore we don't need to check num >= 0
sl@0
    93
					receiverPriorityEntry = iUpdateReceiverPriorityOrder[num];
sl@0
    94
					if(receiverPriorityEntry->iUpdateReceiver == receiver)
sl@0
    95
						{//remove the Content update receiver from the priority list
sl@0
    96
						iUpdateReceiverPriorityOrder.Remove(num);
sl@0
    97
						delete receiverPriorityEntry;
sl@0
    98
						break;
sl@0
    99
						}
sl@0
   100
					num--;
sl@0
   101
					}
sl@0
   102
				iUpdateReceiver[aScreen] = NULL; //unregister the Content update receiver by setting the entry to NULL
sl@0
   103
				}
sl@0
   104
			}
sl@0
   105
		else
sl@0
   106
			{
sl@0
   107
	        CExtensionContainer* extCont=static_cast<CExtensionContainer*>(aUpdateReceiver);
sl@0
   108
	        MCompositionSurfaceUpdate* updateReceiver=extCont->GetInterface<MCompositionSurfaceUpdate>();
sl@0
   109
	        if (updateReceiver)
sl@0
   110
	            {
sl@0
   111
                receiverPriorityEntry = new TUpdateReceiverPriorityEntry;
sl@0
   112
                if(!receiverPriorityEntry)
sl@0
   113
                    return KErrNoMemory;
sl@0
   114
                receiverPriorityEntry->iPriority = aPriority;
sl@0
   115
                receiverPriorityEntry->iUpdateReceiver = updateReceiver;
sl@0
   116
        
sl@0
   117
                err = iUpdateReceiverPriorityOrder.InsertInOrder(receiverPriorityEntry, CSurfaceUpdateServer::CompareUpdateReceiverPriority);
sl@0
   118
                if(err == KErrNone)
sl@0
   119
                    {
sl@0
   120
                    iUpdateReceiver[aScreen] = updateReceiver;
sl@0
   121
                    }
sl@0
   122
                else
sl@0
   123
                    {
sl@0
   124
                    delete receiverPriorityEntry;
sl@0
   125
                    }
sl@0
   126
	            }
sl@0
   127
	        else
sl@0
   128
	            {
sl@0
   129
	            err=KErrArgument;
sl@0
   130
	            }
sl@0
   131
			}	
sl@0
   132
		}
sl@0
   133
	return err;
sl@0
   134
	}
sl@0
   135
sl@0
   136
/**
sl@0
   137
Create a new session with a server. Derived from CSession2.
sl@0
   138
sl@0
   139
@param aVersion required version of the server
sl@0
   140
@param aMessage message from the client.
sl@0
   141
@return New instance of the CSurfaceUpdateSession.
sl@0
   142
*/
sl@0
   143
CSession2* CSurfaceUpdateServer::NewSessionL(const TVersion& aVersion, const RMessage2& /*aMessage*/) const
sl@0
   144
	{
sl@0
   145
      // Check that the version is OK
sl@0
   146
	TVersion v(KSurfaceUpdateServMajorVersionNumber,KSurfaceUpdateServMinorVersionNumber,KSurfaceUpdateServBuildVersionNumber);
sl@0
   147
	if (!User::QueryVersionSupported(v,aVersion))
sl@0
   148
		User::Leave(KErrNotSupported);	
sl@0
   149
	
sl@0
   150
	// Security is not an issue, any client can have connection to the server	
sl@0
   151
	// Create the session.
sl@0
   152
	return new (ELeave) CSurfaceUpdateSession(UpdateReceiverPriority());
sl@0
   153
	}
sl@0
   154
sl@0
   155
/**
sl@0
   156
Utility function to panic the server
sl@0
   157
sl@0
   158
@param aPanic Panic code
sl@0
   159
*/
sl@0
   160
void CSurfaceUpdateServer::PanicServer(TSurfaceUpdateServPanic aPanic)
sl@0
   161
	{
sl@0
   162
	_LIT(KTxtServerPanic,"Surface Update Server panic");
sl@0
   163
	User::Panic(KTxtServerPanic, aPanic);
sl@0
   164
	}
sl@0
   165
sl@0
   166
/**
sl@0
   167
Provide composition receiver.
sl@0
   168
sl@0
   169
@param aScreen targeted screen
sl@0
   170
@return Composition receiver object, associated to particular screen
sl@0
   171
*/
sl@0
   172
MCompositionSurfaceUpdate* CSurfaceUpdateServer::UpdateReceiver(TInt aScreen) const
sl@0
   173
	{
sl@0
   174
	if(aScreen >= iUpdateReceiver.Count())//negative value won't reach this point 
sl@0
   175
		return NULL;
sl@0
   176
	return iUpdateReceiver[aScreen];	
sl@0
   177
	}
sl@0
   178
sl@0
   179
TInt CSurfaceUpdateServer::ThreadFunction(TAny* aAny)
sl@0
   180
	{
sl@0
   181
	  // get clean-up stack
sl@0
   182
	CTrapCleanup* cleanup=CTrapCleanup::New();
sl@0
   183
	__ASSERT_ALWAYS(cleanup!=NULL, CSurfaceUpdateServer::PanicServer(EUpdateServPanicNoMemory));
sl@0
   184
	
sl@0
   185
	  // create an active scheduler and server
sl@0
   186
	CActiveScheduler *pA = new CActiveScheduler;
sl@0
   187
	__ASSERT_ALWAYS(pA != NULL, CSurfaceUpdateServer::PanicServer(EUpdateServPanicNoMemory));
sl@0
   188
sl@0
   189
	  //Install the active scheduler
sl@0
   190
	CActiveScheduler::Install(pA);
sl@0
   191
sl@0
   192
	CSurfaceUpdateServer *pS = NULL;
sl@0
   193
	TRAPD(err, pS = CSurfaceUpdateServer::NewL());
sl@0
   194
	__ASSERT_ALWAYS(err == KErrNone, CSurfaceUpdateServer::PanicServer(EUpdateServPanicNoMemory));
sl@0
   195
	
sl@0
   196
	  // Start the server
sl@0
   197
#ifndef TEST_SURFACE_UPDATE
sl@0
   198
	err = pS->Start(KSurfaceUpdateServerName);
sl@0
   199
#else
sl@0
   200
	err = pS->Start(KTestSurfaceUpdateServerName);
sl@0
   201
#endif
sl@0
   202
	
sl@0
   203
	if (err != KErrNone)
sl@0
   204
		{
sl@0
   205
		CSurfaceUpdateServer::PanicServer(EUpdateServPanicStartUp);
sl@0
   206
		}
sl@0
   207
	*(static_cast <MSurfaceUpdateServerProvider**> (aAny)) = pS->SurfaceUpdateProvider();
sl@0
   208
      
sl@0
   209
      // Let everyone know that we are ready to
sl@0
   210
      // deal with requests.
sl@0
   211
	RThread::Rendezvous(KErrNone);
sl@0
   212
	  // And start fielding requests from client(s).
sl@0
   213
	CActiveScheduler::Start();
sl@0
   214
sl@0
   215
     // Tidy up... 	
sl@0
   216
	delete pS;
sl@0
   217
	delete pA;
sl@0
   218
	delete cleanup; 
sl@0
   219
	
sl@0
   220
	return KErrNone;
sl@0
   221
	}
sl@0
   222
sl@0
   223
inline TInt CSurfaceUpdateServer::NumUpdateReceivers() const
sl@0
   224
	{
sl@0
   225
	return iUpdateReceiver.Count(); 
sl@0
   226
	}
sl@0
   227
sl@0
   228
/**
sl@0
   229
Compare two content update receiver entries according to their priority. 
sl@0
   230
The function is used when receiver priority entry is inserted/retrieved from the array (iCompReceiverPriorityOrder).
sl@0
   231
sl@0
   232
@return zero, if the priorities of two receivers are equal; 
sl@0
   233
a negative value, if the priority of the first receiver is less than the priority of the second one; 
sl@0
   234
a positive value, if the priority of the first receiver is greater than the priority of the second one.
sl@0
   235
*/
sl@0
   236
TInt CSurfaceUpdateServer::CompareUpdateReceiverPriority(const TUpdateReceiverPriorityEntry& aEntry1, const TUpdateReceiverPriorityEntry& aEntry2)
sl@0
   237
	{
sl@0
   238
	return aEntry2.iPriority - aEntry1.iPriority;
sl@0
   239
	}
sl@0
   240
sl@0
   241
/**
sl@0
   242
class CSurfaceUpdateSession
sl@0
   243
sl@0
   244
Maintain the channel between clients and the server. 
sl@0
   245
Functions are provided will respond appropriately to client messages. 
sl@0
   246
*/
sl@0
   247
sl@0
   248
CSurfaceUpdateSession::CSurfaceUpdateSession(const RPointerArray<TUpdateReceiverPriorityEntry>& aEntryList) :
sl@0
   249
	CSession2(),
sl@0
   250
	iUpdateReceiverEntryList(aEntryList)
sl@0
   251
	{
sl@0
   252
	}
sl@0
   253
sl@0
   254
/**
sl@0
   255
Cancel any outstanding client notification requests. 
sl@0
   256
All resources owned by the session will either be immediately released or 
sl@0
   257
scheduled for deferred deletion.
sl@0
   258
*/
sl@0
   259
CSurfaceUpdateSession::~CSurfaceUpdateSession()
sl@0
   260
	{
sl@0
   261
	CancelAllUpdateNotifications();
sl@0
   262
	iUpdateReceiverNotificationBatches.ResetAndDestroy();
sl@0
   263
	}
sl@0
   264
sl@0
   265
/**
sl@0
   266
Main function which deals with requests from clients.
sl@0
   267
*/	
sl@0
   268
void CSurfaceUpdateSession::ServiceL(const RMessage2& aMessage)
sl@0
   269
	{
sl@0
   270
	switch (aMessage.Function())
sl@0
   271
		{
sl@0
   272
	case EUpdateServNotifyWhenAvailable:
sl@0
   273
		NotifyWhenAvailable(aMessage);
sl@0
   274
		return;
sl@0
   275
	case EUpdateServNotifyWhenDisplayed:
sl@0
   276
		NotifyWhenDisplayed(aMessage);
sl@0
   277
		return;
sl@0
   278
	case EUpdateServNotifyWhenDisplayedXTimes:
sl@0
   279
		NotifyWhenDisplayedXTimes(aMessage);
sl@0
   280
		return;
sl@0
   281
	case EUpdateServSubmitUpdate:
sl@0
   282
		SubmitUpdate(aMessage);
sl@0
   283
		return;
sl@0
   284
	case EUpdateServCancelAllNotifications:
sl@0
   285
		CancelAllUpdateNotifications();
sl@0
   286
		aMessage.Complete(KErrNone);
sl@0
   287
		return;
sl@0
   288
#ifdef TEST_SURFACE_UPDATE
sl@0
   289
	case EUpdateServOOM:
sl@0
   290
		{
sl@0
   291
		SetHeapFailure(aMessage);
sl@0
   292
		return;
sl@0
   293
		}
sl@0
   294
#endif
sl@0
   295
	default:
sl@0
   296
		PanicClient(aMessage, EUpdateServPanicBadRequest);
sl@0
   297
		return;
sl@0
   298
		}	 
sl@0
   299
	}
sl@0
   300
sl@0
   301
#ifdef TEST_SURFACE_UPDATE
sl@0
   302
/**
sl@0
   303
  Simulate heap allocation failure for the SUS thread's heap.
sl@0
   304
  Aim for OOM testing.
sl@0
   305
 */
sl@0
   306
void CSurfaceUpdateSession::SetHeapFailure(const RMessage2& aMessage)
sl@0
   307
	{
sl@0
   308
	TInt numElement = iUpdateReceiverNotificationBatches.Count();
sl@0
   309
	TInt index = 0;
sl@0
   310
	while(numElement)
sl@0
   311
		{
sl@0
   312
		CUpdateReceiverNotificationBatch* batch = iUpdateReceiverNotificationBatches[index];
sl@0
   313
		if(batch->iType == EUpdateSrvReusable)
sl@0
   314
			{
sl@0
   315
			iUpdateReceiverNotificationBatches.Remove(index);
sl@0
   316
			delete batch;
sl@0
   317
			}
sl@0
   318
		else
sl@0
   319
			{
sl@0
   320
			index++;
sl@0
   321
			}
sl@0
   322
		numElement--;            
sl@0
   323
		}
sl@0
   324
	if(numElement == 0)
sl@0
   325
		{
sl@0
   326
		iUpdateReceiverNotificationBatches.Reset();
sl@0
   327
		}
sl@0
   328
	TInt failRate = aMessage.Int0();
sl@0
   329
	if(!failRate)
sl@0
   330
		{
sl@0
   331
		__UHEAP_RESET;
sl@0
   332
		}
sl@0
   333
	else
sl@0
   334
		{
sl@0
   335
		__UHEAP_SETFAIL(RHeap::EDeterministic, failRate);
sl@0
   336
		}
sl@0
   337
	aMessage.Complete(KErrNone);
sl@0
   338
	}
sl@0
   339
#endif
sl@0
   340
sl@0
   341
void CSurfaceUpdateSession::PanicClient(const RMessage2& aMessage, TInt aPanic) const
sl@0
   342
	{
sl@0
   343
	_LIT(KTxtServer,"SurfUpServ");
sl@0
   344
	aMessage.Panic(KTxtServer, aPanic);
sl@0
   345
	}
sl@0
   346
sl@0
   347
/**
sl@0
   348
Return first inactive spare notification object stored in the notification array, 
sl@0
   349
create a new one if fail to find it in the array.
sl@0
   350
*/	
sl@0
   351
CUpdateReceiverNotificationBatch* CSurfaceUpdateSession::UpdateReceiverNotificationBatchL()
sl@0
   352
	{
sl@0
   353
	TInt numElement = iUpdateReceiverNotificationBatches.Count();
sl@0
   354
	CUpdateReceiverNotificationBatch* notifier = NULL;
sl@0
   355
	CSurfaceUpdateServer* server = (CSurfaceUpdateServer*) Server();
sl@0
   356
	for(TInt index = 0; index < numElement; index++)
sl@0
   357
		{
sl@0
   358
		notifier = iUpdateReceiverNotificationBatches[index];
sl@0
   359
		if(notifier->iType == EUpdateSrvReusable)
sl@0
   360
			{
sl@0
   361
			__ASSERT_ALWAYS(notifier->iMsg.IsNull(), CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity));
sl@0
   362
            notifier->SetNumUpdateReceivers(server->NumUpdateReceivers());
sl@0
   363
			if(numElement > index + 1)
sl@0
   364
				{
sl@0
   365
			//to improve a search, append the element to the end of the array
sl@0
   366
				iUpdateReceiverNotificationBatches.Remove(index);
sl@0
   367
				iUpdateReceiverNotificationBatches.AppendL(notifier);
sl@0
   368
				}
sl@0
   369
			return notifier;
sl@0
   370
			}
sl@0
   371
		}
sl@0
   372
	
sl@0
   373
	notifier = new (ELeave) CUpdateReceiverNotificationBatch(this, server->NumUpdateReceivers());
sl@0
   374
	CleanupStack::PushL(notifier);
sl@0
   375
	iUpdateReceiverNotificationBatches.AppendL(notifier);
sl@0
   376
	CleanupStack::Pop();
sl@0
   377
	
sl@0
   378
	return notifier;
sl@0
   379
	}
sl@0
   380
	
sl@0
   381
void CSurfaceUpdateSession::NotifyWhenAvailable(const RMessage2& aMessage)
sl@0
   382
	{
sl@0
   383
	StoreNotification(iAvailable, aMessage, EUpdateSrvAvailable);
sl@0
   384
	}
sl@0
   385
	
sl@0
   386
void CSurfaceUpdateSession::NotifyWhenDisplayed(const RMessage2& aMessage)
sl@0
   387
	{
sl@0
   388
	StoreNotification(iDisplayed, aMessage, EUpdateSrvDisplayed);
sl@0
   389
	}
sl@0
   390
	
sl@0
   391
void CSurfaceUpdateSession::NotifyWhenDisplayedXTimes(const RMessage2& aMessage)
sl@0
   392
	{
sl@0
   393
	StoreNotification(iDisplayedXTimes, aMessage, EUpdateSrvDisplayedXTimes);
sl@0
   394
	}
sl@0
   395
sl@0
   396
void CSurfaceUpdateSession::StoreNotification(CUpdateReceiverNotificationBatch*& aNotifier, const RMessage2& aMessage, TNotificationType aType)
sl@0
   397
	{
sl@0
   398
	if(aNotifier)
sl@0
   399
		{
sl@0
   400
		if(!aNotifier->iMsg.IsNull())
sl@0
   401
			{//not expected behaviour
sl@0
   402
			//would happen if a client sends the same notification request in a row
sl@0
   403
			IssueRequestComplete(KErrCancel);
sl@0
   404
			PanicClient(aMessage, EUpdateServPanicDataIntegrity);
sl@0
   405
			return;
sl@0
   406
			}
sl@0
   407
		}
sl@0
   408
	else
sl@0
   409
		{
sl@0
   410
		TRAPD(res, aNotifier = UpdateReceiverNotificationBatchL());
sl@0
   411
		if(res != KErrNone)
sl@0
   412
			{
sl@0
   413
			aMessage.Complete(res);
sl@0
   414
			return;
sl@0
   415
			}
sl@0
   416
		}	
sl@0
   417
	
sl@0
   418
	aNotifier->iMsg = aMessage;
sl@0
   419
	aNotifier->iType=aType;
sl@0
   420
	}
sl@0
   421
sl@0
   422
/*
sl@0
   423
Complete the outstanding requests and reset internal request variables to zero.
sl@0
   424
@param aErr Error code for completion.   
sl@0
   425
*/ 	
sl@0
   426
void CSurfaceUpdateSession::IssueRequestComplete(TInt aErr)
sl@0
   427
	{
sl@0
   428
	if(iAvailable)
sl@0
   429
		{
sl@0
   430
		if(!iAvailable->iMsg.IsNull())
sl@0
   431
			{
sl@0
   432
			iAvailable-> iMsg.Complete(aErr);
sl@0
   433
			iAvailable->CheckForReuse();	 
sl@0
   434
			}
sl@0
   435
		iAvailable = NULL;
sl@0
   436
		}
sl@0
   437
sl@0
   438
	if(iDisplayed)
sl@0
   439
		{
sl@0
   440
		if(!iDisplayed -> iMsg.IsNull())
sl@0
   441
			{
sl@0
   442
			iDisplayed -> iMsg.Complete(aErr);
sl@0
   443
			iDisplayed->CheckForReuse();
sl@0
   444
			}
sl@0
   445
		iDisplayed = NULL;
sl@0
   446
		}
sl@0
   447
sl@0
   448
	if(iDisplayedXTimes)
sl@0
   449
		{
sl@0
   450
		if(!iDisplayedXTimes->iMsg.IsNull())
sl@0
   451
			{
sl@0
   452
			iDisplayedXTimes->iMsg.Complete(aErr);
sl@0
   453
			iDisplayedXTimes->CheckForReuse();
sl@0
   454
			}
sl@0
   455
		iDisplayedXTimes=NULL;
sl@0
   456
		}
sl@0
   457
	}
sl@0
   458
sl@0
   459
/**
sl@0
   460
Redirect call to the DoSubmitUpdateL; error handling
sl@0
   461
*/
sl@0
   462
void CSurfaceUpdateSession::SubmitUpdate(const RMessage2& aMessage)
sl@0
   463
	{
sl@0
   464
	TInt err = KErrNone;
sl@0
   465
	TRAP(err, DoSubmitUpdateL(aMessage));
sl@0
   466
	if(err != KErrNone)
sl@0
   467
		{
sl@0
   468
		IssueRequestComplete(err);
sl@0
   469
		}
sl@0
   470
	aMessage.Complete(err);	
sl@0
   471
	}
sl@0
   472
sl@0
   473
/**
sl@0
   474
Issue request for the update to the composition receiver; 
sl@0
   475
ask notification on composition event if required.
sl@0
   476
*/	
sl@0
   477
void CSurfaceUpdateSession::DoSubmitUpdateL(const RMessage2& aMessage)
sl@0
   478
	{
sl@0
   479
	TInt displayedXTimes = 0;
sl@0
   480
	TInt screen;
sl@0
   481
	TInt buffer;
sl@0
   482
	TSurfaceId surfaceId;
sl@0
   483
	TPckg<TSurfaceId> surfaceIdPckg(surfaceId);
sl@0
   484
sl@0
   485
	RRegion *region = NULL;
sl@0
   486
	TRect *rectangleList = NULL;
sl@0
   487
sl@0
   488
	//extract the composition data
sl@0
   489
	aMessage.ReadL(1, surfaceIdPckg);
sl@0
   490
	
sl@0
   491
	screen = aMessage.Int0();
sl@0
   492
	buffer = aMessage.Int2();
sl@0
   493
	
sl@0
   494
	//validate parameters
sl@0
   495
	if((screen < 0) || (buffer < 0))
sl@0
   496
		{
sl@0
   497
		User::Leave(KErrArgument);
sl@0
   498
		}
sl@0
   499
	//Check that we haven't used another update method before
sl@0
   500
	//The comparison is slightly optimized for performance as oppose to code size
sl@0
   501
	if(iUpdateMethod == EUpdateMethodGlobal) 
sl@0
   502
		{
sl@0
   503
		if(screen != KAllScreens)
sl@0
   504
			User::Leave(KErrNotSupported);
sl@0
   505
		}
sl@0
   506
	else if(iUpdateMethod == EUpdateMethodPerScreen) 
sl@0
   507
		{
sl@0
   508
		if(screen == KAllScreens)
sl@0
   509
			User::Leave(KErrNotSupported);
sl@0
   510
		}
sl@0
   511
	
sl@0
   512
	TInt len = aMessage.GetDesLength(3);
sl@0
   513
	if(len > 0)
sl@0
   514
		{
sl@0
   515
		rectangleList = (TRect*) (User::AllocL(len));
sl@0
   516
		CleanupStack::PushL(rectangleList);
sl@0
   517
		TPtr8 ptrRect(reinterpret_cast<TUint8*> (rectangleList), len);
sl@0
   518
		aMessage.ReadL(3, ptrRect);
sl@0
   519
		TInt regionCount = len / sizeof(TRect);
sl@0
   520
		region = new (ELeave) RRegion(regionCount, rectangleList);
sl@0
   521
		CleanupStack::PushL(region);
sl@0
   522
		}
sl@0
   523
	if(iDisplayedXTimes)
sl@0
   524
		{
sl@0
   525
		displayedXTimes = iDisplayedXTimes -> iMsg.Int0();
sl@0
   526
		if(displayedXTimes < 1)
sl@0
   527
			{
sl@0
   528
			iDisplayedXTimes->iMsg.Complete(KErrArgument);
sl@0
   529
			iDisplayedXTimes->CheckForReuse();
sl@0
   530
			iDisplayedXTimes = NULL;
sl@0
   531
			}
sl@0
   532
		}
sl@0
   533
	
sl@0
   534
	const CSurfaceUpdateServer* server = static_cast <const CSurfaceUpdateServer*> (Server());	
sl@0
   535
	if(screen != KAllScreens)
sl@0
   536
		{
sl@0
   537
		MCompositionSurfaceUpdate* receiver = server->UpdateReceiver(screen);
sl@0
   538
		if(!receiver)
sl@0
   539
			{
sl@0
   540
			User::Leave(KErrUpdateReceiverNotAvailable);
sl@0
   541
			}
sl@0
   542
		DispatchUpdate(surfaceId, buffer, region, &displayedXTimes, receiver);
sl@0
   543
		iUpdateMethod = EUpdateMethodPerScreen;
sl@0
   544
		}
sl@0
   545
	else
sl@0
   546
		{
sl@0
   547
		DispatchUpdate(surfaceId, buffer, region, &displayedXTimes);
sl@0
   548
		iUpdateMethod = EUpdateMethodGlobal;
sl@0
   549
		}
sl@0
   550
				
sl@0
   551
	if(region)
sl@0
   552
		{
sl@0
   553
		CleanupStack::PopAndDestroy(2, rectangleList);
sl@0
   554
		}
sl@0
   555
	}
sl@0
   556
sl@0
   557
/**
sl@0
   558
 Dispatch update to the composition update receivers. 
sl@0
   559
 The function could fail to allocate the notification objects 
sl@0
   560
 due to memory shortage, however, the content update command will still be submitted to the GCE.  
sl@0
   561
 */
sl@0
   562
void CSurfaceUpdateSession::DispatchUpdate(const TSurfaceId& aSurfaceId, TInt aBuffer, RRegion* aRegion, TInt* aDisplayedXTimes, MCompositionSurfaceUpdate* aReceiver)
sl@0
   563
	{
sl@0
   564
	TInt index = 1;
sl@0
   565
	TInt numReceivers = 1;
sl@0
   566
	TInt priority = 0;
sl@0
   567
	
sl@0
   568
	if(!aReceiver)
sl@0
   569
		{
sl@0
   570
		aReceiver = iUpdateReceiverEntryList[0]->iUpdateReceiver;
sl@0
   571
		priority = iUpdateReceiverEntryList[0]->iPriority;
sl@0
   572
		numReceivers = iUpdateReceiverEntryList.Count(); //get the number of all receivers present in the system
sl@0
   573
		}
sl@0
   574
	
sl@0
   575
	for(;;)
sl@0
   576
		{	
sl@0
   577
		CUpdateReceiverNotification* receiverNotificationAvailable = NULL;
sl@0
   578
		CUpdateReceiverNotification* receiverNotificationDisplayed = NULL;
sl@0
   579
		CUpdateReceiverNotification* receiverNotificationDisplayedXTimes = NULL;
sl@0
   580
		TUint32* timeStamp = NULL;
sl@0
   581
	
sl@0
   582
	//activate objects
sl@0
   583
		if(iAvailable)
sl@0
   584
			{
sl@0
   585
			receiverNotificationAvailable = iAvailable->UpdateReceiverNotification();
sl@0
   586
			if(!receiverNotificationAvailable)
sl@0
   587
				{
sl@0
   588
				iAvailable->iMsg.Complete(KErrNoMemory);
sl@0
   589
				iAvailable->CheckForReuse();
sl@0
   590
				iAvailable = NULL;
sl@0
   591
				}
sl@0
   592
			}
sl@0
   593
sl@0
   594
		if(iDisplayed)
sl@0
   595
			{
sl@0
   596
			receiverNotificationDisplayed = iDisplayed->UpdateReceiverNotification(priority);
sl@0
   597
			if(!receiverNotificationDisplayed)
sl@0
   598
				{
sl@0
   599
				iDisplayed->iMsg.Complete(KErrNoMemory);
sl@0
   600
				iDisplayed->CheckForReuse();
sl@0
   601
				iDisplayed = NULL;
sl@0
   602
				}
sl@0
   603
			}
sl@0
   604
sl@0
   605
		if(iDisplayedXTimes)
sl@0
   606
			{
sl@0
   607
			receiverNotificationDisplayedXTimes = iDisplayedXTimes->UpdateReceiverNotification();
sl@0
   608
			if(!receiverNotificationDisplayedXTimes)
sl@0
   609
				{
sl@0
   610
				iDisplayedXTimes->iMsg.Complete(KErrNoMemory);
sl@0
   611
				iDisplayedXTimes->CheckForReuse();
sl@0
   612
				iDisplayedXTimes = NULL;
sl@0
   613
				}
sl@0
   614
			}
sl@0
   615
	
sl@0
   616
		TRequestStatus *statusAvailable = NULL;
sl@0
   617
		TRequestStatus *statusDisplayed = NULL;
sl@0
   618
		TRequestStatus *statusDisplayedXTimes = NULL;
sl@0
   619
	//activate all notifications
sl@0
   620
		if(receiverNotificationAvailable)
sl@0
   621
			{
sl@0
   622
			statusAvailable = &(receiverNotificationAvailable->Status());
sl@0
   623
			receiverNotificationAvailable->Activate();
sl@0
   624
			}
sl@0
   625
		if(receiverNotificationDisplayed)
sl@0
   626
			{
sl@0
   627
			statusDisplayed = &(receiverNotificationDisplayed->Status());
sl@0
   628
			timeStamp = & receiverNotificationDisplayed -> iTimeStamp;
sl@0
   629
			receiverNotificationDisplayed->Activate();
sl@0
   630
			}
sl@0
   631
		if(receiverNotificationDisplayedXTimes)
sl@0
   632
			{
sl@0
   633
			statusDisplayedXTimes = &(receiverNotificationDisplayedXTimes->Status());
sl@0
   634
			receiverNotificationDisplayedXTimes->Activate();
sl@0
   635
			}
sl@0
   636
	//And finally, send request to the receiver   
sl@0
   637
		aReceiver->ContentUpdated(aSurfaceId, aBuffer, aRegion,
sl@0
   638
				statusAvailable, statusDisplayed, timeStamp, 
sl@0
   639
				statusDisplayedXTimes, statusDisplayedXTimes ? aDisplayedXTimes : NULL);
sl@0
   640
	
sl@0
   641
		if(numReceivers > index)
sl@0
   642
			{
sl@0
   643
			priority = iUpdateReceiverEntryList[index]->iPriority;
sl@0
   644
			aReceiver = iUpdateReceiverEntryList[index++]->iUpdateReceiver;
sl@0
   645
			}
sl@0
   646
		else
sl@0
   647
			break;
sl@0
   648
		}//for(;;)
sl@0
   649
	
sl@0
   650
	iAvailable = NULL;
sl@0
   651
	iDisplayed = NULL;
sl@0
   652
	iDisplayedXTimes = NULL;
sl@0
   653
	}
sl@0
   654
sl@0
   655
void CSurfaceUpdateSession::CancelAllUpdateNotifications()
sl@0
   656
	{
sl@0
   657
	//go through all notification objects and issue request complete for outstanding requests
sl@0
   658
	TInt count = iUpdateReceiverNotificationBatches.Count();
sl@0
   659
	
sl@0
   660
	for(TInt index = 0; index < count; index++)
sl@0
   661
		{
sl@0
   662
		CUpdateReceiverNotificationBatch* notifier = iUpdateReceiverNotificationBatches[index];
sl@0
   663
		if(!notifier->iMsg.IsNull())
sl@0
   664
			{
sl@0
   665
			notifier->iMsg.Complete(KErrCancel);
sl@0
   666
			}
sl@0
   667
		}
sl@0
   668
sl@0
   669
	iAvailable = NULL;
sl@0
   670
	iDisplayed = NULL;
sl@0
   671
	iDisplayedXTimes = NULL;
sl@0
   672
	}
sl@0
   673
	
sl@0
   674
//*********************
sl@0
   675
CUpdateReceiverNotification::CUpdateReceiverNotification(CActive::TPriority aPriority, TInt aReceiverPriority, CUpdateReceiverNotificationBatch *aParentNotificationBatch) :
sl@0
   676
	CActive(aPriority), iUpdateReceiverPriority(aReceiverPriority), iParentNotificationBatch(aParentNotificationBatch)
sl@0
   677
	{
sl@0
   678
	CActiveScheduler::Add(this);
sl@0
   679
#ifdef TEST_SURFACE_UPDATE
sl@0
   680
	iServer = iParentNotificationBatch->Server();
sl@0
   681
#endif
sl@0
   682
	}
sl@0
   683
	
sl@0
   684
CUpdateReceiverNotification::~CUpdateReceiverNotification()
sl@0
   685
	{
sl@0
   686
	//Content updates can not be cancelled. The user must ensure that the associated content update 
sl@0
   687
	//is complete before deleting this object.
sl@0
   688
	__ASSERT_ALWAYS(!IsActive(), CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity));
sl@0
   689
	}
sl@0
   690
	
sl@0
   691
void CUpdateReceiverNotification::DoCancel()
sl@0
   692
	{
sl@0
   693
	//Content Updates can not be cancelled. Content Updates must be allowed to complete normally.
sl@0
   694
	CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity);
sl@0
   695
	}
sl@0
   696
sl@0
   697
/**
sl@0
   698
Is triggered every time the GCE signals on notification objects.
sl@0
   699
Delegates processing to the parent notification batch.   
sl@0
   700
*/	
sl@0
   701
void CUpdateReceiverNotification::RunL()
sl@0
   702
	{
sl@0
   703
	// CReceiverNotification object is deleted here once it is set to self destroying when run.
sl@0
   704
	if (iSelfDestructWhenRun)
sl@0
   705
		{
sl@0
   706
#ifdef TEST_SURFACE_UPDATE
sl@0
   707
		DecNumberPendingNotifications();
sl@0
   708
#endif
sl@0
   709
		delete this;
sl@0
   710
		return;
sl@0
   711
		}
sl@0
   712
	iParentNotificationBatch->ProcessNotificationEvent(this);
sl@0
   713
	}
sl@0
   714
	
sl@0
   715
TRequestStatus& CUpdateReceiverNotification::Status()
sl@0
   716
	{
sl@0
   717
	return iStatus;	
sl@0
   718
	}
sl@0
   719
sl@0
   720
void CUpdateReceiverNotification::Activate()
sl@0
   721
	{
sl@0
   722
	iStatus = KRequestPending;
sl@0
   723
	SetActive();
sl@0
   724
	}
sl@0
   725
sl@0
   726
#ifdef TEST_SURFACE_UPDATE
sl@0
   727
void CUpdateReceiverNotification::DecNumberPendingNotifications()
sl@0
   728
	{
sl@0
   729
	if (iServer)
sl@0
   730
		{
sl@0
   731
		iServer-> iNumberPendingNotification--;
sl@0
   732
		}
sl@0
   733
	}
sl@0
   734
#endif
sl@0
   735
sl@0
   736
/**
sl@0
   737
The class maintains the notification objects of the same type and attributed to a 
sl@0
   738
particular submit update command.   
sl@0
   739
 */
sl@0
   740
CUpdateReceiverNotificationBatch::CUpdateReceiverNotificationBatch(CSurfaceUpdateSession *aSession, TInt aNumReceivers) :
sl@0
   741
	iSession(aSession), iNumUpdateReceivers(aNumReceivers)
sl@0
   742
	{
sl@0
   743
	CheckForReuse();
sl@0
   744
	}
sl@0
   745
sl@0
   746
CUpdateReceiverNotificationBatch::~CUpdateReceiverNotificationBatch()
sl@0
   747
	{
sl@0
   748
	TInt count = iUpdateReceiverNotifications.Count();
sl@0
   749
	for(TInt index = 0; index < count; index++)
sl@0
   750
		{
sl@0
   751
		CUpdateReceiverNotification* notifier = iUpdateReceiverNotifications[index];
sl@0
   752
		// CReceiverNotification active object cannot be destroyed if it is active and waiting for
sl@0
   753
		// receiver to complete the notification. It deletes itself inside its RunL function when the
sl@0
   754
		// notification is completed.
sl@0
   755
		if (notifier->IsActive())
sl@0
   756
			{
sl@0
   757
			notifier->iSelfDestructWhenRun = ETrue;
sl@0
   758
#ifdef TEST_SURFACE_UPDATE
sl@0
   759
			IncNumberPendingNotifications();
sl@0
   760
#endif
sl@0
   761
			}
sl@0
   762
		else
sl@0
   763
			{
sl@0
   764
			delete notifier;
sl@0
   765
			}
sl@0
   766
		}
sl@0
   767
	iUpdateReceiverNotifications.Close();
sl@0
   768
	}
sl@0
   769
sl@0
   770
/**
sl@0
   771
The function processes signal from composition receiver. 
sl@0
   772
It completes outstanding messages on the client and set timestamp parameters if appropriate.
sl@0
   773
Note that this object will not be removed from the 
sl@0
   774
array (CSurfaceUpdateSession:: iReceiverNotifications) and can be reused later.
sl@0
   775
*/
sl@0
   776
void CUpdateReceiverNotificationBatch::ProcessNotificationEvent(CUpdateReceiverNotification* aReceiverNotification)
sl@0
   777
	{
sl@0
   778
	TInt index = iUpdateReceiverNotifications.Find(aReceiverNotification);
sl@0
   779
	__ASSERT_DEBUG(index != KErrNotFound, CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity));
sl@0
   780
	iUpdateReceiverNotifications.Remove(index);
sl@0
   781
	if(iMsg.IsNull())
sl@0
   782
		{
sl@0
   783
		CheckForReuse();
sl@0
   784
		delete aReceiverNotification;
sl@0
   785
		return; // the message has already been completed, possibly, because of request cancelation
sl@0
   786
		}
sl@0
   787
	TBool oldCompleteWithSuccess = iCompleteWithSuccess;
sl@0
   788
	TBool newCompleteWithSuccess = EFalse;
sl@0
   789
	if(aReceiverNotification->iStatus.Int() == KErrNone)
sl@0
   790
		{
sl@0
   791
		iCompleteWithSuccess = ETrue;
sl@0
   792
		newCompleteWithSuccess = ETrue;
sl@0
   793
		}
sl@0
   794
	
sl@0
   795
	switch(iType)
sl@0
   796
		{
sl@0
   797
	case EUpdateSrvAvailable:
sl@0
   798
		if(iUpdateReceiverNotifications.Count() == 0)
sl@0
   799
			{
sl@0
   800
			TInt res = iCompleteWithSuccess ? KErrNone : aReceiverNotification->iStatus.Int();
sl@0
   801
			iMsg.Complete(res);
sl@0
   802
			}
sl@0
   803
		break;
sl@0
   804
	case EUpdateSrvDisplayedXTimes:
sl@0
   805
		if((newCompleteWithSuccess && (index == 0)) || (iUpdateReceiverNotifications.Count() == 0))
sl@0
   806
			{
sl@0
   807
			TInt res = iCompleteWithSuccess ? KErrNone : aReceiverNotification->iStatus.Int();
sl@0
   808
			iMsg.Complete(res);
sl@0
   809
			}
sl@0
   810
		break;
sl@0
   811
	case EUpdateSrvDisplayed:
sl@0
   812
		if(newCompleteWithSuccess && 
sl@0
   813
				((iHighestPriority < aReceiverNotification->iUpdateReceiverPriority) || !oldCompleteWithSuccess))
sl@0
   814
			{
sl@0
   815
			iHighestPriority = aReceiverNotification->iUpdateReceiverPriority;
sl@0
   816
			iTimeStamp = aReceiverNotification->iTimeStamp;
sl@0
   817
			}
sl@0
   818
		if((newCompleteWithSuccess && (index == 0)) || (iUpdateReceiverNotifications.Count() == 0))
sl@0
   819
			{
sl@0
   820
			TPckgBuf<TUint32> p(iTimeStamp);
sl@0
   821
			TInt res = iMsg.Write(0, p); //We must not leave here as it will cause panic on Active scheduler. This would be inappropriate for the server side thread.
sl@0
   822
			if(res == KErrNone)
sl@0
   823
				{
sl@0
   824
				res = iCompleteWithSuccess ? KErrNone : aReceiverNotification->iStatus.Int();
sl@0
   825
				}
sl@0
   826
			iMsg.Complete(res);
sl@0
   827
			}
sl@0
   828
		break;
sl@0
   829
	default:	
sl@0
   830
		break;
sl@0
   831
		}
sl@0
   832
	
sl@0
   833
	delete aReceiverNotification;
sl@0
   834
	CheckForReuse();
sl@0
   835
	}
sl@0
   836
sl@0
   837
/**
sl@0
   838
 The method allocates a notification object and inserts it into the list
sl@0
   839
*/ 
sl@0
   840
CUpdateReceiverNotification* CUpdateReceiverNotificationBatch::UpdateReceiverNotification(TInt aReceiverPriority)
sl@0
   841
	{
sl@0
   842
	__ASSERT_DEBUG(iNumUpdateReceivers > iUpdateReceiverNotifications.Count(), CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity));
sl@0
   843
	
sl@0
   844
	CUpdateReceiverNotification* receiverNotification = new CUpdateReceiverNotification(CActive::EPriorityStandard, aReceiverPriority, this);
sl@0
   845
	if(receiverNotification)
sl@0
   846
		{
sl@0
   847
		TInt res = iUpdateReceiverNotifications.Append(receiverNotification);
sl@0
   848
		if(res != KErrNone)
sl@0
   849
			{
sl@0
   850
			delete receiverNotification;
sl@0
   851
			receiverNotification = NULL;
sl@0
   852
			}
sl@0
   853
		}
sl@0
   854
	
sl@0
   855
	return receiverNotification;
sl@0
   856
	}
sl@0
   857
sl@0
   858
/**
sl@0
   859
If notification list is empty mark the batch for further use
sl@0
   860
*/
sl@0
   861
void CUpdateReceiverNotificationBatch::CheckForReuse()
sl@0
   862
	{
sl@0
   863
	if(iUpdateReceiverNotifications.Count() == 0)
sl@0
   864
		{
sl@0
   865
		iType = EUpdateSrvReusable;
sl@0
   866
		iCompleteWithSuccess = EFalse;
sl@0
   867
		iHighestPriority = 0;
sl@0
   868
		iTimeStamp = 0;
sl@0
   869
		}
sl@0
   870
	}
sl@0
   871
sl@0
   872
#ifdef TEST_SURFACE_UPDATE
sl@0
   873
CSurfaceUpdateServer* CUpdateReceiverNotificationBatch::Server()
sl@0
   874
	{
sl@0
   875
	return (CSurfaceUpdateServer*)(iSession->Server());
sl@0
   876
	}
sl@0
   877
sl@0
   878
void CUpdateReceiverNotificationBatch::IncNumberPendingNotifications()
sl@0
   879
	{
sl@0
   880
	CServer2* server = static_cast<CServer2*> (Server());
sl@0
   881
	if(server)
sl@0
   882
		{
sl@0
   883
		(static_cast<CSurfaceUpdateServer*> (server))-> iNumberPendingNotification++;
sl@0
   884
		}
sl@0
   885
	}
sl@0
   886
#endif
sl@0
   887
sl@0
   888
sl@0
   889
/**
sl@0
   890
Set number of UpdateReceivers - called when update receivers are added/removed.
sl@0
   891
sl@0
   892
@param aNumUpdateReceivers - new number of update receivers for the batch.
sl@0
   893
 */
sl@0
   894
void CUpdateReceiverNotificationBatch::SetNumUpdateReceivers(TInt aNumUpdateReceivers)
sl@0
   895
    {
sl@0
   896
    __ASSERT_DEBUG(aNumUpdateReceivers >= 0 && aNumUpdateReceivers < 1000 /* arbitrary "large" limit */,
sl@0
   897
            CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity));
sl@0
   898
    __ASSERT_DEBUG(iType == EUpdateSrvReusable, 
sl@0
   899
            CSurfaceUpdateServer::PanicServer(EUpdateServPanicDataIntegrity));
sl@0
   900
    iNumUpdateReceivers = aNumUpdateReceivers;
sl@0
   901
    }
sl@0
   902
/**
sl@0
   903
sl@0
   904
The class will be used by composition receiver
sl@0
   905
*/
sl@0
   906
CSurfaceUpdateServerProvider* CSurfaceUpdateServerProvider::NewL(CActive::TPriority aPriority, CSurfaceUpdateServer* aServer)
sl@0
   907
	{
sl@0
   908
	CSurfaceUpdateServerProvider* serverProvider = new (ELeave) CSurfaceUpdateServerProvider(aPriority, aServer);
sl@0
   909
	CleanupStack::PushL(serverProvider);
sl@0
   910
	serverProvider->ConstructL();
sl@0
   911
	CleanupStack::Pop();
sl@0
   912
	return serverProvider;
sl@0
   913
	}
sl@0
   914
sl@0
   915
CSurfaceUpdateServerProvider::CSurfaceUpdateServerProvider(CActive::TPriority aPriority, CSurfaceUpdateServer* aServer) :
sl@0
   916
								CActive(aPriority), iServer(aServer)
sl@0
   917
	{
sl@0
   918
	RThread thread;
sl@0
   919
	iThreadId = thread.Id();
sl@0
   920
	}
sl@0
   921
	
sl@0
   922
CSurfaceUpdateServerProvider::~CSurfaceUpdateServerProvider()
sl@0
   923
	{
sl@0
   924
	iSemaphore.Close();
sl@0
   925
	Cancel();
sl@0
   926
	}
sl@0
   927
/**
sl@0
   928
Create provider and add it to the active scheduler
sl@0
   929
*/
sl@0
   930
void CSurfaceUpdateServerProvider::ConstructL()
sl@0
   931
	{
sl@0
   932
	User::LeaveIfError(iSemaphore.CreateLocal(0));
sl@0
   933
	CActiveScheduler::Add(this);
sl@0
   934
	iStatus = KRequestPending;
sl@0
   935
	SetActive();
sl@0
   936
	}
sl@0
   937
sl@0
   938
/**  
sl@0
   939
 Assign composition receiver instance to particular screen.
sl@0
   940
 The following calls of this function for the same screen will override the previous.
sl@0
   941
 @see MSurfaceUpdateServerProvider::::Register
sl@0
   942
 */	
sl@0
   943
EXPORT_C TInt CSurfaceUpdateServerProvider::Register(TInt aScreen, CBase* aReceiver, TInt aPriority)
sl@0
   944
	{
sl@0
   945
	RThread thread;
sl@0
   946
	TInt res = thread.Open(iThreadId);
sl@0
   947
	if(res == KErrNone)
sl@0
   948
		{
sl@0
   949
		iScreen = aScreen;
sl@0
   950
		iUpdateReceiver = aReceiver;
sl@0
   951
		iPriority = aPriority;
sl@0
   952
sl@0
   953
		TRequestStatus* status = &iStatus;
sl@0
   954
		thread.RequestComplete(status, EUpdateServEventRegister);
sl@0
   955
		thread.Close();
sl@0
   956
		iSemaphore.Wait();
sl@0
   957
		res = iRegisterErr;
sl@0
   958
		}
sl@0
   959
	return res;
sl@0
   960
	}
sl@0
   961
sl@0
   962
/**
sl@0
   963
Terminate the SUS and release all memory associated with it. 
sl@0
   964
The function was introduced for debugging purpose only and is not considered 
sl@0
   965
as part of public API.
sl@0
   966
*/
sl@0
   967
EXPORT_C void CSurfaceUpdateServerProvider::Terminate()
sl@0
   968
	{
sl@0
   969
#ifdef TEST_SURFACE_UPDATE
sl@0
   970
	RThread thread;
sl@0
   971
sl@0
   972
	if(thread.Open(iThreadId) == KErrNone)
sl@0
   973
		{
sl@0
   974
	    TInt err = gProviderFastLock.CreateLocal();
sl@0
   975
	    __ASSERT_ALWAYS(err == KErrNone || err == KErrAlreadyExists, CSurfaceUpdateServer::PanicServer(EUpdateServPanicGlobalFastLock));
sl@0
   976
	    
sl@0
   977
	    gProviderFastLock.Wait();
sl@0
   978
	    gProvider = NULL;
sl@0
   979
		if (iServer)
sl@0
   980
			{
sl@0
   981
			while((static_cast<CSurfaceUpdateServer*> (iServer))-> iNumberPendingNotification)
sl@0
   982
				User::After(TTimeIntervalMicroSeconds32(1000));
sl@0
   983
			}
sl@0
   984
		TRequestStatus* status = &iStatus;
sl@0
   985
		thread.RequestComplete(status, EUpdateServEventTerminate);
sl@0
   986
		
sl@0
   987
		//wait until the thread dies
sl@0
   988
		TRequestStatus status1;
sl@0
   989
		thread.Logon(status1);
sl@0
   990
		User::WaitForRequest(status1);
sl@0
   991
		thread.Close();
sl@0
   992
		
sl@0
   993
     	gProviderFastLock.Close();
sl@0
   994
		}
sl@0
   995
#endif
sl@0
   996
	}
sl@0
   997
sl@0
   998
/**
sl@0
   999
The function processes signals which come from composition receiver thread.
sl@0
  1000
*/	
sl@0
  1001
void CSurfaceUpdateServerProvider::RunL()
sl@0
  1002
	{
sl@0
  1003
	switch(iStatus.Int())
sl@0
  1004
		{
sl@0
  1005
	case EUpdateServEventTerminate:
sl@0
  1006
		CActiveScheduler::Stop();
sl@0
  1007
		return; 
sl@0
  1008
	case EUpdateServEventRegister:
sl@0
  1009
		iRegisterErr = iServer->Register(iScreen, iUpdateReceiver, iPriority);
sl@0
  1010
		iUpdateReceiver = NULL;
sl@0
  1011
		iStatus = KRequestPending;
sl@0
  1012
		SetActive();
sl@0
  1013
		iSemaphore.Signal();
sl@0
  1014
		break;
sl@0
  1015
	default :
sl@0
  1016
		CSurfaceUpdateServer::PanicServer(EUpdateServPanicBadRequest); 
sl@0
  1017
		iStatus = KRequestPending;
sl@0
  1018
		SetActive();
sl@0
  1019
		break;	
sl@0
  1020
		}
sl@0
  1021
	}
sl@0
  1022
	
sl@0
  1023
void CSurfaceUpdateServerProvider::DoCancel()
sl@0
  1024
	{
sl@0
  1025
	}
sl@0
  1026
sl@0
  1027
/**
sl@0
  1028
Spawn a thread within WSERV process. This will lead to starting the surface update server in it 
sl@0
  1029
@publishedPartner
sl@0
  1030
@prototype Intended to be used by Surface Update control flow
sl@0
  1031
	
sl@0
  1032
@param aUpdateProvider - [out] reference pointer to surface update server provider, 
sl@0
  1033
		which will be set when the server is started. The variable will be used to registry 
sl@0
  1034
		composition receiver instances. The caller doesn't acquire the ownership of this instance,
sl@0
  1035
		thus mustn't delete it. The pointer will be valid until server is operating, 
sl@0
  1036
		i.e. system is up.
sl@0
  1037
sl@0
  1038
@return KErrNone if an operation is successful, any other system error codes otherwise
sl@0
  1039
*/
sl@0
  1040
EXPORT_C TInt StartSurfaceUpdateServer(MSurfaceUpdateServerProvider*& aSurfaceUpdateServerProvider)
sl@0
  1041
	{
sl@0
  1042
#ifndef TEST_SURFACE_UPDATE
sl@0
  1043
	TPtrC serverName(KSurfaceUpdateServerName);
sl@0
  1044
#else
sl@0
  1045
	TPtrC serverName(KTestSurfaceUpdateServerName);
sl@0
  1046
#endif
sl@0
  1047
	//locking
sl@0
  1048
	TInt err = gProviderFastLock.CreateLocal();
sl@0
  1049
	
sl@0
  1050
	if (err != KErrNone && err != KErrAlreadyExists)
sl@0
  1051
	    {
sl@0
  1052
        return err;
sl@0
  1053
	    }
sl@0
  1054
	
sl@0
  1055
	gProviderFastLock.Wait();
sl@0
  1056
sl@0
  1057
	TAny *provider = gProvider;
sl@0
  1058
	if(provider)
sl@0
  1059
		{
sl@0
  1060
		aSurfaceUpdateServerProvider = static_cast <MSurfaceUpdateServerProvider*> (provider);
sl@0
  1061
		gProviderFastLock.Signal();
sl@0
  1062
		return KErrNone;
sl@0
  1063
		}
sl@0
  1064
	TFullName   name;
sl@0
  1065
	RThread serverThread;
sl@0
  1066
	TInt res = KErrAlreadyExists;
sl@0
  1067
	
sl@0
  1068
	TFindServer findSurfaceUpdateServer(serverName);
sl@0
  1069
	  // Need to check that the server exists.
sl@0
  1070
	if (findSurfaceUpdateServer.Next(name) !=KErrNone)
sl@0
  1071
		{
sl@0
  1072
		TTime tm;
sl@0
  1073
		TBuf<32> buf;
sl@0
  1074
		tm.UniversalTime();
sl@0
  1075
		TRAP(res, tm.FormatL(buf, _L("_%H%T%S%C")));
sl@0
  1076
		if(res != KErrNone)	
sl@0
  1077
			{
sl@0
  1078
			gProviderFastLock.Signal();
sl@0
  1079
			return res;
sl@0
  1080
			}
sl@0
  1081
		TBuf<128> threadName(serverName);
sl@0
  1082
		threadName.Append(buf); //guarantee uniqueness  of the thread name
sl@0
  1083
		  // Create the thread for the server.
sl@0
  1084
		res = serverThread.Create(threadName,
sl@0
  1085
			CSurfaceUpdateServer::ThreadFunction,
sl@0
  1086
			KDefaultStackSize,
sl@0
  1087
			KDefaultHeapSize,
sl@0
  1088
			KDefaultHeapSize,
sl@0
  1089
			(TAny*) &aSurfaceUpdateServerProvider
sl@0
  1090
			);
sl@0
  1091
          // The thread has been created OK so get it started - however
sl@0
  1092
          // we need to make sure that it has started before we continue.
sl@0
  1093
		if (res==KErrNone)
sl@0
  1094
			{
sl@0
  1095
			TRequestStatus rendezvousStatus;
sl@0
  1096
			TThreadPriority priority = RThread().Priority();    
sl@0
  1097
			serverThread.SetPriority(priority); // The same as the priority of the creating thread
sl@0
  1098
			serverThread.Rendezvous(rendezvousStatus);
sl@0
  1099
			serverThread.Resume();
sl@0
  1100
			User::WaitForRequest(rendezvousStatus);
sl@0
  1101
			res = rendezvousStatus.Int();
sl@0
  1102
			gProvider = aSurfaceUpdateServerProvider;
sl@0
  1103
			}
sl@0
  1104
    // The thread has not been created - clearly there's been a problem.
sl@0
  1105
		else
sl@0
  1106
			{
sl@0
  1107
			serverThread.Close();
sl@0
  1108
			}
sl@0
  1109
		}
sl@0
  1110
       gProviderFastLock.Signal();
sl@0
  1111
		return res;
sl@0
  1112
	}