genericopenlibs/cstdlib/USTLIB/UPIPE.CPP
changeset 0 e4d67989cc36
--- /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*)&param,4);
+		TRAP(ret,iIoctlMessage.WriteL(2,paramReturn,0));
+		}
+	iIoctlMessage.Complete(ret);
+	iClientIoctlPending=0;
+	}