os/kernelhwsrv/userlibandfileserver/fileserver/sfile/sf_plugin_man.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // f32\sfile\sf_plugin.cpp
    15 // 
    16 //
    17 
    18 #include <e32std.h>
    19 #include "sf_std.h"
    20 #include "sf_plugin_priv.h"
    21 
    22 CFsObjectCon* FsPluginManager::iPluginFactories = NULL;
    23 CFsObjectCon* FsPluginManager::iPluginConns     = NULL;
    24 RFastLock FsPluginManager::iChainLock;
    25 RPointerArray<CFsPlugin> FsPluginManager::iPluginChain;
    26 CFsSyncMessageScheduler* FsPluginManager::iScheduler = NULL;
    27 
    28 TBool IsPagableDrive(TInt aDrive)
    29 	{
    30 	if(LocalDrives::IsValidDriveMapping(aDrive))
    31 		{
    32 		TLocalDriveCapsBuf capsBuf;	
    33 		if(!LocalDrives::IsProxyDrive(aDrive) && LocalDrives::GetLocalDrive(aDrive).Caps(capsBuf) && capsBuf().iDriveAtt & KDriveAttPageable)
    34 			{
    35 			return (TBool)ETrue;
    36 			}
    37 		}
    38 	return (TBool) EFalse;
    39 	}
    40 
    41 /*
    42 @param aNonPagableDriveMask - a drive mask of the drives a plugin wishes to mount on
    43 @return A drive mask of the drives a plugin wishes to mount on not containing any pagable drives.
    44 */
    45 TInt NonPagableDrivesMask(TInt aNonPagableDriveMask)
    46 	{
    47 	TInt driveMask = aNonPagableDriveMask;
    48 	for(TInt i = 0; i < KMaxDrives; i++)
    49 		{
    50 		//If we're interested in this drive
    51 		if((aNonPagableDriveMask & 1<<i) && IsPagableDrive(i)) 
    52 			{
    53 			driveMask ^= 1<<i; //remove this drive
    54 			}
    55 		}
    56 	return driveMask;
    57 	}
    58 
    59 TInt FsPluginManager::UpdateMountedDrive(CFsPlugin* aPlugin, CFsPluginFactory* aFactory,TInt aDrive)
    60 	{
    61 	if(aDrive==KPluginAutoAttach) //KPluginAutoAttach
    62 		{
    63 		if(!(aFactory->SupportedDrives()&KPluginVersionTwo)) 
    64 			{ //Version 1 Plugin - Mount on all (except Z and pagble drives) 
    65 			TInt drivesAToY = (KPluginSupportAllDrives>>1);
    66 			aPlugin->iMountedOn = NonPagableDrivesMask(drivesAToY);
    67 			}
    68 		else 
    69 			{ //Version 2 Plugin - Mount on what the plugin supports (except pagable drives)
    70 			aPlugin->iMountedOn = NonPagableDrivesMask((aFactory->SupportedDrives()&(~KPluginVersionTwo)));
    71 			}
    72 		
    73 		if(!(aPlugin->iMountedOn &(~KPluginVersionTwo))) 
    74 			{ //Are we mounted on anything?
    75 			return KErrNotSupported;
    76 			}
    77 		return KErrNone;
    78 		}
    79 	
    80 	// DriveZ special handling
    81 	if(aDrive==KPluginMountDriveZ)
    82 		aDrive = EDriveZ;
    83 	
    84 	//Mounting on a single drive
    85 	if(!IsPagableDrive(aDrive))
    86 		{
    87 		aPlugin->iMountedOn |= 1<<aDrive;
    88 		return KErrNone;
    89 		}
    90 
    91 	return KErrNotSupported;
    92 	}
    93 
    94 /**
    95 FsPluginManager::Initialise
    96 */
    97 void FsPluginManager::InitialiseL()
    98 	{
    99 	iPluginFactories = TheContainer->CreateL();
   100 	iPluginConns = TheContainer->CreateL();
   101 	iPluginChain.Reset();
   102 	User::LeaveIfError(iChainLock.CreateLocal());
   103 
   104 	// Create and install the synchronous message scheduler
   105 	//  - Messages are dispatched here from plugin threads if they are
   106 	//	  to be executed in the context of the main file server thread.
   107 	iScheduler = CFsSyncMessageScheduler::NewL();
   108 	iScheduler->RunL();
   109 	}
   110 
   111 /**
   112 FsPluginManager::MountPlugin
   113 */
   114 TInt FsPluginManager::MountPlugin(CFsPluginFactory& aPluginFactory, TInt aDrive, TInt aPos)
   115 	{
   116 	TInt uniquePosition = aPluginFactory.UniquePosition();
   117 	CFsPlugin* pP = NULL;
   118 	CFsPluginFactory* pF = &aPluginFactory;
   119 	
   120 	//Version1 plugins could either been mounted on 1 or all drives.
   121 	//This isn't particularily desirable.
   122 	// Thus -
   123 	//For version2 plugins:
   124 	//Check whether this plugin has already been mounted
   125 	pP = FindByUniquePosition(uniquePosition);
   126 	if(pP && (aPluginFactory.iSupportedDrives&KPluginVersionTwo))
   127 		{
   128 		//if this plugin has already been mounted then 
   129 		//Instead of trying to mount and failing with KErrInUse,
   130 		//lets update the iMountedOn instead.
   131 		return UpdateMountedDrive(pP,pF,aDrive);
   132 		}
   133 	
   134 	
   135 	TRAPD(err, pP = aPluginFactory.NewPluginL());
   136 	if(err != KErrNone)
   137 		{
   138 		if(pP)
   139 			pP->Close();
   140 		return err;
   141 		}
   142 
   143 	TFullName name = aPluginFactory.Name();
   144 	pP->SetName(&name);
   145 	pP->iUniquePos=aPluginFactory.UniquePosition();
   146 	pP->SetDrive(aDrive);
   147 	
   148 	//Set which drive(s?) this plugin is mounted on.
   149 	err = UpdateMountedDrive(pP,pF,aDrive);
   150 	if(err != KErrNone)
   151 		{
   152 		pP->Close();
   153 		return err;
   154 		}
   155 
   156 	LockChain();
   157 	err = InsertInPluginStack(pP,aPos);
   158 	UnlockChain();
   159 	if(err != KErrNone)
   160 		{
   161 		pP->Close();
   162 		return err;
   163 		}
   164 
   165 	err = InitPlugin(*pP);
   166 	if(err != KErrNone)
   167 		{
   168 		return err;
   169 		}
   170  	aPluginFactory.IncrementMounted();
   171 
   172 	return KErrNone;
   173 	}
   174 
   175 /**
   176 Dismounts a plugin
   177 
   178 Must be called with the plugin chain locked.
   179 */
   180 void FsPluginManager::DismountPlugin(CFsPluginFactory& aPluginFactory,TInt aPos)
   181 	{
   182 	CFsPlugin* plugin=iPluginChain[aPos];
   183 
   184 	if (plugin != NULL)
   185 		{
   186 		// Check if there is any requests for this plugin
   187 		// if so, deliver them to the next supporting plugin
   188 		TransferRequests(plugin->iThreadP);
   189 
   190 		plugin->iThreadP=NULL;
   191 		
   192 		//Remove the plugin from the chain
   193 		iPluginChain.Remove(aPos);
   194 		iPluginChain.Compress();
   195 
   196 	    //Close the plugin (destructed when CPluginThread is destructed).
   197  		plugin->Close();
   198 		plugin=NULL;
   199 		}
   200 	else
   201 		{
   202 		ASSERT(0);	// force panic in debug mode
   203 		}
   204 
   205 	aPluginFactory.DecrementMounted();
   206 	}
   207 
   208 /*
   209  * This will iterate through a plugins request queue and 
   210  * search for the first occurance it finds of a CancelPluginOp
   211  * request.
   212  */
   213 void FsPluginManager::GetNextCancelPluginOpRequest(CPluginThread* aPluginThread, CFsRequest*& aCancelPluginRequest)
   214     {
   215     __THRD_PRINT(_L("FsPluginManager::GetNextCancelPluginOpRequest"));
   216     
   217     TDblQueIter<CFsRequest> iter(aPluginThread->iList);
   218     CFsRequest* request = NULL;
   219 
   220     while((request=iter++)!=NULL)
   221         {
   222         if(request->Operation()->iFunction == KCancelPlugin)
   223             {
   224             aCancelPluginRequest = request;
   225             break;
   226             }
   227         }
   228     }
   229  
   230 
   231 
   232 
   233 
   234 /**
   235 Transfer any outstanding requests to next/previous plugin depending on
   236 if it is post filter or not
   237 
   238 Must be called with the plugin chain locked.
   239 Attains plugin-thread's listlock.
   240 */
   241 void FsPluginManager::TransferRequests(CPluginThread* aPluginThread)
   242 	{
   243 	aPluginThread->iListLock.Wait();
   244 	
   245 	__THRD_PRINT(_L("FsPluginManager::TransferRequests - moving requests"));
   246 	
   247 	/*
   248 	 * We are transferring requests up and down the chain
   249 	 * because this plugin is being removed.
   250 	 * 
   251 	 * There is a potential problem when one of the outstanding requests
   252 	 * is CancelPluginOp which is called when the Session is being closed.
   253 	 * The CancelPluginOp will try to cancel all of the requests on a plugin's
   254 	 * queue which is associated with that session.
   255 	 * DismountPlugin(and thus TransferRequests) is trying to preserve the requests
   256 	 * by passing them along to the Next/Previous plugins. 
   257 	 * 
   258 	 * If there is a cancel in the chain we must NOT pass any requests to Previous Plugins 
   259 	 * as these have already had their chains emptied.
   260 	 * We should also be wary of passing requests up the chain as they will simply be cancelled 
   261 	 * somewhere closer to the drive [thread].
   262 	 * 
   263 	 * Therefore, we shall check whether there is a KCancelPlugin op in the 
   264 	 * chain first. 
   265      * If there is a cancelPluginOp in the chain, we will cancel of the requests 
   266      * that are associated with that session.
   267      * 
   268      * After that is out of the way we preserve the remaining requests for different sessions by
   269      * passing them on.
   270 	 */
   271 	if(!aPluginThread->iList.IsEmpty())
   272 	    {
   273 	    CFsRequest* cancelRequest = NULL;
   274 	    //For every CancelPluginOp 
   275 	    while(FsPluginManager::GetNextCancelPluginOpRequest(aPluginThread, cancelRequest), cancelRequest!=NULL)
   276 	        {
   277 	        RDebug::Print(_L("Transferring Plugin Requests - CancelPluginOp"));
   278 	        TDblQueIter<CFsRequest> iter(aPluginThread->iList);
   279 	        CFsRequest* request = NULL;
   280 	        //For every request
   281 	        while((request=iter++)!=NULL)
   282 	            {
   283 	            if(request->Session() == cancelRequest->Session() && request != cancelRequest)
   284 	                {
   285 	                request->iLink.Deque();
   286 	                request->Complete(KErrCancel);
   287 	                }
   288 	            }
   289 	        cancelRequest->iLink.Deque();
   290 	        cancelRequest->Complete(KErrNone);
   291 	        cancelRequest = NULL;
   292 	        }
   293 
   294 	    /*
   295 	     * Now that all requests that were to be cancelled have been cancelled,
   296 	     * we can now go about moving the remaining ones on to , or back to, 
   297 	     * the appropriate next or previous plugins.
   298 	     * 
   299 	     * ToDo: This next 'while' might be able to be replaced with a call to
   300 	     * DispatchToPlugin/DispatchToDrive instead.
   301 	     */
   302 	    while(!aPluginThread->iList.IsEmpty())
   303 	        {
   304 	        CFsRequest* pR=aPluginThread->iList.First();
   305 	        CFsMessageRequest& mR = *(CFsMessageRequest*) pR;
   306 	        pR->iLink.Deque();
   307 	        pR->iCurrentPlugin=NULL;
   308 
   309 	        if(pR->IsPluginSpecific())
   310 	            {
   311 	            pR->Complete(KErrCancel);
   312 	            continue;
   313 	            }
   314 
   315 	        if(pR->IsPostOperation())
   316 	            {
   317 	            //[set the plugin to] pass the request backwards in the chain
   318 	            PrevPlugin(pR->iCurrentPlugin, &mR, EFalse);
   319 	            }
   320 	        else //IsPreOperations
   321 	            {
   322 	            //[set the plugin to] pass the request forwards in the chain
   323 	            NextPlugin(pR->iCurrentPlugin, &mR, EFalse);
   324 	            }
   325 
   326 	        if(pR->iCurrentPlugin)
   327 	            {
   328 	            pR->iCurrentPlugin->iThreadP->DeliverBack(pR);
   329 	            }
   330 	        else
   331 	            {
   332 	            if(!pR->IsPostOperation() && (pR->DriveNumber()>=EDriveA && pR->DriveNumber()<=EDriveZ))
   333 	                {
   334 	                //Deliver to drive thread
   335 	                CDriveThread* dT=NULL;
   336 	                TInt r=FsThreadManager::GetDriveThread(pR->DriveNumber(),&dT);
   337 	                __ASSERT_ALWAYS(r==KErrNone && dT,Fault(EFsDriveThreadError));
   338 	                CRequestThread* pT = (CRequestThread*)dT;
   339 	                pT->DeliverBack(pR);
   340 	                }
   341 	            else
   342 	                {
   343 	                pR->Complete(KErrCancel);
   344 	                }
   345 	            }
   346 	        }
   347 	    }
   348 
   349 	aPluginThread->iExit = ETrue;
   350 	aPluginThread->iListLock.Signal();
   351 
   352 	__THRD_PRINT(_L("FsPluginManager::TransferRequests - all requests moved/cancelled"));
   353 	}
   354 
   355 /**
   356 Install a plugin factory
   357 */
   358 TInt FsPluginManager::InstallPluginFactory(CFsPluginFactory* aFactory,RLibrary aLib)
   359 	{
   360 	TInt r=aFactory->Install();
   361 	__PRINT1TEMP(_L("InstallPluginFactory %S"),aFactory->Name());
   362 	if (r==KErrNone)
   363 		{TRAP(r,iPluginFactories->AddL(aFactory,ETrue))}
   364 	if (r!=KErrNone)
   365 		aFactory->Remove();
   366 	if (r==KErrNone)
   367 		aFactory->SetLibrary(aLib);
   368 	else
   369 		aFactory->Close();
   370 	return(r);
   371 	}
   372 
   373 /**
   374 Find a plugin factory by name
   375 */
   376 CFsPluginFactory* FsPluginManager::GetPluginFactory(const TDesC& aName)
   377 	{
   378 
   379 	TInt h=0;
   380 	TInt r=iPluginFactories->FindByName(h,aName);
   381 	if (r!=KErrNone)
   382 		return(NULL);
   383 	return((CFsPluginFactory*)iPluginFactories->At(h));
   384 	}
   385 
   386 /**
   387 Find the next plugin that supports the operation
   388 
   389 @param aPlugin - On calling the function this may contain either NULL or the current plugin.
   390                  If it is called with NULL, then we start to look for plugins from the beginning of the chain.
   391                  If is is called with a plugin then we start to look after that plugin for the next one.
   392                  On return, aPlugin shall contain either a plugin or NULL.
   393                  
   394 @param aLock - If this is set to ETRUE, then the function shall lock the plugin chain.
   395                If this is set to EFALSE, then the caller of the function MUST already hold the lock.
   396 
   397 @param aCheckCurrentOperation - Optional, if false, will return the next plugin,
   398  								whether the plugin is currently registered
   399 								for the current function or not. (so long as mounted on the current drive)
   400 */
   401 TInt FsPluginManager::NextPlugin(CFsPlugin*& aPlugin, CFsMessageRequest* aMsgRequest,TBool aLock, TBool aCheckCurrentOperation)
   402 	{
   403 	if(aMsgRequest->DirectToDrive())
   404 		{
   405 		aPlugin = NULL;
   406 		return KErrNotFound;
   407 		}
   408 
   409 	TInt start;
   410 	TInt function = aMsgRequest->Operation()->Function();
   411 	TInt drive = aMsgRequest->DriveNumber();
   412 
   413 	if(aLock)
   414 	    LockChain();
   415 	
   416 	//the plugin chain lock must be held by this point.
   417 	TInt count = iPluginChain.Count();
   418 
   419 	if(aPlugin == NULL)
   420 		start=0;
   421 	else
   422 		start = iPluginChain.Find(aPlugin)+1;
   423 
   424 	if(start!=KErrNotFound)
   425 		{
   426 		for(TInt i=start;i<count;i++)
   427 			{
   428 			if(!aCheckCurrentOperation || iPluginChain[i]->IsRegistered(function, CFsPlugin::EPreIntercept))
   429 				{
   430 				if((function == EFsDismountPlugin) || (iPluginChain[i]->IsMounted(drive))) 
   431 					{
   432 
   433 					aPlugin = iPluginChain[i];
   434 					if(aLock)
   435 					    UnlockChain();
   436 					return KErrNone;
   437 					}
   438 				}
   439 			}
   440 		}
   441 	aPlugin = NULL;
   442 	if(aLock)
   443 	    UnlockChain();
   444 	return KErrNotFound;
   445 	}
   446 
   447 /**
   448 Find the next plugin that supports the operation
   449 
   450 @see FsPluginManager::NextPlugin
   451 */
   452 TInt FsPluginManager::PrevPlugin(CFsPlugin*& aPlugin, CFsMessageRequest* aMsgRequest, TBool aLock)
   453 	{
   454 	if(aMsgRequest->DirectToDrive() && (aMsgRequest->CurrentOperationPtr() != NULL))
   455 		{
   456 		aPlugin = NULL;
   457 		return KErrNotFound;
   458 		}
   459 
   460 	TInt start;
   461 	TInt function = aMsgRequest->Operation()->Function();
   462 	TInt drive = aMsgRequest->DriveNumber();
   463 
   464 	if(aLock)
   465 	    LockChain();
   466 	
   467 	//the plugin chain lock must be held by this point.
   468 	TInt count= iPluginChain.Count();
   469 
   470 	if(aPlugin == NULL)
   471 		start = count-1;
   472 	else
   473 		start = iPluginChain.Find(aPlugin)-1;
   474 
   475 	if(start!=KErrNotFound)
   476 		{
   477 		for(TInt i=start;i>=0;i--)
   478 			{
   479 			CFsPlugin* owner = aMsgRequest->iOwnerPlugin;
   480 			if(owner == iPluginChain[i])
   481 				break;
   482 
   483 			if(iPluginChain[i]->IsRegistered(function, CFsPlugin::EPostIntercept))
   484 				{
   485 				if((function == EFsDismountPlugin) || (iPluginChain[i]->IsMounted(drive))) 
   486 					{
   487 
   488 					aPlugin = iPluginChain[i];
   489 					if(aLock)
   490 					    UnlockChain();
   491 					return KErrNone;
   492 					}
   493 				}
   494 			}
   495 		}
   496 	aPlugin = NULL;
   497 	if(aLock)
   498 	    UnlockChain();
   499 	return KErrNotFound;
   500 	}
   501 /**
   502 Inserts the plugin in the stack (chain)
   503 
   504 if aPos absolute postion, it simply inserts it
   505 if aPos unique position, it walks through chain and checks the unique positions
   506 */
   507 TInt FsPluginManager::InsertInPluginStack(CFsPlugin*& aPlugin,TInt aPos)
   508 	{
   509 	TInt ret=KErrNone;
   510 	TInt count= iPluginChain.Count();
   511 	if(aPos == KPluginAutoLocate)
   512 		{
   513 		TInt uPos= aPlugin->iUniquePos;
   514 		for(TInt i=0;i<count;i++)
   515 			{
   516 			if(uPos == iPluginChain[i]->iUniquePos)
   517 				{
   518 				return KErrInUse;
   519 				}
   520 
   521 			if(uPos < iPluginChain[i]->iUniquePos)
   522 				{
   523 				ret=iPluginChain.Insert(aPlugin,i);
   524 				return ret;
   525 				}
   526 			}
   527 		ret=iPluginChain.Append(aPlugin);
   528 		}
   529 	else
   530 		{
   531 		// Absolute position
   532 
   533 		if(aPos > count)
   534 			return(KErrNotFound);
   535 		if(aPos == count)
   536 			{
   537 			ret=iPluginChain.Append(aPlugin);
   538 			return ret;
   539 			}
   540 		ret=iPluginChain.Insert(aPlugin,aPos);
   541 		}
   542 	return ret;
   543 	}
   544 
   545 /**
   546 Looks for a plugin in the chain
   547 */
   548 TInt FsPluginManager::IsInChain(TInt aUPos,TInt aPos, TInt aDrive, CFsPluginFactory* aPluginFactory)
   549 	{
   550 	TInt count= iPluginChain.Count();
   551 	
   552 	if(aPos == KPluginAutoLocate)
   553 		{
   554 		for(TInt i=0;i<count;i++)
   555 			{
   556 			CFsPlugin* pP = iPluginChain[i];
   557 			if(aPluginFactory->SupportedDrives()&KPluginVersionTwo) //Version2
   558 				{
   559 				//If KPluginAutoAttach, then we're dismounted from all drives.
   560 				//If KPluginMountDriveZ, then check against 25 explicitly (cannot change aDrive:=Z as that==KPluginAutoAttach))
   561 				//If any other drive mounted.
   562 				if(aUPos == pP->iUniquePos && (aDrive==KPluginAutoAttach || (aDrive==KPluginMountDriveZ && pP->iMountedOn & (1<<EDriveZ)) || pP->iMountedOn & (1<<aDrive)))
   563 					return i;
   564 				}
   565 			else //version1
   566 				{
   567 				if(aUPos == pP->iUniquePos && (aDrive==KPluginAutoAttach || pP->iMountedOn & (1<<aDrive)))
   568 					return i;
   569 				}
   570 			}
   571 		return KErrNotFound;
   572 		}
   573 
   574 	if(aPos+1>iPluginChain.Count())
   575 		return(KErrNotFound);
   576 
   577 	if(iPluginChain[aPos]->iUniquePos == aUPos && aDrive==iPluginChain[aPos]->Drive())
   578 		return aPos;
   579 	return KErrNotFound;
   580 	}
   581 
   582 /**
   583 Finds a plugin by unique position
   584 */
   585 CFsPlugin* FsPluginManager::FindByUniquePosition(TInt aUniquePosition)
   586 	{
   587 	LockChain();
   588 	CFsPlugin* plugin = NULL;
   589 	TInt count= iPluginChain.Count();
   590 	for(TInt i=0;i<count;i++)
   591 		{
   592 		if(aUniquePosition == iPluginChain[i]->iUniquePos)
   593 			{
   594 			plugin = iPluginChain[i];
   595 			break;
   596 			}
   597 		}
   598 	UnlockChain();
   599 	return plugin;
   600 	}
   601 
   602 /**
   603 Create a connection to a plugin
   604 */
   605 CFsPluginConn* FsPluginManager::CreatePluginConnL(TInt aUniquePosition, TUint aClientId)
   606 	{
   607 	CFsPlugin* pP = FindByUniquePosition(aUniquePosition);
   608 	if(pP != NULL)
   609 		{
   610 		CFsPluginConn* pC = pP->NewPluginConnL();
   611 		CleanupStack::PushL(pC);
   612 		pC->iPluginP = pP;
   613 		pC->iClientId = aClientId;
   614 		iPluginConns->AddL(pC, ETrue);
   615 		CleanupStack::Pop(pC);
   616 		return pC;
   617 		}
   618 
   619 	User::Leave(KErrNotFound);
   620 	return NULL;
   621 	}
   622 
   623 /**
   624 Create a plugin thread
   625 Should only by called from main file server thread with plugin thread unavailable
   626 */
   627 TInt FsPluginManager::InitPlugin(CFsPlugin& aPlugin)
   628 	{
   629 	TInt err = KErrNone;
   630 
   631 	if(!aPlugin.iThreadP)
   632 		{
   633 		TRAP(err,aPlugin.iThreadP=CPluginThread::NewL(aPlugin));
   634 		if(err!=KErrNone)
   635 			return err;
   636 		}
   637 
   638 	aPlugin.iThreadId = aPlugin.iThreadP->StartL();
   639 	return err;
   640 	}
   641 /**
   642 Cancels plugin requests
   643 */
   644 void FsPluginManager::CancelPlugin(CFsPlugin* aPlugin,CSessionFs* aSession)
   645 	{
   646 	aPlugin->iThreadP->CompleteSessionRequests(aSession,KErrCancel);
   647 	}
   648 
   649 /**
   650 Gets number of plugins in the plugin stack
   651 */
   652 TInt FsPluginManager::ChainCount()
   653 	{
   654 	return(iPluginChain.Count());
   655 	}
   656 
   657 /**
   658  * Returns a CFsPlugin* from aPos in the plugin chain.
   659  * 
   660  * To be called whilst already holding the iChainLock.
   661  * 
   662  * @returns (via parameter) CFsPlugin*& aPlugin
   663 */
   664 TInt FsPluginManager::Plugin(CFsPlugin*& aPlugin, TInt aPos)
   665 	{
   666 	if(aPos >= iPluginChain.Count() || aPos < 0)
   667 	    return KErrNotFound;
   668 	
   669 	aPlugin = iPluginChain[aPos];
   670 	return KErrNone;
   671 	}
   672 
   673 /**
   674 Locks the chain
   675 */
   676 void FsPluginManager::LockChain()
   677 	{
   678 	iChainLock.Wait();
   679 	}
   680 
   681 /**
   682 Unlocks the chain
   683 */
   684 void FsPluginManager::UnlockChain()
   685 	{
   686 	iChainLock.Signal();
   687 	}
   688 
   689 /**
   690 Gets plugin conn from handle
   691 */
   692 CFsPluginConn* FsPluginManager::GetPluginConnFromHandle(CSessionFs* aSession, TInt aHandle)
   693 	{
   694 	return((CFsPluginConn*)(SessionObjectFromHandle(aHandle,iPluginConns->UniqueID(),aSession)));
   695 	}
   696 
   697 /**
   698 Checks if the current thread is plugin conn's thread
   699 */
   700 TBool FsPluginManager::IsPluginConnThread(TThreadId tid, CFsPlugin* aPlugin)
   701 	{
   702 	iPluginConns->Lock();
   703 	TInt count = iPluginConns->Count();
   704 	while(count--)
   705 		{
   706 		CFsPluginConn* conn = (CFsPluginConn*)(*iPluginConns)[count];
   707 		if(conn->Plugin() == aPlugin)
   708 			{
   709 			if(conn->ClientId() == tid)
   710 				{
   711 				iPluginConns->Unlock();
   712 				return ETrue;
   713 				}
   714 			}
   715 		}
   716 	iPluginConns->Unlock();
   717 	return EFalse;
   718 	}
   719 
   720 /**
   721 Dispatch a synchronous message
   722 */
   723 void FsPluginManager::DispatchSync(CFsRequest* aRequest)
   724 	{
   725 	__THRD_PRINT(_L("FsPluginManager::DispatchSync"));
   726 	if(!FsThreadManager::IsMainThread() && iScheduler)
   727 		{
   728 		iScheduler->Dispatch(aRequest);
   729 		}
   730 	else
   731 		{
   732 		aRequest->Process();
   733 		}
   734 	}
   735 
   736 void FsPluginManager::CompleteSessionRequests(CSessionFs* aSession, TInt aValue, CFsInternalRequest* aRequest)
   737 /**
   738  * Complete outstanding requests for the specified session
   739  */
   740 	{
   741 	__PRINT2(_L("FsPluginManager::CompleteSessionRequests(%08x, %d)"), aSession, aValue);
   742 
   743 	// Iterate through all plugins, cancelling outstanding session requests
   744 	aRequest->Set(CancelPluginOp, aSession);
   745 
   746 	FsPluginManager::LockChain();
   747 	TInt count = FsPluginManager::ChainCount();
   748 	TInt i;
   749 	for(i=0; i<count; i++)
   750 	    {
   751 	    CFsPlugin* plugin = NULL;
   752 	    User::LeaveIfError(FsPluginManager::Plugin(plugin, i));
   753 	    __ASSERT_DEBUG(plugin, User::Leave(KErrNotFound));
   754 	    aRequest->iCurrentPlugin = plugin;
   755 	    aRequest->Status() = KRequestPending;
   756 	    aRequest->Dispatch();
   757 	    //Cancel is delivered to the front of the request queue
   758 	    //so hopefully this wont take too long.
   759 	    FsPluginManager::UnlockChain();
   760 	    User::WaitForRequest(aRequest->Status());
   761 	    FsPluginManager::LockChain();
   762 	    __ASSERT_ALWAYS(aRequest->Status().Int()==KErrNone||aRequest->Status().Int()==KErrCancel,Fault(ESessionDisconnectThread2));
   763 	    count = FsPluginManager::ChainCount();
   764 	    }
   765 	FsPluginManager::UnlockChain();
   766 	
   767 //	RDebug::Print(_L("FsPluginManager::CompleteSessionRequests - CSRs"));
   768 	iScheduler->CompleteSessionRequests(aSession, aValue);
   769 	}
   770 
   771