Convert Kernelhwsrv package from SFL to EPL
kernel\eka\compsupp is subject to the ARM EABI LICENSE
userlibandfileserver\fatfilenameconversionplugins\unicodeTables is subject to the Unicode license
kernel\eka\kernel\zlib is subject to the zlib license
// 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;
}