--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/genericopenlibs/cstdlib/USTLIB/UPIPE.CPP Tue Feb 02 02:01:42 2010 +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 <sys/errno.h>
+#include <sys/stat.h>
+
+// 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;
+ }