userlibandfileserver/fileserver/sfile/sf_plugin_man.cpp
changeset 0 a41df078684a
child 2 4122176ea935
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/userlibandfileserver/fileserver/sfile/sf_plugin_man.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,755 @@
+// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// f32\sfile\sf_plugin.cpp
+// 
+//
+
+#include <e32std.h>
+#include "sf_std.h"
+#include "sf_plugin_priv.h"
+
+CFsObjectCon* FsPluginManager::iPluginFactories = NULL;
+CFsObjectCon* FsPluginManager::iPluginConns     = NULL;
+RFastLock FsPluginManager::iChainLock;
+RPointerArray<CFsPlugin> FsPluginManager::iPluginChain;
+CFsSyncMessageScheduler* FsPluginManager::iScheduler = NULL;
+
+TBool IsPagableDrive(TInt aDrive)
+	{
+	if(LocalDrives::IsValidDriveMapping(aDrive))
+		{
+		TLocalDriveCapsBuf capsBuf;	
+		if(!LocalDrives::IsProxyDrive(aDrive) && LocalDrives::GetLocalDrive(aDrive).Caps(capsBuf) && capsBuf().iDriveAtt & KDriveAttPageable)
+			{
+			return (TBool)ETrue;
+			}
+		}
+	return (TBool) EFalse;
+	}
+
+/*
+@param aNonPagableDriveMask - a drive mask of the drives a plugin wishes to mount on
+@return A drive mask of the drives a plugin wishes to mount on not containing any pagable drives.
+*/
+TInt NonPagableDrivesMask(TInt aNonPagableDriveMask)
+	{
+	TInt driveMask = aNonPagableDriveMask;
+	for(TInt i = 0; i < KMaxDrives; i++)
+		{
+		//If we're interested in this drive
+		if((aNonPagableDriveMask & 1<<i) && IsPagableDrive(i)) 
+			{
+			driveMask ^= 1<<i; //remove this drive
+			}
+		}
+	return driveMask;
+	}
+
+TInt FsPluginManager::UpdateMountedDrive(CFsPlugin* aPlugin, CFsPluginFactory* aFactory,TInt aDrive)
+	{
+	if(aDrive==KPluginAutoAttach) //KPluginAutoAttach
+		{
+		if(!(aFactory->SupportedDrives()&KPluginVersionTwo)) 
+			{ //Version 1 Plugin - Mount on all (except Z and pagble drives) 
+			TInt drivesAToY = (KPluginSupportAllDrives>>1);
+			aPlugin->iMountedOn = NonPagableDrivesMask(drivesAToY);
+			}
+		else 
+			{ //Version 2 Plugin - Mount on what the plugin supports (except pagable drives)
+			aPlugin->iMountedOn = NonPagableDrivesMask((aFactory->SupportedDrives()&(~KPluginVersionTwo)));
+			}
+		
+		if(!(aPlugin->iMountedOn &(~KPluginVersionTwo))) 
+			{ //Are we mounted on anything?
+			return KErrNotSupported;
+			}
+		return KErrNone;
+		}
+	
+	// DriveZ special handling
+	if(aDrive==KPluginMountDriveZ)
+		aDrive = EDriveZ;
+	
+	//Mounting on a single drive
+	if(!IsPagableDrive(aDrive))
+		{
+		aPlugin->iMountedOn |= 1<<aDrive;
+		return KErrNone;
+		}
+
+	return KErrNotSupported;
+	}
+
+/**
+FsPluginManager::Initialise
+*/
+void FsPluginManager::InitialiseL()
+	{
+	iPluginFactories = TheContainer->CreateL();
+	iPluginConns = TheContainer->CreateL();
+	iPluginChain.Reset();
+	User::LeaveIfError(iChainLock.CreateLocal());
+
+	// Create and install the synchronous message scheduler
+	//  - Messages are dispatched here from plugin threads if they are
+	//	  to be executed in the context of the main file server thread.
+	iScheduler = CFsSyncMessageScheduler::NewL();
+	iScheduler->RunL();
+	}
+
+/**
+FsPluginManager::MountPlugin
+*/
+TInt FsPluginManager::MountPlugin(CFsPluginFactory& aPluginFactory, TInt aDrive, TInt aPos)
+	{
+	TInt uniquePosition = aPluginFactory.UniquePosition();
+	CFsPlugin* pP = NULL;
+	CFsPluginFactory* pF = &aPluginFactory;
+	
+	//Version1 plugins could either been mounted on 1 or all drives.
+	//This isn't particularily desirable.
+	// Thus -
+	//For version2 plugins:
+	//Check whether this plugin has already been mounted
+	pP = FindByUniquePosition(uniquePosition);
+	if(pP && (aPluginFactory.iSupportedDrives&KPluginVersionTwo))
+		{
+		//if this plugin has already been mounted then 
+		//Instead of trying to mount and failing with KErrInUse,
+		//lets update the iMountedOn instead.
+		return UpdateMountedDrive(pP,pF,aDrive);
+		}
+	
+	
+	TRAPD(err, pP = aPluginFactory.NewPluginL());
+	if(err != KErrNone)
+		{
+		if(pP)
+			pP->Close();
+		return err;
+		}
+
+	TFullName name = aPluginFactory.Name();
+	pP->SetName(&name);
+	pP->iUniquePos=aPluginFactory.UniquePosition();
+	pP->SetDrive(aDrive);
+	
+	//Set which drive(s?) this plugin is mounted on.
+	err = UpdateMountedDrive(pP,pF,aDrive);
+	if(err != KErrNone)
+		{
+		pP->Close();
+		return err;
+		}
+
+	LockChain();
+	err = InsertInPluginStack(pP,aPos);
+	UnlockChain();
+	if(err != KErrNone)
+		{
+		pP->Close();
+		return err;
+		}
+
+	err = InitPlugin(*pP);
+	if(err != KErrNone)
+		{
+		pP->Close();
+		return err;
+		}
+ 	aPluginFactory.IncrementMounted();
+
+	return KErrNone;
+	}
+
+/**
+Dismounts a plugin
+Must be called with the plugin chain locked.
+*/
+void FsPluginManager::DismountPlugin(CFsPluginFactory& aPluginFactory,TInt aPos)
+	{
+	CFsPlugin* plugin=iPluginChain[aPos];
+
+	if (plugin != NULL)
+		{
+		// Check if there is any requests for this plugin
+		// if so, deliver them to the next supporting plugin
+		TransferRequests(plugin->iThreadP);
+
+		plugin->iThreadP=NULL;
+
+		iPluginChain.Remove(aPos);
+		iPluginChain.Compress();
+
+		//Need this to remove it from container
+		//plugin->Close() deletes plugin.
+ 		plugin->Close();
+		plugin=NULL;
+		}
+	else
+		{
+		ASSERT(0);	// force panic in debug mode
+		}
+
+	aPluginFactory.DecrementMounted();
+	}
+
+/*
+ * This will iterate through a plugins request queue and 
+ * search for the first occurance it finds of a CancelPluginOp
+ * request.
+ */
+void FsPluginManager::GetNextCancelPluginOpRequest(CPluginThread* aPluginThread, CFsRequest*& aCancelPluginRequest)
+    {
+    __THRD_PRINT(_L("FsPluginManager::GetNextCancelPluginOpRequest"));
+    
+    TDblQueIter<CFsRequest> iter(aPluginThread->iList);
+    CFsRequest* request = NULL;
+
+    while((request=iter++)!=NULL)
+        {
+        if(request->Operation()->iFunction == KCancelPlugin)
+            {
+            aCancelPluginRequest = request;
+            break;
+            }
+        }
+    }
+ 
+
+
+
+
+/**
+Transfer any outstanding requests to next/previous plugin depending on
+if it is post filter or not
+*/
+void FsPluginManager::TransferRequests(CPluginThread* aPluginThread)
+	{
+	aPluginThread->iListLock.Wait();
+	
+	__THRD_PRINT(_L("FsPluginManager::TransferRequests - moving requests"));
+	
+	/*
+	 * We are transferring requests up and down the chain
+	 * because this plugin is being removed.
+	 * 
+	 * There is a potential problem when one of the outstanding requests
+	 * is CancelPluginOp which is called when the Session is being closed.
+	 * The CancelPluginOp will try to cancel all of the requests on a plugin's
+	 * queue which is associated with that session.
+	 * DismountPlugin(and thus TransferRequests) is trying to preserve the requests
+	 * by passing them along to the Next/Previous plugins. 
+	 * 
+	 * If there is a cancel in the chain we must NOT pass any requests to Previous Plugins 
+	 * as these have already had their chains emptied.
+	 * We should also be wary of passing requests up the chain as they will simply be cancelled 
+	 * somewhere closer to the drive [thread].
+	 * 
+	 * Therefore, we shall check whether there is a KCancelPlugin op in the 
+	 * chain first. 
+     * If there is a cancelPluginOp in the chain, we will cancel of the requests 
+     * that are associated with that session.
+     * 
+     * After that is out of the way we preserve the remaining requests for different sessions by
+     * passing them on.
+	 */
+	if(!aPluginThread->iList.IsEmpty())
+	    {
+	    CFsRequest* cancelRequest = NULL;
+	    //For every CancelPluginOp 
+	    while(FsPluginManager::GetNextCancelPluginOpRequest(aPluginThread, cancelRequest), cancelRequest!=NULL)
+	        {
+	        RDebug::Print(_L("Transferring Plugin Requests - CancelPluginOp"));
+	        TDblQueIter<CFsRequest> iter(aPluginThread->iList);
+	        CFsRequest* request = NULL;
+	        //For every request
+	        while((request=iter++)!=NULL)
+	            {
+	            if(request->Session() == cancelRequest->Session() && request != cancelRequest)
+	                {
+	                request->iLink.Deque();
+	                request->Complete(KErrCancel);
+	                }
+	            }
+	        cancelRequest->iLink.Deque();
+	        cancelRequest->Complete(KErrNone);
+	        cancelRequest = NULL;
+	        }
+
+	    /*
+	     * Now that all requests that were to be cancelled have been cancelled,
+	     * we can now go about moving the remaining ones on to , or back to, 
+	     * the appropriate next or previous plugins.
+	     * 
+	     * ToDo: This next 'while' might be able to be replaced with a call to
+	     * DispatchToPlugin/DispatchToDrive instead.
+	     */
+	    while(!aPluginThread->iList.IsEmpty())
+	        {
+	        CFsRequest* pR=aPluginThread->iList.First();
+	        CFsMessageRequest& mR = *(CFsMessageRequest*) pR;
+	        pR->iLink.Deque();
+	        pR->iCurrentPlugin=NULL;
+
+	        if(pR->IsPluginSpecific())
+	            {
+	            pR->Complete(KErrCancel);
+	            continue;
+	            }
+
+	        if(pR->IsPostOperation())
+	            {
+	            //[set the plugin to] pass the request backwards in the chain
+	            PrevPlugin(pR->iCurrentPlugin, &mR, EFalse);
+	            }
+	        else //IsPreOperations
+	            {
+	            //[set the plugin to] pass the request forwards in the chain
+	            NextPlugin(pR->iCurrentPlugin, &mR, EFalse);
+	            }
+
+	        if(pR->iCurrentPlugin)
+	            {
+	            pR->iCurrentPlugin->iThreadP->DeliverBack(pR);
+	            }
+	        else
+	            {
+	            if(!pR->IsPostOperation() && (pR->DriveNumber()>=EDriveA && pR->DriveNumber()<=EDriveZ))
+	                {
+	                //Deliver to drive thread
+	                CDriveThread* dT=NULL;
+	                TInt r=FsThreadManager::GetDriveThread(pR->DriveNumber(),&dT);
+	                __ASSERT_ALWAYS(r==KErrNone && dT,Fault(EFsDriveThreadError));
+	                CRequestThread* pT = (CRequestThread*)dT;
+	                pT->DeliverBack(pR);
+	                }
+	            else
+	                {
+	                pR->Complete(KErrCancel);
+	                }
+	            }
+	        }
+	    }
+
+	aPluginThread->iExit = ETrue;
+	aPluginThread->iListLock.Signal();
+
+	__THRD_PRINT(_L("FsPluginManager::TransferRequests - all requests moved/cancelled"));
+	}
+
+/**
+Install a plugin factory
+*/
+TInt FsPluginManager::InstallPluginFactory(CFsPluginFactory* aFactory,RLibrary aLib)
+	{
+	TInt r=aFactory->Install();
+	__PRINT1TEMP(_L("InstallPluginFactory %S"),aFactory->Name());
+	if (r==KErrNone)
+		{TRAP(r,iPluginFactories->AddL(aFactory,ETrue))}
+	if (r!=KErrNone)
+		aFactory->Remove();
+	if (r==KErrNone)
+		aFactory->SetLibrary(aLib);
+	else
+		aFactory->Close();
+	return(r);
+	}
+
+/**
+Find a plugin factory by name
+*/
+CFsPluginFactory* FsPluginManager::GetPluginFactory(const TDesC& aName)
+	{
+
+	TInt h=0;
+	TInt r=iPluginFactories->FindByName(h,aName);
+	if (r!=KErrNone)
+		return(NULL);
+	return((CFsPluginFactory*)iPluginFactories->At(h));
+	}
+
+/**
+Find the next plugin that supports the operation
+@param aCheckCurrentOperation - Optional, if false, will return the next plugin,
+ 								whether the plugin is currently registered
+								for the current function of not. (so long as mounted on the current drive)
+*/
+TInt FsPluginManager::NextPlugin(CFsPlugin*& aPlugin, CFsMessageRequest* aMsgRequest,TBool aLock, TBool aCheckCurrentOperation)
+	{
+	if(aMsgRequest->DirectToDrive())
+		{
+		aPlugin = NULL;
+		return KErrNotFound;
+		}
+
+	TInt r = KErrNone;
+	TInt start;
+	TInt function = aMsgRequest->Operation()->Function();
+	TInt drive = aMsgRequest->DriveNumber();
+
+	if(aLock)
+	    LockChain();
+	
+	TInt count = iPluginChain.Count();
+
+	if(aPlugin == NULL)
+		start=0;
+	else
+		start = iPluginChain.Find(aPlugin)+1;
+
+	if(start!=KErrNotFound)
+		{
+		for(TInt i=start;i<count;i++)
+			{
+			if(!aCheckCurrentOperation || iPluginChain[i]->IsRegistered(function, CFsPlugin::EPreIntercept))
+				{
+				if((function == EFsDismountPlugin) || (iPluginChain[i]->IsMounted(drive))) 
+					{
+
+					aPlugin = iPluginChain[i];
+					if(aLock)
+					    UnlockChain();
+					return(r);
+					}
+				}
+			}
+		}
+	aPlugin = NULL;
+	if(aLock)
+	    UnlockChain();
+	return(KErrNotFound);
+	}
+
+/**
+Find the next plugin that supports the operation
+*/
+TInt FsPluginManager::PrevPlugin(CFsPlugin*& aPlugin, CFsMessageRequest* aMsgRequest, TBool aLock)
+	{
+	if(aMsgRequest->DirectToDrive() && (aMsgRequest->CurrentOperationPtr() != NULL))
+		{
+		aPlugin = NULL;
+		return KErrNotFound;
+		}
+
+	TInt r = KErrNone;
+	TInt start;
+	TInt function = aMsgRequest->Operation()->Function();
+	TInt drive = aMsgRequest->DriveNumber();
+
+	if(aLock)
+	    LockChain();
+	
+	TInt count= iPluginChain.Count();
+
+	if(aPlugin == NULL)
+		start = count-1;
+	else
+		start = iPluginChain.Find(aPlugin)-1;
+
+	if(start!=KErrNotFound)
+		{
+		for(TInt i=start;i>=0;i--)
+			{
+			CFsPlugin* owner = aMsgRequest->iOwnerPlugin;
+			if(owner == iPluginChain[i])
+				break;
+
+			if(iPluginChain[i]->IsRegistered(function, CFsPlugin::EPostIntercept))
+				{
+				if((function == EFsDismountPlugin) || (iPluginChain[i]->IsMounted(drive))) 
+					{
+
+					aPlugin = iPluginChain[i];
+					if(aLock)
+					    UnlockChain();
+					return(r);
+					}
+				}
+			}
+		}
+	aPlugin = NULL;
+	if(aLock)
+	    UnlockChain();
+	return(KErrNotFound);
+	}
+/**
+Inserts the plugin in the stack (chain)
+
+if aPos absolute postion, it simply inserts it
+if aPos unique position, it walks through chain and checks the unique positions
+*/
+TInt FsPluginManager::InsertInPluginStack(CFsPlugin*& aPlugin,TInt aPos)
+	{
+	TInt ret=KErrNone;
+	TInt count= iPluginChain.Count();
+	if(aPos == KPluginAutoLocate)
+		{
+		TInt uPos= aPlugin->iUniquePos;
+		for(TInt i=0;i<count;i++)
+			{
+			if(uPos == iPluginChain[i]->iUniquePos)
+				{
+				return KErrInUse;
+				}
+
+			if(uPos < iPluginChain[i]->iUniquePos)
+				{
+				ret=iPluginChain.Insert(aPlugin,i);
+				return ret;
+				}
+			}
+		ret=iPluginChain.Append(aPlugin);
+		}
+	else
+		{
+		// Absolute position
+
+		if(aPos > count)
+			return(KErrNotFound);
+		if(aPos == count)
+			{
+			ret=iPluginChain.Append(aPlugin);
+			return ret;
+			}
+		ret=iPluginChain.Insert(aPlugin,aPos);
+		}
+	return ret;
+	}
+
+/**
+Looks for a plugin in the chain
+*/
+TInt FsPluginManager::IsInChain(TInt aUPos,TInt aPos, TInt aDrive, CFsPluginFactory* aPluginFactory)
+	{
+	TInt count= iPluginChain.Count();
+	
+	if(aPos == KPluginAutoLocate)
+		{
+		for(TInt i=0;i<count;i++)
+			{
+			CFsPlugin* pP = iPluginChain[i];
+			if(aPluginFactory->SupportedDrives()&KPluginVersionTwo) //Version2
+				{
+				//If KPluginAutoAttach, then we're dismounted from all drives.
+				//If KPluginMountDriveZ, then check against 25 explicitly (cannot change aDrive:=Z as that==KPluginAutoAttach))
+				//If any other drive mounted.
+				if(aUPos == pP->iUniquePos && (aDrive==KPluginAutoAttach || (aDrive==KPluginMountDriveZ && pP->iMountedOn & (1<<EDriveZ)) || pP->iMountedOn & (1<<aDrive)))
+					return i;
+				}
+			else //version1
+				{
+				if(aUPos == pP->iUniquePos && (aDrive==KPluginAutoAttach || pP->iMountedOn & (1<<aDrive)))
+					return i;
+				}
+			}
+		return KErrNotFound;
+		}
+
+	if(aPos+1>iPluginChain.Count())
+		return(KErrNotFound);
+
+	if(iPluginChain[aPos]->iUniquePos == aUPos && aDrive==iPluginChain[aPos]->Drive())
+		return aPos;
+	return KErrNotFound;
+	}
+
+/**
+Finds a plugin by unique position
+*/
+CFsPlugin* FsPluginManager::FindByUniquePosition(TInt aUniquePosition)
+	{
+	LockChain();
+	CFsPlugin* plugin = NULL;
+	TInt count= iPluginChain.Count();
+	for(TInt i=0;i<count;i++)
+		{
+		if(aUniquePosition == iPluginChain[i]->iUniquePos)
+			{
+			plugin = iPluginChain[i];
+			break;
+			}
+		}
+	UnlockChain();
+	return plugin;
+	}
+
+/**
+Create a connection to a plugin
+*/
+CFsPluginConn* FsPluginManager::CreatePluginConnL(TInt aUniquePosition, TUint aClientId)
+	{
+	CFsPlugin* pP = FindByUniquePosition(aUniquePosition);
+	if(pP != NULL)
+		{
+		CFsPluginConn* pC = pP->NewPluginConnL();
+		pC->iPluginP = pP;
+		pC->iClientId = aClientId;
+		iPluginConns->AddL(pC, ETrue);
+		return pC;
+		}
+
+	User::Leave(KErrNotFound);
+	return NULL;
+	}
+
+/**
+Create a plugin thread
+Should only by called from main file server thread with plugin thread unavailable
+*/
+TInt FsPluginManager::InitPlugin(CFsPlugin& aPlugin)
+	{
+	TInt err = KErrNone;
+
+	if(!aPlugin.iThreadP)
+		{
+		TRAP(err,aPlugin.iThreadP=CPluginThread::NewL(aPlugin));
+		if(err!=KErrNone)
+			return err;
+		}
+
+	aPlugin.iThreadId = aPlugin.iThreadP->StartL();
+	return err;
+	}
+/**
+Cancels plugin requests
+*/
+void FsPluginManager::CancelPlugin(CFsPlugin* aPlugin,CSessionFs* aSession)
+	{
+	aPlugin->iThreadP->CompleteSessionRequests(aSession,KErrCancel);
+	}
+
+/**
+Gets number of plugins in the plugin stack
+*/
+TInt FsPluginManager::ChainCount()
+	{
+	return(iPluginChain.Count());
+	}
+
+/**
+ * Returns a CFsPlugin* from aPos in the plugin chain.
+ * 
+ * To be called whilst already holding the iChainLock.
+ * 
+ * @returns (via parameter) CFsPlugin*& aPlugin
+*/
+TInt FsPluginManager::Plugin(CFsPlugin*& aPlugin, TInt aPos)
+	{
+	if(aPos >= iPluginChain.Count() || aPos < 0)
+	    return KErrNotFound;
+	
+	aPlugin = iPluginChain[aPos];
+	return KErrNone;
+	}
+
+/**
+Locks the chain
+*/
+void FsPluginManager::LockChain()
+	{
+	iChainLock.Wait();
+	}
+
+/**
+Unlocks the chain
+*/
+void FsPluginManager::UnlockChain()
+	{
+	iChainLock.Signal();
+	}
+
+/**
+Gets plugin conn from handle
+*/
+CFsPluginConn* FsPluginManager::GetPluginConnFromHandle(CSessionFs* aSession, TInt aHandle)
+	{
+	return((CFsPluginConn*)(SessionObjectFromHandle(aHandle,iPluginConns->UniqueID(),aSession)));
+	}
+
+/**
+Checks if the current thread is plugin conn's thread
+*/
+TBool FsPluginManager::IsPluginConnThread(TThreadId tid, CFsPlugin* aPlugin)
+	{
+	iPluginConns->Lock();
+	TInt count = iPluginConns->Count();
+	while(count--)
+		{
+		CFsPluginConn* conn = (CFsPluginConn*)(*iPluginConns)[count];
+		if(conn->Plugin() == aPlugin)
+			{
+			if(conn->ClientId() == tid)
+				{
+				iPluginConns->Unlock();
+				return ETrue;
+				}
+			}
+		}
+	iPluginConns->Unlock();
+	return EFalse;
+	}
+
+/**
+Dispatch a synchronous message
+*/
+void FsPluginManager::DispatchSync(CFsRequest* aRequest)
+	{
+	__THRD_PRINT(_L("FsPluginManager::DispatchSync"));
+	if(!FsThreadManager::IsMainThread() && iScheduler)
+		{
+		iScheduler->Dispatch(aRequest);
+		}
+	else
+		{
+		aRequest->Process();
+		}
+	}
+
+void FsPluginManager::CompleteSessionRequests(CSessionFs* aSession, TInt aValue, CFsInternalRequest* aRequest)
+/**
+Complete outstanding requests for the specified session
+*/
+	{
+	__PRINT2(_L("FsPluginManager::CompleteSessionRequests(%08x, %d)"), aSession, aValue);
+
+	// Iterate through all plugins, cancelling outstanding session requests
+	aRequest->Set(CancelPluginOp, aSession);
+
+	FsPluginManager::LockChain();
+	TInt count = FsPluginManager::ChainCount();
+	TInt i;
+	for(i=0; i<count; i++)
+	    {
+	    CFsPlugin* plugin = NULL;
+	    User::LeaveIfError(FsPluginManager::Plugin(plugin, i));
+	    __ASSERT_DEBUG(plugin, User::Leave(KErrNotFound));
+	    aRequest->iCurrentPlugin = plugin;
+	    aRequest->Status() = KRequestPending;
+	    aRequest->Dispatch();
+	    //Cancel is delivered to the front of the request queue
+	    //so hopefully this wont take too long.
+	    FsPluginManager::UnlockChain();
+	    User::WaitForRequest(aRequest->Status());
+	    FsPluginManager::LockChain();
+	    __ASSERT_ALWAYS(aRequest->Status().Int()==KErrNone||aRequest->Status().Int()==KErrCancel,Fault(ESessionDisconnectThread2));
+	    count = FsPluginManager::ChainCount();
+	    }
+	FsPluginManager::UnlockChain();
+	
+//	RDebug::Print(_L("FsPluginManager::CompleteSessionRequests - CSRs"));
+	iScheduler->CompleteSessionRequests(aSession, aValue);
+	}
+
+