diff -r 000000000000 -r bde4ae8d615e os/ossrv/genericopenlibs/cstdlib/USTLIB/UPIPE.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/ossrv/genericopenlibs/cstdlib/USTLIB/UPIPE.CPP Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,514 @@ +// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "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: +// Implementation of pipes +// +// + +#include "POSIXIF.H" +#include +#include + +// Child end of the pipe + +CPipeChildDesc::CPipeChildDesc(TInt anIndex, RPosixSession& aSession) + : CFileDescBase(), iIndex(anIndex), iSession(aSession), iParamDes(0,0,0) + {} + +TInt CPipeChildDesc::LSeek (int&, int) + { + return ESPIPE; // can't seek on a pipe + } + +TInt CPipeChildDesc::FStat(struct stat *st) + { + // I am a fifo about which little is known + st->st_mode = S_IFIFO; + st->st_blksize=0; + return KErrNone; + } + +void CPipeChildDesc::Read (TDes8& aBuf, TRequestStatus& aStatus) + { + if (iClientClosed || !IsReadable()) + { + Complete(aStatus,KErrEof); + return; + } + TIpcArgs args(iIndex,&aBuf,aBuf.MaxLength()); + iSession.Request(PMPipeRead,args,aStatus); // asynchronous request + } + +void CPipeChildDesc::ReadCancel() + { + Cancel(PMPipeRead); + } + +TInt CPipeChildDesc::ReadCompletion(TDes8& aDesc, TInt aStatus) + { + if (aStatus==KErrEof) + { + ClientClose(); + aDesc.Zero(); // set read length to zero + return KErrNone; // indicates graceful close at the other end + } + return aStatus; + } + +void CPipeChildDesc::Write(TDes8& aDesc, TRequestStatus& aStatus) + { + if (iClientClosed || !IsWriteable()) + { + Complete(aStatus,KErrEof); + return; + } + TIpcArgs args(iIndex,&aDesc,aDesc.Length()); + iSession.Request(PMPipeWrite,args,aStatus); // asynchronous request + } + +void CPipeChildDesc::WriteCancel() + { + Cancel(PMPipeWrite); + } + +TInt CPipeChildDesc::WriteCompletion(TDes8& /*aDesc*/, TInt aStatus) + { + if (aStatus==KErrEof) + ClientClose(); + return aStatus; + } + +void CPipeChildDesc::Ioctl(int aCmd, void* aParam, TRequestStatus& aStatus) +// +// The work of the Ioctl is done in the parent, including writing back to aParam? +// Use the default completion which just returns aStatus.Int() +// + { + if (iClientClosed) + { + Complete(aStatus,KErrEof); + return; + } + iParamDes.Set((TText8*)aParam,4,4); + TIpcArgs args(iIndex,aCmd,&iParamDes); + if (aCmd==E32IOSELECT) + args.Set(3, *((TInt*)aParam)); + iSession.Request(PMPipeIoctl,args,aStatus); // asynchronous request + } + +void CPipeChildDesc::IoctlCancel() + { + Cancel(PMPipeIoctl); + } + +void CPipeChildDesc::Cancel(TInt aType) + { + if (iClientClosed) + return; + TIpcArgs args(iIndex,aType); + iSession.Request(PMPipeCancel,args); + } + +TInt CPipeChildDesc::FinalClose() + { + ClientClose(); + TIpcArgs args(iIndex); + return iSession.Request(PMPipeClose,args); // synchronous request + } + +// +// Parent end of the pipe, where the real work is done +// + +CPipeDesc::CPipeDesc(TInt anIndex) : CFileDescBase() + { + iIndex=anIndex; + } + +void CPipeDesc::SetClientSide(CPipeDesc*& aClientPointer) + { + iClientSide=&aClientPointer; + } + +_LIT(KCPipeDescPanic, "CPipeDesc"); +void CPipeDesc::Panic(TInt aReason) + { + User::Panic(KCPipeDescPanic,aReason); + } + +void CPipeDesc::Panic(RMessage2& aMessage, TInt aReason) + { + aMessage.Panic(KCPipeDescPanic,aReason); + } + +TInt CPipeDesc::LSeek (int&, int) + { + return ESPIPE; // can't seek on a pipe + } + +TInt CPipeDesc::FStat(struct stat *st) + { + // I am a fifo about which little is known + st->st_mode = S_IFIFO; + st->st_blksize=0; + return KErrNone; + } + +void CPipeDesc::Read (TDes8& aBuf, TRequestStatus& aStatus) + { + if (!IsReadable()) + { + Complete(aStatus, KErrEof); // avoids treading on iStatus of pending Write + return; + } + __ASSERT_DEBUG(iStatus==0,Panic(1)); + iStatus=&aStatus; + if (iClientClosed) + { + User::RequestComplete(iStatus,KErrEof); + return; + } + iReadBuf=&aBuf; + if (ClientIoctlPending()) + CompleteClientIoctl(); + if (iClientLength!=0) + TransferFromClient(); + } + +void CPipeDesc::ReadCancel() + { + Cancel(); + } + +TInt CPipeDesc::ReadCompletion(TDes8& aDesc, TInt aStatus) + { + if (aStatus==KErrEof) + { + ClientClose(); + aDesc.Zero(); // set read length to zero + return KErrNone; // indicates graceful close at the other end + } + return aStatus; + } + +void CPipeDesc::Write(TDes8& aDesc, TRequestStatus& aStatus) + { + if (!IsWriteable()) + { + Complete(aStatus, KErrEof); // avoids treading on iStatus of pending Read + return; + } + __ASSERT_DEBUG(iStatus==0,Panic(2)); + iStatus=&aStatus; + if (iClientClosed) + { + User::RequestComplete(iStatus,KErrEof); + return; + } + iWriteBuf.Set(aDesc); + if (ClientIoctlPending()) + CompleteClientIoctl(); + if (iClientLength!=0) + TransferToClient(); + } + +void CPipeDesc::WriteCancel() + { + Cancel(); + } + +TInt CPipeDesc::WriteCompletion(TDes8& /*aDesc*/, TInt aStatus) + { + if (aStatus==KErrEof) + ClientClose(); + return aStatus; + } + +void CPipeDesc::Ioctl(int aCmd, void* aParam, TRequestStatus& aStatus) + { + TInt ret=KErrNone; + iIoctlStatus=&aStatus; + int *param=REINTERPRET_CAST(int*,aParam); + switch (aCmd) + { + case E32IONREAD: + // synchronous ioctls are handled in the completion routine. + break; + case E32IOSELECT: + { + int mask=(*param)&SelectMask(); + if (mask!=0 && iClientLength==0) + return; // wait for client to show up + } + break; + default: + ret=KErrNotSupported; + break; + } + User::RequestComplete(iIoctlStatus,ret); + } + +TInt CPipeDesc::IoctlCompletion(int aCmd, void* aParam, TInt aStatus) + { + TInt ret=aStatus; + if (ret!=KErrNone) + return ret; + int *param=REINTERPRET_CAST(int*,aParam); + switch (aCmd) + { + case E32IONREAD: + if (IsReadable()) + *param=iClientLength; // 0 if no outstanding client data + else + *param=0; // claim that no data is available + break; + case E32IOSELECT: + { + int mask=0; + if (iClientLength!=0) + mask = SelectMask(); + *param=(*param)&mask; + } + break; + default: + ret=KErrNotSupported; + break; + } + return ret; + } + +void CPipeDesc::IoctlCancel() + { + User::RequestComplete(iIoctlStatus,KErrCancel); + } + +void CPipeDesc::Cancel() + { + // Pipes are unidirectional, so don't need to distinguish between + // ReadCancel and WriteCancel + User::RequestComplete(iStatus,KErrCancel); + } + +// Client-side interface + +void CPipeDesc::ClientWrite(const RMessage2& aMessage) + { + __ASSERT_DEBUG(iClientLength==0,Panic(3)); + if (iClientClosed) + { + aMessage.Complete(KErrEof); + return; + } + iClientLength=aMessage.Int2(); + iClientOffset=0; + iMessage=aMessage; + if (iIoctlStatus!=0) + User::RequestComplete(iIoctlStatus,KErrNone); + if (iStatus!=0) + TransferFromClient(); + } + +void CPipeDesc::ClientRead(const RMessage2& aMessage) + { + __ASSERT_DEBUG(iClientLength==0,Panic(4)); + if (iClientClosed) + { + aMessage.Complete(KErrEof); + return; + } + iClientLength=aMessage.Int2(); + iMessage=aMessage; + if (iIoctlStatus!=0) + User::RequestComplete(iIoctlStatus,KErrNone); + if (iStatus!=0) + TransferToClient(); + } + +void CPipeDesc::ClientIoctl(const RMessage2& aMessage) + { + __ASSERT_DEBUG(!ClientIoctlPending(),Panic(7)); + if (iClientClosed) + { + aMessage.Complete(KErrEof); + return; + } + iClientIoctlPending=1; + iIoctlMessage=aMessage; + TInt ret=KErrNone; + switch (aMessage.Int1()) + { + case E32IONREAD: + // synchronous ioctls are handled in the completion routine. + break; + case E32IOSELECT: + { + int mask=aMessage.Int3(); + mask&=ClientSelectMask(); + if (mask!=0 && iStatus==0) + return; // wait for parent activity + } + break; + default: + ret=KErrNotSupported; + break; + } + CompleteClientIoctl(ret); + } + +void CPipeDesc::ClientCancel(const RMessage2& aMessage) + { + if (aMessage.Int1()==PMPipeIoctl) + { + if (ClientIoctlPending()) + CompleteClientIoctl(KErrCancel); + return; + } + // Pipes are unidirectional, so Read and Write are cancelled by + // cancelling the current client operation. + // + if (iClientLength!=0) + { + iMessage.Complete(KErrCancel); + iClientLength=0; + } + } + +void CPipeDesc::ClientClose() + { + iClientClosed=1; + // terminate any pending requests + if (iStatus!=0) + User::RequestComplete(iStatus,KErrEof); + if (ClientIoctlPending()) + CompleteClientIoctl(KErrEof); + if (iClientLength!=0) + { + iMessage.Complete(KErrEof); + iClientLength=0; + } + } + +TInt CPipeDesc::FinalClose() + { + ClientClose(); + if (iClientSide) + { + *iClientSide=0; + iClientSide=0; + } + return KErrNone; + } + +void CPipeDesc::TransferFromClient() +// +// Handle transfer of data from client to parent. +// Always complete the parent read, but only complete the child write when +// all of the data has been consumed. +// + { + TRAPD(err,iMessage.ReadL(1,*iReadBuf,iClientOffset)); + if (err) + { + Panic(iMessage,5); + iClientLength=0; + ClientClose(); // will complete the parent read + return; + } + TInt length=iReadBuf->Length(); // record the amount of data transferred + User::RequestComplete(iStatus,KErrNone); + iClientOffset+=length; + iClientLength-=length; + if (iClientLength==0) + iMessage.Complete(KErrNone); + } + +void CPipeDesc::TransferToClient() +// +// Handle transfer from parent to client +// Always complete the client read, but only complete the parent write when +// all of the data has been consumed. +// + { + TInt err=KErrNone; + TInt length=iWriteBuf.Length(); + TInt written=length; + if (iClientLength >= length) + { + TRAP(err,iMessage.WriteL(1,iWriteBuf,0)); + } + else + { + written=iClientLength; + TRAP(err,iMessage.WriteL(1,iWriteBuf.Left(written),0)); + } + iClientLength=0; + if (err) + { + Panic(iMessage,6); + ClientClose(); // will complete the parent write + return; + } + iMessage.Complete(KErrNone); + length-=written; + if (length==0) + User::RequestComplete(iStatus,KErrNone); + else + iWriteBuf.Set(iWriteBuf.Right(length)); + } + +void CPipeDesc::CompleteClientIoctl(TInt ret) + { + if (ret!=KErrNone) + { + iIoctlMessage.Complete(ret); + iClientIoctlPending=0; + return; + } + CompleteClientIoctl(); + } + +void CPipeDesc::CompleteClientIoctl() +// +// Complete outstanding PMPipeIoctl message +// + { + TInt ret=KErrNone; + int param=0; + switch (iIoctlMessage.Int1()) + { + case E32IONREAD: + if (IsWriteable() && iStatus!=0) + param=iWriteBuf.Length(); + else + param=0; // claim that no data is available + break; + case E32IOSELECT: + { + int mask=0; + if (iStatus!=0) + mask=ClientSelectMask(); + param=(iIoctlMessage.Int3())&mask; + } + break; + default: + ret=KErrNotSupported; + break; + } + if (ret==KErrNone) + { + TPtrC8 paramReturn((const TText8*)¶m,4); + TRAP(ret,iIoctlMessage.WriteL(2,paramReturn,0)); + } + iIoctlMessage.Complete(ret); + iClientIoctlPending=0; + }