kernel/eka/drivers/pipe/dpipe.cpp
changeset 0 a41df078684a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/pipe/dpipe.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,2194 @@
+// Copyright (c) 2006-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:
+//
+
+
+#include <kernel/kern_priv.h>
+#include "dpipe.h"
+
+//_LIT(KPipePanicCategory,"PipePanic");
+const TInt KPipeGranularity   = 8;
+
+DECLARE_STANDARD_LDD()
+/** 
+Standard export function for LDDs. This creates a DLogicalDevice derived
+object, in this case our DPipeDevice
+*/
+	{
+	return new DPipeDevice;
+	}
+
+DPipeDevice::DPipeDevice()
+/**
+DPipeDevice Constructor has minimal implementation such setting the version number
+Indicate the use of unit number
+
+@param		None
+
+@return 	None
+*/ 
+	{
+	iCount = 0;
+    iIdindex = 0;
+    iAllocated = 0;
+	iVersion = RPipe::VersionRequired();
+	}
+
+
+DPipeDevice::~DPipeDevice()
+	{
+	// Delete the existing pipes
+	for(TInt count = 0; count<iCount; count++)
+		{
+		DPipe* pipe=iDpipes[count];
+		pipe->Wait();
+		pipe->CloseAll();
+		delete pipe;
+		}
+	Kern::Free(iDpipes);
+	iMutex->Close(NULL);
+	}
+
+
+TInt DPipeDevice::Install()
+/**
+Second stage constructor and at least set a name for the 
+driver object. Inherited from DLogicalDevice. This must at least set a name
+for the driver object.
+
+@param		None
+
+@return 	KErrNone 	If successful, otherwise one of the system wide error codes.
+*/
+	{
+	_LIT(KMutexName,"PipeDeviceMutex");
+	TInt err = Kern::MutexCreate(iMutex, KMutexName, KMutexOrdGeneral1);
+	if (err)
+		{
+		return err;
+		}
+	
+	return SetName(&RPipe::Name());
+	}
+
+
+void DPipeDevice::GetCaps(TDes8& aDes) const
+/**
+Returns the driver capabilities. Called in the response to
+an RPipe::GetCaps() request
+
+@param  	aDes 		Descriptor into which capabilities information 
+					    is to be written
+@return 	None
+*/
+	{
+	// Write it back to user memory
+	TVersion version;
+	version = iVersion;
+	Kern::InfoCopy(aDes,(TUint8*)&version, sizeof(version));
+	}
+
+
+TInt DPipeDevice::Create(DLogicalChannelBase*& aChannel)
+/**
+Called by the kernel's device driver framework to create a Logical Channel. 
+This is called in the context of the user thread (client) which requested the
+creation of the Logical Channel. 
+
+ @param 	aChannel 	Set to point to the created logical channel
+
+ @return 	KErrNone 	If successful, otherwise system one of the other
+ 						wide error codes.
+ */
+	{
+	aChannel = new DPipeChannel;
+	if (!aChannel)
+		return KErrNoMemory;
+	return KErrNone;
+	}
+
+
+TInt  DPipeDevice::CreatePipe(const TDesC& aName, TInt aSize, DPipe*& aPipe, TAny* aCap)
+/**
+Called by DPipeChannel instance to create named DPipe object and 
+associate itself with the newly created named DPipe instance.
+
+@param aName			name need to be attached to the newly created DPipe object.
+@param aSize			size of the DPipe object.
+@param aPipe	 		Pointer to DPipe, If successful set the pointer to newly created DPipe					instance else NULL						
+@param aCap				Pointer to TSecuritypolicy passed as void pointer
+
+@return  KErrNone 		If successful, otherwise one of the other system wide error code	
+@pre    Calling thread must be in a critical section.
+@pre    Mutex must be held
+*/	
+	{	
+	__ASSERT_MUTEX(iMutex);
+	__KTRACE_OPT(KPIPE, Kern::Printf(">DPipeDevice::CreatePipe")); 
+	TInt err = KErrNone;
+	DPipe** pS = iDpipes;
+	DPipe** pE = pS + iCount;
+	while(pS < pE)
+		{
+		DPipe* pO = *pS++;
+		if((pO->MatchName(&aName)))
+			{ 
+			err = KErrAlreadyExists;
+			break;
+			}
+		}
+	if(err == KErrNone)
+		{
+		DPipe* pipe = DPipe::CreatePipe(aName, aSize, aCap);	
+		if(pipe)
+			{
+		 	err = AddPipe(pipe);
+			if(err!= KErrNone)
+				{
+				delete pipe;
+				}
+			else
+				{
+				aPipe = pipe;		
+				}
+			}
+		else
+			{
+			err = KErrNoMemory;
+			}
+		}
+	__KTRACE_OPT(KPIPE, Kern::Printf("<DPipeDevice::CreatePipe ret=%d", err)); 
+	return err;
+	}
+
+
+DPipe*  DPipeDevice::CreatePipe(TInt aSize)
+/**
+Called by DPipeChannel instance to create un-named DPipe instance and 
+associate itself with the newly created un-named DPipe instance.
+
+@param aSize		size of the DPipe object.
+				
+@return  DPipe*	    If successful, otherwise NULL
+@pre    Mutex must be held
+@pre	In critical section
+*/
+	{
+	__ASSERT_CRITICAL;
+	__ASSERT_MUTEX(iMutex);
+	TKName aName;
+	DPipe* pipe =  DPipe::CreatePipe(aName, aSize);
+	if(!pipe)
+		{
+		return NULL;
+		}
+		
+	TInt r = AddPipe(pipe);
+	if (r != KErrNone)
+		{
+		delete pipe;
+		return NULL;
+		}		
+	return pipe;	
+	}
+
+
+	
+TInt DPipeDevice::AddPipe(DPipe* aObj)
+/**
+Add an instance of Dpipe to the array. 
+@param aObj			Pointer to  DPipe object
+@return KErrNone 	If the call is successful otherwise  one of the other
+					system wide error code.
+					
+@pre    Calling thread must be in a critical section.
+@pre    Mutex to be held
+*/
+	{
+	__ASSERT_CRITICAL; //otherwise iDPipes and iCount could go out of sync
+	__ASSERT_MUTEX(iMutex);
+	// store the current instance to the array
+	if(iCount == iAllocated)
+		{
+		TInt newAlloc = iAllocated + KPipeGranularity;
+		TInt r = Kern::SafeReAlloc((TAny*&)iDpipes, iCount * sizeof(DPipe*), newAlloc * sizeof(DPipe*));
+		if (r!= KErrNone)
+			{
+			return r;
+			}
+		iAllocated = newAlloc;
+		}
+	TInt id = GenerateId();	
+	aObj->SetId(id);
+	iDpipes[iCount++]= aObj;
+
+	__KTRACE_OPT(KPIPE, Kern::Printf("DPipeDevice::AddPipe Pipe added ID=%d", id)); 
+	return KErrNone;
+	}
+	
+
+	
+void DPipeDevice::RemovePipe(DPipe** aObj)
+/**
+Remove an instance of DPipe from the array
+
+@param	Pointer to Dpipe Array
+
+@return None
+
+@pre    Calling thread must not be in a critical section.
+@pre    Mutex to be held
+*/
+	{
+	__ASSERT_MUTEX(iMutex);
+	__ASSERT_CRITICAL; //we don't want to leave the array inconsistant
+
+ 	DPipe**	pE = (iDpipes + iCount) - 1;
+ 	if(aObj<pE)
+		{
+		//bump along array elements to close the gap
+		wordmove((TAny*)aObj, (TAny*)(aObj+1), TInt(pE)- TInt(aObj));
+		}
+	--iCount;
+	if(iCount % KPipeGranularity == 0)
+		{
+			Kern::SafeReAlloc((TAny*&)iDpipes, iAllocated*sizeof(DPipe*), iCount* sizeof(DPipe*));
+			iAllocated = iCount;
+		}
+	}
+	
+
+DPipe* DPipeDevice::FindNamedPipe(const TDesC* aName)
+/**
+Called by the DPipeChannel to check if a named DPipe instance exist with a name
+as specified by aName parameter.
+
+@param aName		The name of the DPipe instance to search for. 
+
+@return  DPipe*	    If successful, otherwise NULL
+
+@pre Device mutex to be held
+*/
+	{
+	__ASSERT_MUTEX(iMutex);
+	DPipe** pS = iDpipes;
+	DPipe** pE = pS + iCount;
+	
+	while(pS < pE)
+		{
+		DPipe* pO = *pS++;
+		if(pO->MatchName(aName))
+			{ 
+			return pO;
+			}
+		}
+	return NULL;
+	}
+		
+DPipe* DPipeDevice::FindUnnamedPipe(const TInt aId)
+/**
+Called by the DPipeChannel to check if an un-named DPipe instance exist with an ID
+as specified by aId parameter.
+
+@param aId			The ID of the DPipe instance to search for. 
+	
+@return  DPipe*	   If successful, otherwise NULL
+@pre Device mutex to be held
+*/
+	{
+	__ASSERT_MUTEX(iMutex);
+	DPipe** pS = iDpipes;
+	DPipe** pE = pS + iCount;	
+	while(pS < pE)
+		{
+		DPipe* pO = *pS++;
+		if(pO->MatchId(aId))
+			{
+			return pO;
+			}
+		}
+	return NULL;
+	}
+
+TInt DPipeDevice::Destroy(const TDesC* aName)
+/**
+This method is called to destroy a named DPipe instance. The caller needs to have 
+sufficient capabilities to delete a named pipe. This method will fail if there are
+any handles still open on the pipe. 
+
+@param	aName		Name of the DPipe instance to be deleted.
+
+@return	KErrNone 	If successful, otherwise one of the other system wide error.
+
+*/
+	{
+	TAutoWait<DMutex> autoMutex(*iMutex);
+	DPipe** pS = iDpipes;
+	DPipe**	pE = pS + iCount;
+	TInt err = KErrNotFound;
+	TInt count = 0;
+	while(pS < pE)
+		{
+		DPipe** pO = pS++;
+		DPipe* pipe = *pO;
+		if(((*pO)->MatchName(aName)))
+			{
+			//! Check capability 
+			if(pipe->GetCap())
+				{
+				if(!(pipe->GetCap()->CheckPolicy(&Kern::CurrentThread())))
+					{
+					err = KErrPermissionDenied;
+					break;
+					}
+				}
+			// Check if any handles still opened on the pipe.
+			pipe->Wait();
+			if (!pipe->IsPipeClosed())
+				{
+				err = KErrInUse;
+				pipe->Signal(); //need to signal if we won't be destroying pipe
+				break;
+				}
+			__KTRACE_OPT(KPIPE, Kern::Printf("DPipeDevice::Destroy remove ID=%d", pipe->OpenId())); 
+			delete iDpipes[count];
+			RemovePipe(pO);
+			err = KErrNone;
+			break;
+			}
+		count ++;
+		}
+	return err;
+	}
+
+
+TInt DPipeDevice::Close(TInt aId)
+/**
+This method is called to close both named and un-named DPipe. In case of un-named DPipe
+if there is no further reference of a DPipeChannel exist, the corresponding un-named DPipe
+will be deleted. 
+
+@param aId		 	ID of the pipe that need to be closed.
+
+@return KErrNone 	If successful otherwise one of the other system wide error.
+
+*/
+	{
+	TAutoWait<DMutex> autoMutex(*iMutex);
+	DPipe** pS = iDpipes;
+	DPipe**	pE = pS + iCount;
+	TInt err = KErrNotFound;
+	while(pS < pE)
+		{
+		DPipe** pO = pS++;
+		DPipe* pipe = *pO;
+		if(pipe->MatchId(aId))
+			{
+			__KTRACE_OPT(KPIPE, Kern::Printf("DPipeDevice::Close found ID=%d", pipe->OpenId())); 
+			//even if we can't delete the pipe, we have
+			//found it so don't return KErrNotFound
+			err = KErrNone;
+
+			pipe->Wait();
+			
+			// we can only delete an unamed pipe with both ends closed
+		 	if(!pipe->IsNamedPipe() && pipe->IsPipeClosed())
+		 		{
+				__KTRACE_OPT(KPIPE, Kern::Printf("DPipeDevice::Close remove ID=%d", pipe->OpenId())); 
+				delete pipe;
+				RemovePipe(pO); 
+				break;
+		 		}
+			pipe->Signal(); 
+
+			}
+		}
+	return err;
+	}
+
+
+
+TInt DPipeDevice::GenerateId()
+/**
+Generate a ID  and store for a Named pipe while creating.
+
+@param 	 None
+@return  TInt	ID for the name pipe
+
+@pre    Mutex to be held
+
+*/
+	{
+	__ASSERT_MUTEX(iMutex);
+	iIdindex++;
+	return (KIdBase + iIdindex);		
+	}
+
+
+DPipeChannel::DPipeChannel()
+	:iClientRequest(NULL), iData(NULL), iChannelType(RPipe::EChannelUnset)
+/**
+Constructor
+*/
+	{
+	}
+
+
+DPipeChannel::~DPipeChannel()
+/**
+Destructor
+*/
+	{
+	CloseHandle();
+	
+	Kern::DestroyClientRequest(iClientRequest); //null ptr is safe
+	}
+
+
+
+TInt DPipeChannel::RequestUserHandle (DThread* aThread, TOwnerType aType)
+/**
+Inherited from DObject. This method is called when a user thread requests
+a handle to this channel. Minimal implantation here is capability check
+
+@param aThread		DThread instance reference that requests a handle to this channel.
+@param aType		Ownership type for the handle.
+
+@return  KErrNone  If successful otherwise one the system wide error.
+*/
+	{
+	(void)aThread;
+	(void)aType;
+ 	return KErrNone;
+	}
+
+
+    
+TInt DPipeChannel::DoCreate (TInt aUnit, const TDesC8* aInfo, const TVersion& aVer)
+/**
+Inherited from DLogicalChannelBase class.  This method represents the second stage
+constructor called by the kernel's device driver framework. This is called in the
+context of the user thread (client) which requested the creation of the Logical
+Channel. The thread is in critical section.
+
+@param aUnit		The unit argument supplied by the client
+@param aInfo		The info argument supplied by the client 
+@param aVer			The version argument supplied by the client 
+
+@return KErrNone 	If successful, otherwise one of the other system wide error codes.
+*/
+	{
+	(void)aInfo;
+	(void)aUnit;
+	
+  	// Check version
+    if (!Kern::QueryVersionSupported(RPipe::VersionRequired(),aVer))
+        return KErrNotSupported;
+
+	TInt r = Kern::CreateClientRequest(iClientRequest);
+	if(r != KErrNone)
+		{
+		return r;
+		}
+
+	// Done 
+	return KErrNone;
+	}
+
+
+TInt DPipeChannel::Request(TInt aReqNo, TAny* a1, TAny* a2)
+/**
+Called by the Device driver framework upon user request. Stores the 
+Thread pointer under whose context this function is called. 
+
+@param aFunction	A number identifying the  message type
+@param a1			A 32-bit Value passed by the user
+@param a2			A 32-bit Value passed by the user
+
+@return	KErrNone	If successful, otherwise one of the system wide error code
+	
+*/	
+	{
+	TInt err = KErrNone;
+	
+	DATAPAGING_TEST
+		(
+		err = Kern::HalFunction(EHalGroupVM, EVMHalFlushCache, 0, 0);
+		if(err != KErrNone)
+			{
+			return err;
+			}
+		)
+
+	if(aReqNo == KMaxTInt)
+		{
+			CancelRequest((TInt)a1);
+			return err;
+		}
+	if(aReqNo < 0)
+		{
+		// DoRequest
+		TAny *array[2] = {0,0};
+		TRequestStatus * pStat = (TRequestStatus*)a1;
+		kumemget32(&array[0], a2, 2*sizeof(TAny*));
+		err = DoRequest(~aReqNo, pStat, array[0], array[1]);
+		if(err!= KErrNone)
+			Kern::RequestComplete(pStat, err);
+		
+		}
+	else
+		{
+		// DoControl
+		err = DoControl(aReqNo, a1, a2);
+		}
+		return err;
+	}
+
+
+TInt DPipeChannel::DoControl(TInt aFunction, TAny* a1, TAny* a2)
+/**
+Processes Synchronous 'control' requests. This function is called to service
+any synchronous calls through the  user side RPipe handle. 
+
+@param aFunction		A number identifying the  message type
+@param a1				A 32-bit Value passed by the user
+@param a2				A 32-bit Value passed by the user
+
+@return KErrNone 		If the call is successful, otherwise one of the other
+						system wide error
+*/
+	{
+	TInt aSize = 0;
+	TInt aId = 0;
+	
+    switch(aFunction)
+		{
+		case RPipe::EDefineNamedPipe:
+			return PipeCreate(a1, a2);
+			
+		case RPipe::EOpenToReadNamedPipe:
+			return PipeOpen((const TDesC*)a1, RPipe::EReadChannel);
+		
+		case RPipe::EOpenToWriteNamedPipe:
+			return PipeOpen((const TDesC*)a1, RPipe::EWriteChannel);
+		
+		case RPipe::EOpenToWriteButFailOnNoReaderNamedPipe:
+			return OpenOnReader((const TDesC*)a1);
+		
+		case RPipe::EDestroyNamedPipe:
+			return PipeDestroy((const TDesC*)a1);	
+		
+		case RPipe::ECreateUnNamedPipe:
+			kumemget((TAny*)&aSize, a1, sizeof(TInt));
+			return PipeCreate( aSize);
+		
+		case RPipe::EOpenUnNamedPipe:
+			kumemget((TAny*)&aId, a1, sizeof(TInt));
+			return PipeOpen(aId);
+		
+		case RPipe::ERead:
+			kumemget((TAny*)&aSize, a2, sizeof(TInt));
+			return Read (a1, aSize);
+		
+		case RPipe::EWrite:
+			kumemget((TAny*)&aSize, a2, sizeof(TInt));
+			return Write (a1, aSize);
+				
+		case RPipe::ESize:
+			 return Size();
+		
+		case RPipe::EDataAvailableCount:
+			 {		
+			 TAutoWait<DMutex> autoMutex(iData->Mutex());
+			 return iData->AvailableDataCount();
+			 }
+			 
+		case RPipe::EFlushPipe:
+			 Flush();
+			 return KErrNone;
+			 
+		case RPipe::EGetPipeInfo:
+			 umemput(a1,(TAny*)&iChannelType, sizeof(TInt));
+			 aSize = Size();
+			 umemput(a2,(TAny*)&aSize, sizeof(TInt));
+			 return KErrNone;
+			
+	
+		default:
+			 return KErrNotSupported;
+			 
+		}
+
+	}
+
+
+TInt DPipeChannel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2)
+/**
+Processes Asynchronous requests This function is called to service
+any asynchronous calls through the  user side RPipe handle. 
+
+@param aFunction		A number identifying the  message type
+@param aStatus 			Status request to be completed. 
+@param a1				A 32-bit Value passed by the user
+@param a2				A 32-bit Value passed by the user
+
+@return  KErrNone 		If the call is successful, else one of the system wide error
+*/
+	{
+	(void)a2;
+	TInt aSize = 0;
+	TInt aChoice = 0;
+
+    switch(aReqNo)
+		{
+		case RPipe::EDataAvailable:
+				return NotifyDataAvailable(aStatus, ETrue);	
+			
+		case RPipe::ESpaceAvailable:
+				umemget(&aSize, a1, sizeof(aSize));
+				return NotifySpaceAvailable(aSize, aStatus, ETrue);
+		
+		case RPipe::EWaitNotification:
+				// a2 == RPipe::EWaitForReader is for WaitForReader.
+				// a2 == RPipe::EWaitForWriter is for WaitForWriter.
+				umemget(&aChoice, a2, sizeof(aChoice));
+				return WaitNotification(aStatus, a1, aChoice);
+				
+		case RPipe::EReadBlocking:
+			{
+				return NotifyDataAvailable(aStatus, EFalse);
+			}
+				
+		case RPipe::EWriteBlocking:
+			{
+				umemget(&aSize, a1, sizeof(aSize));
+				return NotifySpaceAvailable(aSize, aStatus, EFalse);
+			}
+		default:
+				return KErrNotSupported;
+		}
+	}
+
+
+		
+TInt DPipeChannel::PipeCreate(TAny* a1,  TAny* a2)
+/**
+Creates named pipes with the specified name  and size. It calls Pipe Device 
+object to create the pipe and obtained the pointer to it. The pointer is then
+stored in its iData member data.
+@param a1		Pointer to TPipeInfo class
+
+@param a2		Pointer to TSecurityPolicy class
+
+@return KErrNone	If successful, otherwise one of the other system wide error code.
+*/
+	{
+	if(iData)
+		{
+		//this channel already has a pipe
+		return KErrInUse;
+		}
+
+	// The following code safely gets the 3 arguments into kernel memory.
+	// (The user side API is badly designed,)
+	RPipe::TPipeInfo& info = (*(RPipe::TPipeInfoBuf*)a1)(); // reference to user side 'TPipeInfo'
+	TInt size;
+	kumemget(&size,&info.isize,sizeof(size));
+	TKName name;
+	Kern::KUDesGet(name,info.iName);
+	TSecurityPolicy* securityPolicy = 0;
+	TSecurityPolicy securityPolicyBuffer;
+	if(a2)
+		{
+		kumemget(&securityPolicyBuffer,a2,sizeof(securityPolicyBuffer));
+		securityPolicy = &securityPolicyBuffer;
+		}
+
+	DPipe * pipe = NULL;
+	DPipeDevice& device = *static_cast<DPipeDevice*>(iDevice);
+
+	//must wait on device since after creation
+	//the pipe becomes globably findable 
+	//and destroyable
+	TAutoWait<DMutex> outerAutoMutex(device.Mutex());
+
+	TInt err = ((DPipeDevice*)iDevice)->CreatePipe(name, size, pipe, securityPolicy);
+	if(err!= KErrNone)
+		{
+		return err;
+		}
+
+	TAutoWait<DMutex> innerAutoMutex(pipe->Mutex());
+	pipe->SetReadEnd(this);
+	iData = pipe;
+	iChannelType = RPipe::EReadChannel;
+	return err;
+	}
+
+
+TInt DPipeChannel::PipeCreate(const TInt aSize)
+/**
+Creates unnamed pipes with the specified Id and size. It calls Pipe Device 
+object to create the pipe and obtained the pointer to it. The pointer is then
+stored in its iData member data. Marked the current channel as read end.  
+
+@param aSize		Size of the unnamed pipe to be created.
+
+@return	Handle ID if successful, otherwise one of the other system wide error code.
+*/
+	{
+	if(iData)
+		{
+		//this channel already has a pipe
+		return KErrInUse;
+		}
+
+	DPipeDevice& device = *static_cast<DPipeDevice*>(iDevice);
+
+	TAutoWait<DMutex> outerAutoMutex(device.Mutex());
+
+	DPipe* pipe = device.CreatePipe(aSize);
+	if(pipe == NULL)
+		{
+		return KErrNoMemory;
+		}
+
+	TAutoWait<DMutex> innerAutoMutex(pipe->Mutex());
+
+	pipe->SetReadEnd(this);
+	iData = pipe;
+	iChannelType = RPipe::EReadChannel;
+
+	return iData->OpenId();
+	}
+
+
+TInt DPipeChannel::OpenOnReader(const TDesC* aName)
+/**
+Opens a named pipe identified by the name parameter. It calls Pipe Device object
+to open the Pipe identified by the name and obtained the pointer to the pipe. The
+pointer is them stored in its iData member data. Marked the current channel as write
+end. 
+@param 	aName		The name of the pipe to be opened.
+
+@return KErrNone	If successful, otherwise one of the other system wide error code. 
+*/
+	{
+	if(iData)
+		{
+		//this channel already has a pipe
+		return KErrInUse;
+		}
+
+	TKName PName;
+	Kern::KUDesGet(PName, *aName);
+
+	DPipeDevice& device = *static_cast<DPipeDevice*>(iDevice);
+
+	//need to hold the device mutex to
+	//prevent the pipe getting deleted before we can call
+	//SetWriteEnd
+	TAutoWait<DMutex> outerAutoMutex(device.Mutex());
+	DPipe* pipe = device.FindNamedPipe(&PName);
+
+	if(pipe == NULL)
+		{
+		return KErrNotFound;
+		}
+
+	TAutoWait<DMutex> innerAutoMutex(pipe->Mutex());
+	if (!pipe->IsReadEndOpened())
+		{
+		return KErrNotReady;
+		}
+	
+	iData = pipe;
+
+	if(!CheckCap())
+		{
+		iData = NULL;
+		return KErrPermissionDenied;
+		}
+	
+	if(pipe->IsWriteEndOpened())
+		{
+		iData = NULL;
+		return KErrInUse;
+		}	
+
+	iData->SetWriteEnd(this);
+	iChannelType = RPipe::EWriteChannel;
+	return KErrNone;
+	}
+
+
+TInt DPipeChannel::PipeDestroy(const TDesC* aName)
+/**
+Destroys the named pipe.
+@param	aName 			Name of the Kernel pipe to be destroyed.
+
+@return KErrNone		If the pipe is successfully destroyed, otherwise one of the
+						other system wide error codes
+*/
+	{	
+	TKName PName;
+	Kern::KUDesGet(PName, *aName);
+	return ((DPipeDevice*)iDevice)->Destroy(&PName);
+	}
+
+TInt DPipeChannel::PipeOpen(const TInt aId)
+/**
+Opens a unnamed pipe identified by the specified id. It calls Pipe Device object
+to open a unnamed pipe identified by the specified id and obtain the pointer to the
+pipe. The pipe reference is then stored in its iData member data and marked the 
+current channel as write end. 
+
+@param 	aId 		Id of the unnamed pipe to be opened.
+
+@return KErrNone	If successful, otherwise one of the system wide error code. 
+*/
+	{
+	if(iData)
+		{
+		//this channel already has a pipe
+		return KErrInUse;
+		}
+
+	DPipeDevice& device = *static_cast<DPipeDevice*>(iDevice);
+	TAutoWait<DMutex> outerAutoMutex(device.Mutex());
+
+	DPipe* pipe = device.FindUnnamedPipe(aId);
+	if(pipe == NULL)
+		{
+		return KErrNotFound;
+		}
+
+	TAutoWait<DMutex> innerAutoMutex(pipe->Mutex());
+	if (pipe->IsWriteEndOpened() )
+		{
+		return KErrInUse;
+		}
+
+	pipe->SetWriteEnd(this);
+
+	iChannelType = RPipe::EWriteChannel;
+	iData = pipe;
+	
+	return KErrNone;
+	}
+
+
+TInt DPipeChannel::PipeOpen(const TDesC* aName, RPipe::TChannelType aType)
+/**
+This function will be called under DoControl();
+Attempts to open the pipe for reading (iReadEnd) or writing (iWriteEnd)
+@param  aName 		Name of the pipe to be opened
+
+@param  aType	 	Type of operation to be performed.
+
+@return KErrNone	Pipe successfully created, otherwise one of the other system wide
+					error code
+*/ 
+	{
+	if(iData)
+		{
+		//this channel already has a pipe
+		return KErrInUse;
+		}
+
+	TKName PName;
+	Kern::KUDesGet(PName, *aName);
+	
+	DPipeDevice& device = *static_cast<DPipeDevice*>(iDevice);
+
+	TAutoWait<DMutex> outerAutoMutex(device.Mutex());
+
+	DPipe* pipe = device.FindNamedPipe(&PName);
+	if(pipe == NULL)
+		{
+		return KErrNotFound;
+		}
+
+
+	TAutoWait<DMutex> innerAutoMutex(pipe->Mutex());
+	iData = pipe;
+	//! Check capabilitity if applicalble
+	if(!CheckCap())
+		{
+		iData = NULL;
+		return KErrPermissionDenied;
+		}
+
+	// Check if the pipe is already opened.
+	if(aType == RPipe::EReadChannel)
+		{
+		if(iData->IsReadEndOpened())
+			{
+			iData = NULL;
+			return KErrInUse;
+			}
+		iData->SetReadEnd(this);
+		}
+	else
+		{
+		if(iData->IsWriteEndOpened())
+			{
+			iData = NULL;
+			return KErrInUse;
+			}
+		iData->SetWriteEnd(this);	
+		}
+
+	iChannelType = aType;
+
+	return KErrNone;	
+	}
+
+
+
+TBool DPipeChannel::CheckCap()
+/**
+Check if Security policy is installed, if so, checks if the current thread
+has required capabilities
+
+@param 	None
+
+@return TBool  ETrue if The current thread has required capabilities and also if
+			  no capabilities is installed, otherwise EFlase.
+			  
+*/
+	{
+	//iData->GetCap is always true
+	if(iData->GetCap())
+		return iData->GetCap()->CheckPolicy(&Kern::CurrentThread());
+	else 
+		return ETrue;
+	}
+
+
+
+TInt DPipeChannel::Read (TAny* aBuff, TInt aSize)
+/**
+Synchronous, non-blocking read operation. If the pipe is empty it will 
+return immediately with KErrUnderflow. A successful DPipe::Read() operation 
+will free up more space in the pipe. If a request status object has been registered
+for Space Available notification, it will complete. Note that there is no 
+guarantee that the amount of space freed up in the pipe will be sufficient 
+for the next DPipe::Write() operation.
+
+@param	aBuff			Buffer from which data need to be read
+
+@param	aSize			Size of the data to be read
+
+@return:>0				Amount of data read  in octets.
+		 KErrArgument   Invalid Length	Amount of data to be read is invalid (e.g. negative) 
+		 KErrNotReady	If the write end is closed,
+		  				otherwise one of the other system wide error code  		
+*/
+	{
+	
+	if( iChannelType != RPipe::EReadChannel)
+		return KErrAccessDenied;
+	
+
+	TAutoWait<DMutex> outerAutoMutex(*iData->iReadMutex);
+	TAutoWait<DMutex> innerAutoMutex(iData->Mutex());
+	//iData->Wait();
+	if(!iData->IsWriteEndOpened() && iData->IsBufferEmpty())
+		{
+		//it is ok to read from a broken pipe provided there is data in it
+		return KErrNotReady;	
+		}
+
+	return iData->Read(aBuff, aSize);
+	}
+
+
+TInt DPipeChannel::Write (TAny* aBuff, TInt aSize)
+/**
+Synchronous, non-blocking write operation. If the pipe is full it will 
+return immediately with KErrOverflow. A successful DPipe::Write() operation will
+return amount of data written to the pipe.If a request status object has been registered
+for Data Available notification, it will complete.
+
+
+@param aBuf				Buffer from which data need to be written to the pipe.
+				
+@param aSize			Amount of data to be written to the pipe.
+	 
+@return >0				Amount of data written to the pipe, in octets.
+		KErrOverflow	The pipe is full no data is written.
+		KErrArgument	if the amount of data to be written in invalid
+		KErrNotReady	if the read end is not opened.
+						otherwise one of the other system wide error code
+*/
+	{
+	
+	if(iChannelType!= RPipe::EWriteChannel)
+		return KErrAccessDenied;
+		
+	TAutoWait<DMutex> outerAutoMutex(*iData->iWriteMutex);
+	TAutoWait<DMutex> innerAutoMutex(iData->Mutex());
+	
+	if(!(iData->IsReadEndOpened()))
+		{
+		return KErrNotReady;
+		}
+
+	return iData->Write(aBuff, aSize);	
+	}
+
+
+
+TInt DPipeChannel::CloseHandle()
+/**
+Attempts to close the pipe for reading  or writing .
+
+@param	None
+
+@return KErrNone				Success.
+		KErrCouldNotDisconnect	The pipe is already closed for that operation.
+
+*/
+	{
+	if(iData==NULL)
+		{
+		return KErrNone;
+		}
+
+	__KTRACE_OPT(KPIPE, Kern::Printf("DPipeChannel::CloseHandle ID=%d, ChannelType=%d", iData->OpenId(), iChannelType)); 
+	
+	NKern::ThreadEnterCS();
+	iData->Wait();
+	TInt err = KErrNone;
+	if(iChannelType == RPipe::EReadChannel)
+	 	{
+	 	CancelRequest(RPipe::EDataAvailable);
+	 	err = iData->CloseReadEnd();
+	 	}
+	else if(iChannelType == RPipe::EWriteChannel)
+	 	{
+	 	CancelRequest(RPipe::ESpaceAvailable);
+	 	err = iData->CloseWriteEnd();
+	 	}
+	else
+	 	{
+		FAULT(); //iChannelType should be set correctly if iData was non-null
+	 	}
+	// If we had a pointer to the pipe but it had no back pointer
+	// to us something has gone wrong.
+	__NK_ASSERT_DEBUG(err == KErrNone); 
+
+	const TInt pipeId=iData->OpenId();
+	iData->Signal();
+	iData = NULL;
+
+	// The return code from close would inform us if
+	// the device had no record of the pipe.
+	// However, for a named pipe there is no gurrantee that the pipe
+	// hasn't been deleted once we close our end of the pipe and
+	// Signal.
+	static_cast<DPipeDevice*>(iDevice)->Close(pipeId);
+
+	NKern::ThreadLeaveCS();
+	 
+	return err;
+	}
+
+
+
+TInt DPipeChannel::NotifySpaceAvailable ( TInt aSize,TRequestStatus* aStat, TBool aAllowDisconnected)
+/**
+Registers the request status object to be completed when space becomes 
+available in the pipe. 
+
+@param 	aSize			The size for which the user has requested for notification
+
+@param	aStat			Status request to be registered
+@param	aAllowDisconnected If false then confirm that the pipe has a reader
+
+@return KErrNone		 Success in registering the request
+		KErrAccessDenied If the correct end is not used to register the request
+		KErrInUse		 A notifier of this type has already been registered.
+						 otherwise one of the other system wide error code.
+		KErrNotReady	The pipe has no reader
+*/
+	{
+	
+	//! Check if correct end is used
+	if(iChannelType!= RPipe::EWriteChannel)
+		{
+		return KErrAccessDenied;
+		}
+	
+	TAutoWait<DMutex> autoMutex(iData->Mutex());
+	//Check if there is already a pending Space Available request.
+	if(iClientRequest->StatusPtr())
+		{
+		return KErrInUse;
+		}
+	else
+		{
+		if(!aAllowDisconnected && !(iData->IsReadEndOpened()) )
+			return KErrNotReady;
+
+		TInt r = iClientRequest->SetStatus(aStat);
+		__NK_ASSERT_ALWAYS(KErrNone == r); //we just checked StatusPtr
+		DThread* const currThread = &Kern::CurrentThread();
+
+		if((iData->RegisterSpaceAvailableNotification(aSize))==KErrCompletion)
+			{
+			Kern::QueueRequestComplete(currThread, iClientRequest, KErrNone);
+			}
+		else
+			{
+			iRequestThread = currThread;
+			// Open a reference on client thread so its control block can't disappear until
+			// this channel has finished with it.
+			iRequestThread->Open();   
+			iRequestType = RPipe::ESpaceAvailable;
+			}
+		}
+	return KErrNone;
+	}
+
+
+TInt DPipeChannel::NotifyDataAvailable (TRequestStatus* aStat, TBool aAllowDisconnected)
+/**
+Registers the request status object to be completed when data becomes 
+available in the pipe. 
+
+@param	aStat			Status request to be registered
+@param	aAllowDisconnected  If false then fail if the pipe is empty with no writer.
+
+@return KErrNone		 Success in registering the request
+		KErrAccessDenied If the correct end is not used to register the request 
+		KErrInUse		 A notifier of this type has already been registered.
+						 otherwise one of the other system wide error code.
+		KErrNotReady	 The pipe was empty and had no writer
+*/
+	{	
+
+	//! Check if correct end is used
+	if(iChannelType!= RPipe::EReadChannel)
+		{
+		return KErrAccessDenied;
+		}
+
+	// Check if there is already a pending Data Available request.	
+	TAutoWait<DMutex> autoMutex(iData->Mutex() );
+	if(iClientRequest->StatusPtr())
+		{
+		return KErrInUse;
+		}
+	else
+		{
+		if(!aAllowDisconnected)
+			{
+			if(iData->IsBufferEmpty() && (!iData->IsWriteEndOpened()))
+				return KErrNotReady;
+			}
+		
+		TInt r = iClientRequest->SetStatus(aStat);
+		__NK_ASSERT_ALWAYS(KErrNone == r); //we just checked StatusPtr
+		DThread* const currThread = &Kern::CurrentThread();
+
+		if((iData->RegisterDataAvailableNotification()) == KErrCompletion)
+			{
+			Kern::QueueRequestComplete(currThread, iClientRequest, KErrNone);
+			}
+		else
+			{
+			iRequestThread = currThread;
+			// Open a reference on client thread so its control block can't disappear until
+			// this channel has finished with it.
+			iRequestThread->Open();   
+			iRequestType = RPipe::EDataAvailable;
+			}
+		}
+	return  KErrNone;;
+	}
+
+
+TInt DPipeChannel::WaitNotification(TRequestStatus* aStat, TAny* aName, TInt aChoice)
+/**
+Registers the request status object to be completed when other end of the pipe
+is opened for reading (or writing).This method completes immediately if the other end of the
+pipe is already opened.
+
+
+@param	aName		Pointer to the a name passed as void pointer
+
+@param	aStat		Status request to be registered
+
+@param	aChoice		EWaitForReader,wait notification for Read end Opened.
+					EWaitForWriter,wait notification for Write end Opened.
+
+@return KErrNone		 Success in registering the request
+		KErrInUse		 A notifier of this type has already been registered.
+		KErrAccessDenied If the correct end is not used to register the request 
+						 otherwise one of the other system wide error code
+
+*/
+	{
+	//! Check if correct end is used
+	if(((aChoice == RPipe::EWaitForReader) && (iChannelType!= RPipe::EWriteChannel))
+		|| ((aChoice == RPipe::EWaitForWriter) && (iChannelType!= RPipe::EReadChannel)))
+		{
+		return KErrAccessDenied;
+		}
+
+	TKName PName;
+	Kern::KUDesGet(PName, *(TDesC*)aName);
+
+	TAutoWait<DMutex> autoMutex(iData->Mutex());
+	if(iData->MatchName(&PName)== EFalse)
+		{
+		return KErrNotFound;
+		}
+	// Check if there is already a pending request.
+	else if(iClientRequest->StatusPtr())
+		{
+		return KErrInUse;
+		}
+	else
+		{
+		TInt r = iClientRequest->SetStatus(aStat);
+		__NK_ASSERT_ALWAYS(KErrNone == r); //we just checked StatusPtr
+		DThread* const currThread = &Kern::CurrentThread();
+
+		//register the request.
+		if((iData->RegisterWaitNotification((TInt )aChoice))== KErrCompletion)
+			{
+			Kern::QueueRequestComplete(currThread, iClientRequest, KErrNone);
+			}
+		else
+			{
+			iRequestThread = currThread;
+			// Open a reference on client thread so its control block can't disappear until
+			// this channel has finished with it.
+			iRequestThread->Open();   
+			iRequestType = RPipe::EWaitNotification;
+			}
+		}
+	return KErrNone;
+	}
+
+
+/**
+For a given request return true if the notification
+we are cancelling is outstanding. If not, or
+if the supplied request is not a valid cancllation
+return false
+*/
+TBool DPipeChannel::ValidCancellation(TInt aReqType)
+{
+	switch(aReqType)
+	{
+	case RPipe::ECancelDataAvailable:
+		return (iRequestType==RPipe::EDataAvailable);
+	case RPipe::ECancelSpaceAvailable:
+		return (iRequestType==RPipe::ESpaceAvailable);
+	case RPipe::ECancelWaitNotification:
+		return (iRequestType==RPipe::EWaitNotification);
+	default:
+		return EFalse;
+	}
+}
+
+void DPipeChannel::CancelRequest ( TInt aReqType)
+/**
+Cancels an outstanding space available notifier request.
+
+@param 	aReqType A number identifying the  message type
+
+@return  None
+*/
+{
+	TAutoWait<DMutex> autoMutex(iData->Mutex() );
+	if(iClientRequest->StatusPtr() && ValidCancellation(aReqType))
+		{
+		switch(aReqType)
+			{
+			case RPipe::ECancelDataAvailable:
+				iData->CancelDataAvailable();			
+				break;
+			
+			case RPipe::ECancelSpaceAvailable:
+				iData->CancelSpaceAvailable();
+				break;
+		
+			case RPipe::ECancelWaitNotification:
+				iData->CancelWaitNotifier();
+				break;
+	
+			default:
+				FAULT();
+			}
+		Kern::QueueRequestComplete(iRequestThread, iClientRequest, KErrCancel);
+		// Close our reference on the client thread
+		Kern::SafeClose((DObject*&)iRequestThread,NULL);
+		iRequestThread = NULL;
+		}
+	return;	
+	}
+
+
+TInt DPipeChannel::Size()
+/**
+Returns the size of the Pipe's buffer
+
+@param None
+
+@return TInt	Return the size of the pipe, otherwise one of the other system wide 
+				error code.
+*/	{
+	if(!iData)
+		return KErrNotReady;
+	else
+		return iData->Size();
+	}
+
+    
+void DPipeChannel::Flush()
+/*
+Flush the content of the pipe
+
+@param	None
+@pre   Must be in a critical section.
+@return	None
+
+*/	{
+	//The flush is, in effect, a read where the data is ignored
+	TAutoWait<DMutex> autoMutex(*iData->iReadMutex);
+
+	iData->Wait();
+	iData->FlushPipe();
+	iData->Signal();
+	}
+	
+
+// Called from the DPipe  
+	
+void DPipeChannel::DoRequestCallback()
+/**
+It is called from the DPipe to complete the Outstanding request
+
+@param None
+
+@return None
+*/
+	{
+	__ASSERT_MUTEX(&iData->Mutex());
+	__NK_ASSERT_DEBUG(iRequestThread);
+	Kern::QueueRequestComplete(iRequestThread, iClientRequest, KErrNone);
+	Kern::SafeClose((DObject*&)iRequestThread,NULL);
+	iRequestThread=NULL;
+	}
+
+
+
+// DPipe the Kernel side pipe representing class
+
+DPipe::~DPipe()
+/**
+Destructor
+*/
+	{
+	delete iBuffer;
+	if (iPipeMutex)
+		iPipeMutex->Close(NULL);
+	if (iReadMutex)
+		iReadMutex->Close(NULL);
+	if(iWriteMutex)
+		iWriteMutex->Close(NULL);
+	}
+	
+
+// Creates a Named pipe
+DPipe* DPipe::CreatePipe(const TDesC& aName, TInt aSize, TAny *aPolicy)
+/**
+Static method to Create a Named pipe. 
+@param	aName		Reference to the Name to be set to the current named pipe.
+@param	aSize		Size of the Pipe.
+@param TAny			Pointer to TSecurityPolicy passed as void pointer
+
+@return DPipe*  	Reference to DPipe* instance if successful, otherwise NULL
+*/
+	{
+
+	DPipe* tmp = new DPipe;
+	if (!tmp)
+		{
+		return NULL;
+		}
+	if(tmp->ConstructPipe(aName, aSize, aPolicy)!= KErrNone)
+		{
+		delete tmp;
+		return NULL;
+		}
+	return tmp;
+	}
+	
+	
+TInt DPipe::ConstructPipe(const TDesC& aName, TInt aSize,TAny* aPolicy)
+/**
+Second phase constructor
+
+@param	aName		The name of the pipe to be created
+@param	aSize		The size of the pipe to be created
+@param TAny			Pointer to TSecurityPolicy passed as void pointer
+
+@return KErrNone	If successful, otherwise one of the other system wide error code
+*/
+	{
+	// check the size parameter.
+	if(aPolicy)
+		{
+		
+		memcpy(&iPolicy,aPolicy,sizeof(TSecurityPolicy));
+		
+		}
+	else
+		{
+		TSecurityPolicy apolicy(ECapability_None);
+		memcpy(&iPolicy,&apolicy,sizeof(TSecurityPolicy));
+		}
+
+	if(aName.Length() != 0)
+		{
+		iName.Copy(aName);	
+		}
+		
+	iBuffer = static_cast<TUint8*>(Kern::AllocZ(aSize));
+	if(!iBuffer)
+		return KErrNoMemory;
+		
+	// Initialisation
+	_LIT(KMutexName,"PipeMutex");
+	TInt err = Kern::MutexCreate(iPipeMutex, KMutexName, KMutexOrdGeneral0);
+	if (err)
+		{
+		return err;
+		}
+	_LIT(KReadMutex,"ReadMutex");
+	err = Kern::MutexCreate(iReadMutex, KReadMutex, KMutexOrdGeneral1);
+	if (err)
+		{
+		return err;
+		}
+
+	_LIT(KWriteMutex,"WriteMutex");
+	err = Kern::MutexCreate(iWriteMutex, KWriteMutex, KMutexOrdGeneral1);
+	if (err)
+		{
+		return err;
+		}
+
+	iSize = aSize;
+	iWritePointer = iReadPointer = 0;
+	iFull = EFalse;	
+	return KErrNone;		
+	}	
+
+
+TInt DPipe::OpenId()
+/**
+Returns the id of the Pipe
+
+@param	None
+
+@return iID			 ID of the pipe
+*/
+	{
+	//could be const
+	return iID;
+	}
+
+
+void DPipe::SetId(TInt aId)
+/**
+Set the id of the Pipe
+
+@param 	aId		 	The id to be set 
+
+@return None
+*/
+	{
+	//this is only called by the pipe device
+	//it could also be set at construction time
+	iID = aId;	
+	}
+
+
+TBool DPipe::IsPipeClosed()
+/**
+Check if the Pipe is Closed.
+@param	None
+@return TBool		ETure if Successful, otherwise EFalse;
+*/
+	{
+	__ASSERT_MUTEX(iPipeMutex);
+
+	return !(iReadChannel || iWriteChannel);
+	}
+
+
+TBool DPipe::MatchName(const TDesC8* aName)
+/**
+Check if the current instance of DPipe Name is matching with aName parameter
+
+@param	aName		Name to be checked with the current DPipe's name.
+
+@return TBool	  	ETrue if match found, otherwise EFalse
+*/
+	{
+	//name could be const
+ 	return (iName.Compare(*aName) == 0);
+	}
+	
+
+TBool DPipe::MatchId(const TInt aId)
+/**
+Checks if the current instance of DPipe is matching with the aId parameter
+
+@param	aId	 		ID to be checked with the current DPipe's id
+
+@return TBool		ETure if match found , otherwise EFalse;
+*/
+	{
+	return (iID == aId);
+	}
+
+
+TBool DPipe::IsBufferEmpty()
+/**
+Checks if the Buffer is Empty
+
+@param   None
+@return ETrue if buffer is empty
+*/
+	{
+	return (AvailableDataCount()==0);
+	}
+
+
+TInt DPipe::Write(TAny* aBuf, TInt aSize)
+/**
+Synchronous, non-blocking write operation. If the pipe is full it will 
+return immediately with KErrOverflow. A successful DPipe::Write() operation will
+return amount of data written to the pipe.If a request status object has been registered
+for Data Available notification, it will complete.
+
+@param	aBuf		Buffer from which data need to be written to the pipe.
+@param	aSize		Amount of data to be written to the pipe.
+	 
+@return >0			 Amount of data written to the pipe, in octets.
+		KErrNone	 No data written to the pipe.
+		KErrOverflow Pipe is full, cannot write any more data. 
+		KErrArgument If the amount of data to be written is invalid.
+					 Otherwise one of the other system wide error code
+
+@pre iPipeMutex held
+@pre iWriteMutex held
+
+@note Write enters and exists with the pipe mutex held - but releases and reaquires internally
+*/
+	{
+	__KTRACE_OPT(KPIPE, Kern::Printf("DPipe::Write(aBuf=0x%08x, aSize=%d)", aBuf, aSize));
+	
+	__ASSERT_MUTEX(iPipeMutex);
+	__ASSERT_MUTEX(iWriteMutex);
+	// Check for the Invalid  Length
+	if(aSize < 0)
+		{
+		return KErrArgument;
+		}
+
+	if(aSize == 0)
+		{
+		return KErrNone;
+		}
+	
+	//Since only one thread can be writing to the write end
+	//of a pipe it is sufficient that AvailableDataCount
+	//holds the pipe mutex. After it returns the 
+	//available space may increase
+	//but can not decrease
+	const TInt spaceavailable = (iSize - AvailableDataCount());
+	if (spaceavailable < aSize)
+		{
+		//Though the API may suggest otherwise - partial writes are not supported.
+		return KErrOverflow;
+		}
+		
+	//release mutex before IPC read
+	Signal();
+
+	//First half
+	const TDesC8*  pBuf = (const TDesC8*)aBuf;
+
+	const TInt distanceToEnd =  iSize - iWritePointer;
+	const TInt firstHalf = Min(distanceToEnd, aSize);
+	TPtr ptr(&iBuffer[iWritePointer], firstHalf);
+
+	DThread* const currThread = &Kern::CurrentThread();
+	TInt r=Kern::ThreadDesRead(currThread, pBuf, ptr, 0, KChunkShiftBy0);
+	if(r!=KErrNone)
+		{
+		Wait(); //we must exit with mutex held
+		return r;
+		}
+
+	//Second half
+	const TInt secondHalf = aSize - firstHalf;
+	__NK_ASSERT_DEBUG( secondHalf >= 0);
+	if(secondHalf != 0)	
+		{
+		ptr.Set(&iBuffer[0], secondHalf, secondHalf);
+
+		r = Kern::ThreadDesRead(currThread, pBuf, ptr, firstHalf, KChunkShiftBy0);
+		if(r!=KErrNone)
+			{
+			Wait(); //we must exit with mutex held
+			return r;
+			}
+		}
+	
+	Wait(); //reaquire mutex for state update
+	iWritePointer = (iWritePointer + aSize)% iSize;	
+		
+	if(iWritePointer == iReadPointer)
+		{
+		iFull = ETrue;
+		}
+		
+	if(iDataAvailableRequest)
+		{
+		iReadChannel->DoRequestCallback();
+		iDataAvailableRequest = EFalse;		
+		}
+
+	return aSize;
+	}
+
+
+TInt DPipe::Read(TAny* aBuf, TInt aSize)
+/**
+Synchronous, non-blocking read operation. If the pipe is empty it will 
+return immediately with KErrUnderflow. A successful DPipe::Read() operation 
+will free up more space in the pipe. If a request status object has been registered
+for Space Available notification, it will complete. Note that there is no 
+guarantee that the amount of space freed up in the pipe will be sufficient 
+for the next DPipe::Write() operation.
+
+@param	aBuff		Buffer to which data need to be written.
+@param	aSize		Size of the data to be read from the pipe.
+
+@return	>0			 Amount of data read from the pipe, in octets.
+		KErrNone	 The pipe is empty , no data was read from the pipe.
+		KErrArgument If the amount of data to be read is invalid.
+					 Otherwise one of the system wide error code
+@pre iPipeMutex held
+@pre iReadMutex held
+
+@note Read enters and exists with the pipe mutex held - but releases and reaquires internally
+*/
+	{	
+	__KTRACE_OPT(KPIPE, Kern::Printf("DPipe::Read(aBuf=0x%08x, aSize=%d)", aBuf, aSize));
+	__ASSERT_MUTEX(iPipeMutex);
+	__ASSERT_MUTEX(iReadMutex);
+		
+	if(aSize < 0)
+		{
+		return KErrArgument;
+		}
+	
+	const TInt totalToRead = Min(AvailableDataCount(), aSize);
+	
+
+	if(totalToRead == 0)
+		return 0;
+
+	Signal();
+
+
+	//! First half	
+	const TInt distanceToEnd = iSize - iReadPointer;
+	__NK_ASSERT_DEBUG(distanceToEnd>=0);
+	const TInt firstHalf = Min(totalToRead, distanceToEnd);
+
+	TPtrC8 pipeBuffer(&iBuffer[iReadPointer], firstHalf);
+	TDes8* userBuffer = (TDes8*)aBuf;
+
+	DThread* const currThread = &Kern::CurrentThread();
+	TInt r = Kern::ThreadDesWrite(currThread, userBuffer, pipeBuffer, 0, KChunkShiftBy0, NULL); 
+	if(r!=KErrNone)
+		{
+		Wait(); //we must exit with mutex held
+		return r;
+		}
+	
+	const TInt secondHalf=totalToRead-firstHalf;
+	__NK_ASSERT_DEBUG(secondHalf>=0);
+	if(secondHalf!=0)
+		{
+	    //! Second half
+		pipeBuffer.Set(&iBuffer[0], secondHalf);
+		r = Kern::ThreadDesWrite(currThread, userBuffer, pipeBuffer, firstHalf, KChunkShiftBy0, NULL);
+		if(r!=KErrNone)
+			{
+			Wait(); //we must exit with mutex held
+			return r;
+			}
+		}
+	__NK_ASSERT_DEBUG(firstHalf+secondHalf==totalToRead);
+
+	Wait(); //Reaquire mutex for state update
+
+	iReadPointer = (iReadPointer + totalToRead)% iSize;
+	iFull = EFalse;
+	MaybeCompleteSpaceNotification();
+		
+	__ASSERT_MUTEX(iReadMutex);
+	return totalToRead;			
+	}
+
+TInt DPipe::AvailableDataCount()
+/**
+Returns the Data available in the pipe. 
+
+@param	None
+
+@return TInt  Amount of data available in the pipe
+
+*/
+	{
+	__ASSERT_MUTEX(iPipeMutex);
+	TInt size=-1;
+	if ( iWritePointer > iReadPointer )
+		{
+		size = iWritePointer - iReadPointer;
+		}
+	else if ( iReadPointer > iWritePointer )
+		{
+		size = iSize - iReadPointer + iWritePointer;
+		}
+	else 
+		{
+		//iReadPointer == iWritePointer
+		size = iFull ? iSize : 0;
+		}
+	return size;
+	}
+
+TInt DPipe::RegisterSpaceAvailableNotification(TInt aSize)
+/**
+Registers the request status object to be completed when space becomes 
+available in the pipe. 
+
+@param	aSize			The size for which the space availability be notified.
+
+@return KErrNone		Success.
+	    KErrCompletion	The request is not registered as it completes immediately
+	    				otherwise one of the system wide error code.
+@pre   Mutex must be held.
+@pre   Must be in a critical section.
+*/
+	{
+	__ASSERT_MUTEX(iPipeMutex);
+	__NK_ASSERT_DEBUG(Rng(1, aSize, iSize));
+
+	// Check if Specified size is available.
+	TInt err = KErrNone;
+	if ((aSize <= (iSize - AvailableDataCount())))
+		{
+		iSpaceAvailableRequest = EFalse;
+		err = KErrCompletion;
+		}
+	else
+		{
+		iSpaceAvailableSize  = aSize;
+		iSpaceAvailableRequest = ETrue;	
+		}
+    return err;
+	}
+
+
+TInt DPipe::RegisterDataAvailableNotification()
+/**
+Registers the request status object to be completed when data becomes 
+available in the pipe. 
+
+@param	None
+
+@return KErrNone	If successful, otherwise one of the other system wide
+					error code.
+@pre   Mutex must be held.
+@pre   Must be in a critical section.
+*/
+	{
+	__ASSERT_MUTEX(iPipeMutex);
+
+	TInt err = KErrNone;
+	// Check if Data is available.
+	if(AvailableDataCount())
+		{
+		iDataAvailableRequest = EFalse;
+		err = KErrCompletion;
+		}
+	else
+		{
+		iDataAvailableRequest = ETrue;
+		}	
+ 	return err;
+	}
+
+
+TInt DPipe::RegisterWaitNotification(TInt aChoice)	
+/**
+Registers the request status object to be completed when other end of the pipe
+is opened for reading. This method completes immediately if the other end of the
+pipe is already opened.
+
+@param 	None
+
+@return KErrNone	Successfully registered, otherwise one of the other system wide
+					error code.
+@pre Mutex must be held.
+@pre Must be in a critical section.
+*/
+	{
+	__ASSERT_MUTEX(iPipeMutex);
+
+	TInt err = KErrNone;
+	// Check if Read end is opened
+	if (aChoice == RPipe::EWaitForReader) 
+		{
+		if(IsReadEndOpened())
+			{	
+			iWaitRequest = EFalse;
+			err = KErrCompletion;
+			}
+		else
+			{
+			iWaitRequest = ETrue;
+			}	
+			
+		}
+	else 
+		{
+		if(IsWriteEndOpened())
+			{	
+			iWaitRequest = EFalse;
+			err = KErrCompletion;
+			}
+		else
+			{
+			iWaitRequest = ETrue;
+			}	
+		}
+	
+	return err;
+	}
+
+
+//! Cancellation methods
+void DPipe::CancelSpaceAvailable()
+/**
+Cancels an outstanding space available notifier request.
+
+@param  None
+
+@return None
+*/
+	{	
+	__ASSERT_MUTEX(iPipeMutex);
+	if(iSpaceAvailableRequest)	
+		iSpaceAvailableRequest = EFalse;
+	}
+
+
+void DPipe::CancelDataAvailable()
+/**
+Cancels an outstanding data available notifier request.
+
+@param None
+
+@return None
+*/
+	{
+	__ASSERT_MUTEX(iPipeMutex);
+	if(iDataAvailableRequest)
+		iDataAvailableRequest = EFalse;
+	}
+
+
+void DPipe::CancelWaitNotifier()
+/**
+Cancel an outstanding wait notifier request
+
+@param	None
+
+@return	KErrNone		If Successful, otherwise one of the other system wide error code.
+	
+*/
+	{
+	__ASSERT_MUTEX(iPipeMutex);
+	// Cancel Wait Notifier request
+	if(iWaitRequest)
+		iWaitRequest = EFalse;
+	}
+
+
+void DPipe::CloseAll()
+/**
+Cancel any outstanding request. 
+
+@param	 None
+
+@return  None
+*/
+	{
+	CancelSpaceAvailable();
+	CancelDataAvailable();
+	CancelWaitNotifier();
+	
+	CloseWriteEnd();
+  	CloseReadEnd(); 
+	}
+
+
+TInt DPipe::CloseReadEnd()
+/**
+Close the read end of the pipe.
+
+Cancels outstanding requests placed by the *write*
+channel and clears pipe's pointer to the read channel.
+If this function is called then the read channel's back
+pointer to the pipe must also be cleared.
+
+@param	None
+
+@return KErrNone 	If the end is closed, else  one  of the other system 
+					wide error code
+*/
+	{
+	__ASSERT_MUTEX(iPipeMutex);
+	__KTRACE_OPT(KPIPE, Kern::Printf(">DPipe::CloseReadEnd ID=%d, iReadChannel=0x%08x", OpenId(), iReadChannel)); 
+
+	if (!iReadChannel)
+		return KErrCouldNotDisconnect;
+	else
+		{
+		if(iWriteChannel)
+			{
+			iWriteChannel->CancelRequest(RPipe::ECancelSpaceAvailable);	
+			}
+		iReadChannel = NULL;
+		}		
+	return KErrNone;
+	}
+
+
+TInt  DPipe::CloseWriteEnd()
+/**
+Close the write end of the pipe
+
+Cancels outstanding requests placed by the *read*
+channel and clears pipe's pointer to the write channel.
+If this function is called then the write channel's back
+pointer to the pipe must also be cleared.
+
+@param	None
+
+@return KErrNone 	If the write end is successfully closed, else
+	                one of the other system wide error code.
+*/
+	{
+	__ASSERT_MUTEX(iPipeMutex);
+	__KTRACE_OPT(KPIPE, Kern::Printf(">DPipe::CloseWriteEnd ID=%d, iWriteChannel=0x%08x", OpenId(), iWriteChannel)); 
+
+	if (!iWriteChannel)
+		return KErrCouldNotDisconnect;
+	else
+		{
+		// Cancel RBlocking call if it is there
+		if(iReadChannel)
+			{
+			iReadChannel->CancelRequest(RPipe::ECancelDataAvailable);	
+			}
+		iWriteChannel = NULL;	
+		}
+	return KErrNone;				
+	}
+	
+	
+
+void DPipe::FlushPipe()
+/**
+Flush all the date from the pipe and reinitialise the buffer pointer.
+
+@param 	None
+
+@return None
+
+@pre 	Pipe Mutex to be held
+@pre 	Read Mutex to be held
+
+*/
+	{
+	__ASSERT_MUTEX(iPipeMutex);
+	__ASSERT_MUTEX(iReadMutex);
+
+	iReadPointer = iWritePointer;
+	iFull	= EFalse;
+	
+	MaybeCompleteSpaceNotification();	
+	}
+
+/**
+If there is an outstanding space request, and
+there is enough space to satisfy it then complete
+and clear request.
+
+@pre the pipe mutex must be held
+*/
+void DPipe::MaybeCompleteSpaceNotification()
+	{
+	__ASSERT_MUTEX(iPipeMutex);
+
+	// Check if there is writeblocking request
+	if(iSpaceAvailableRequest) 
+		{
+		const TInt spacecount = (iSize - AvailableDataCount());
+		if (iSpaceAvailableSize <= spacecount)
+			{
+			iWriteChannel->DoRequestCallback();
+			iSpaceAvailableRequest = EFalse;		
+			}	
+		}
+	}
+
+TBool DPipe::IsReadEndOpened()
+/**
+Returns information regarding the read end of the current pipe instance.
+
+@return TBool	ETrue if read end is Opened, otherwise EFalse
+@pre the pipe mutex must be held
+*/
+	{
+	__ASSERT_MUTEX(iPipeMutex);
+	return (iReadChannel != NULL);
+	}
+
+
+TBool DPipe::IsWriteEndOpened()
+/**
+Returns information regarding the write end of the current pipe instance.
+
+@return  TBool ETrue if WriteChannel is opened, otherwise EFalse
+@pre the pipe mutex must be held
+*/
+	{
+	__ASSERT_MUTEX(iPipeMutex);
+	return (iWriteChannel != NULL);
+	}
+
+
+TBool DPipe::IsNamedPipe()
+/**
+Returns whether the pipe is named or unnamed.
+
+@return TBool  ETrue if it is a named pipe, otherwise EFalse
+
+*/
+	{
+	return (iName.Length() != 0); 
+	}
+
+
+void DPipe::SetReadEnd(DPipeChannel* aChannel)
+/**
+Set the Read end of the pipe as opened and store the pointer for the read channel
+It also notify if there is any pending Wait Request.
+
+@param	aChannel	The pointer to the read channel
+
+@pre the pipe mutex must be held
+@pre The pipe's read end must be closed ie. IsReadEndOpened returns false
+*/
+	{
+	__ASSERT_MUTEX(iPipeMutex);
+	__KTRACE_OPT(KPIPE, Kern::Printf(">DPipe::SetReadEnd ID=%d", OpenId())); 
+
+
+	//A channel must be sure this function
+	//succeeded otherwise the pipe
+	//could be destroyed without the channel's
+	//knowledge
+	__NK_ASSERT_DEBUG(iReadChannel==NULL);
+
+	iReadChannel = aChannel;
+	__KTRACE_OPT(KPIPE, Kern::Printf("DPipe::SetReadEnd set iReadChannel=0x%08x", iReadChannel)); 
+	
+	if(iWaitRequest)
+		{
+		if(iWriteChannel)
+			iWriteChannel->DoRequestCallback();
+		iWaitRequest=EFalse;
+		}
+	}
+	
+
+void DPipe::SetWriteEnd(DPipeChannel* aChannel)
+/**
+Set the write end of the pipe as opened and store the pointer to the write channel
+
+@param aChannel		The pointer to the write channel
+
+
+@pre the pipe mutex must be held
+@pre The pipe's write end must be closed ie. IsWriteEndOpened returns false
+*/
+	{
+	__ASSERT_MUTEX(iPipeMutex);
+	__KTRACE_OPT(KPIPE, Kern::Printf(">DPipe::SetWriteEnd ID=%d", OpenId())); 
+
+	//A channel must be sure this function
+	//succeeded otherwise the pipe
+	//could be destroyed without the channel's
+	//knowledge
+	__NK_ASSERT_DEBUG(iWriteChannel==NULL);
+
+	iWriteChannel = aChannel;
+	__KTRACE_OPT(KPIPE, Kern::Printf("DPipe::SetWriteEnd set iWriteChannel=0x%08x", iWriteChannel)); 
+
+	if(iWaitRequest)
+		{
+		if(iReadChannel)
+			iReadChannel->DoRequestCallback();
+		iWaitRequest=EFalse;
+		}		
+	}
+
+TInt DPipe::Size()
+/**
+@return The size of the pipe's circular buffer 
+*/
+	{
+	//this could be const
+	return iSize;	
+	}
+