diff -r 000000000000 -r 96e5fb8b040d kernel/eka/drivers/pipe/dpipe.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/pipe/dpipe.cpp Thu Dec 17 09:24:54 2009 +0200 @@ -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 +#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; countWait(); + 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("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(aObjMatchName(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 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 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 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(iDevice); + + //must wait on device since after creation + //the pipe becomes globably findable + //and destroyable + TAutoWait outerAutoMutex(device.Mutex()); + + TInt err = ((DPipeDevice*)iDevice)->CreatePipe(name, size, pipe, securityPolicy); + if(err!= KErrNone) + { + return err; + } + + TAutoWait 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(iDevice); + + TAutoWait outerAutoMutex(device.Mutex()); + + DPipe* pipe = device.CreatePipe(aSize); + if(pipe == NULL) + { + return KErrNoMemory; + } + + TAutoWait 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(iDevice); + + //need to hold the device mutex to + //prevent the pipe getting deleted before we can call + //SetWriteEnd + TAutoWait outerAutoMutex(device.Mutex()); + DPipe* pipe = device.FindNamedPipe(&PName); + + if(pipe == NULL) + { + return KErrNotFound; + } + + TAutoWait 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(iDevice); + TAutoWait outerAutoMutex(device.Mutex()); + + DPipe* pipe = device.FindUnnamedPipe(aId); + if(pipe == NULL) + { + return KErrNotFound; + } + + TAutoWait 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(iDevice); + + TAutoWait outerAutoMutex(device.Mutex()); + + DPipe* pipe = device.FindNamedPipe(&PName); + if(pipe == NULL) + { + return KErrNotFound; + } + + + TAutoWait 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 outerAutoMutex(*iData->iReadMutex); + TAutoWait 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 outerAutoMutex(*iData->iWriteMutex); + TAutoWait 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(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 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 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 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 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 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(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; + } +