diff -r 000000000000 -r 7f656887cf89 core/extra/pipsrun/pipsrun.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/extra/pipsrun/pipsrun.cpp Wed Jun 23 15:52:26 2010 +0100 @@ -0,0 +1,227 @@ +// pipsrun.cpp +// +// Copyright (c) 2008 - 2010 Accenture. All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the "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: +// Accenture - Initial contribution +// + +#include +#include +#include +#include +#include + +const TInt KBlockSize = 512; + +using namespace IoUtils; + +class CCmdPipsRun : public CCommandBase + { +public: + static CCommandBase* NewLC(); + ~CCmdPipsRun(); +private: + CCmdPipsRun(); +private: // From CCommandBase. + virtual const TDesC& Name() const; + virtual const TDesC& Description() const; + virtual void DoRunL(); + }; + + +CCommandBase* CCmdPipsRun::NewLC() + { + CCmdPipsRun* self = new(ELeave) CCmdPipsRun(); + CleanupStack::PushL(self); + self->BaseConstructL(); + return self; + } + +CCmdPipsRun::~CCmdPipsRun() + { + } + +CCmdPipsRun::CCmdPipsRun() : CCommandBase(ESharableIoSession) + { + } + +const TDesC& CCmdPipsRun::Name() const + { + _LIT(KName, "pipsrun"); + return KName; + } + +const TDesC& CCmdPipsRun::Description() const + { + _LIT(KDescription, "Internal helper executable for launching processes that use PIPS in such a way that they can interact with fshell's I/O primitives. You should not call it directly."); + return KDescription; + } + +const TUint8* GetDesParamLC(TInt aSlot) + { + TInt paramLen = User::ParameterLength(aSlot); + StaticLeaveIfErr(paramLen, _L("Couldn't read environment slot %d"), aSlot); + HBufC* buf = HBufC::NewLC(paramLen + 1); // + 1 for the terminating null character. + TPtr bufPtr(buf->Des()); + User::LeaveIfError(User::GetDesParameter(aSlot, bufPtr)); + TPtr8 narrowPtr = buf->Des().Collapse(); + narrowPtr.ZeroTerminate(); + return narrowPtr.Ptr(); + } + +void AppendNarrowDes(TUint8*& aTarget, const TDesC& aDes) + { + TInt len = aDes.Length(); + const TUint16 *pS = aDes.Ptr(); + const TUint16 *pE = pS + len; + while (pS < pE) + { + TUint c = (*pS++); + if (c >= 0x100) + { + c = 1; + } + *aTarget++ = (TUint8)c; + } + } + +class TGlueParams + { +public: + TGlueParams(TInt aFileDescriptor, RIoWriteHandle aWriteHandle); +public: + TInt iFileDescriptor; + RIoWriteHandle iWriteHandle; + }; + +TGlueParams::TGlueParams(TInt aFileDescriptor, RIoWriteHandle aWriteHandle) + : iFileDescriptor(aFileDescriptor), iWriteHandle(aWriteHandle) + { + } + +void* GlueFileDescriptor(void* aParams) + { + TGlueParams* params = (TGlueParams*)aParams; + TBuf8 buf; + ssize_t s; + TInt err = KErrNone; + do + { + s = read((int)params->iFileDescriptor, (char*)buf.Ptr(), KBlockSize); + if (s > 0) + { + buf.SetLength(s); + err = params->iWriteHandle.Write(buf.Expand()); + } + } + while ((s > 0) && (err == KErrNone)); + return (void*)err; + } + +void CCmdPipsRun::DoRunL() + { + // Pack the envronment object we inherited from fshell in the way POSIX expects. + _LIT(KEquals, "="); + _LIT(KNull, "\x0"); + const CEnvironment& env = Env(); + RPointerArray keys; + LtkUtils::CleanupResetAndDestroyPushL(keys); + env.GetKeysL(keys); + const TInt numVars = keys.Count(); + TUint8** envp = (TUint8**)User::AllocLC((numVars + 1) * sizeof(TInt*)); // + 1 because the last pointer must be NULL. + for (TInt i = 0; i < numVars; ++i) + { + const TDesC& key = *keys[i]; + const TDesC& val = env.GetAsDesL(key); + const TInt length = (key.Length() + 2 + val.Length()); // 2 for the delimiting '=' and the terminating null. + TUint8* p = (TUint8*)User::AllocLC(length); + envp[i] = p; + AppendNarrowDes(p, key); + AppendNarrowDes(p, KEquals); + AppendNarrowDes(p, val); + AppendNarrowDes(p, KNull); + } + envp[numVars] = NULL; + + const TUint8* commandName(GetDesParamLC(IoUtils::KPipsCommandNameProcessSlot)); + const TUint8* commandLine(GetDesParamLC(IoUtils::KPipsCommandLineProcessSlot)); + TInt fds[3]; + TInt pid = popen3((const char*)commandName, (const char*)commandLine, (char**)envp, fds); + if (pid == -1) + { + User::Leave(KErrGeneral); + } + CleanupStack::PopAndDestroy(2 + numVars + 1); + CleanupStack::PopAndDestroy(&keys); + + RProcess childProcess; + User::LeaveIfError(childProcess.Open(pid)); + CleanupClosePushL(childProcess); + TRequestStatus childProcessStatus; + childProcess.Logon(childProcessStatus); + RProcess::Rendezvous(pid); + + pthread_t stdoutReaderThreadId = 0; + pthread_t stderrReaderThreadId = 0; + pthread_attr_t threadAttr; + pthread_attr_init(&threadAttr); + pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED); + TGlueParams stdoutParams(fds[1], Stdout()); + TGlueParams stderrParams(fds[2], Stderr()); + TInt err = pthread_create(&stdoutReaderThreadId, &threadAttr, GlueFileDescriptor, (void*)&stdoutParams); + if (err == 0) + { + err = pthread_create(&stderrReaderThreadId, &threadAttr, GlueFileDescriptor, (void*)&stderrParams); + } + if (err != 0) + { + User::Leave(err); + } + + Stdin().SetReadMode(RIoReadHandle::EOneOrMore); + TBuf buf; + TRequestStatus stdinReadStatus; + TBool finished(EFalse); + while (!finished) + { + Stdin().Read(buf, stdinReadStatus); + User::WaitForRequest(childProcessStatus, stdinReadStatus); + if (childProcessStatus == KRequestPending) + { + TPtr8 narrowPtr(buf.Collapse()); + narrowPtr.ZeroTerminate(); + do + { + TInt ret = write(fds[0], narrowPtr.Ptr(), narrowPtr.Length()); + if (ret < 0) + { + finished = ETrue; + } + else + { + narrowPtr.Set(narrowPtr.MidTPtr(ret)); + } + } + while (!finished && narrowPtr.Length()); + } + else + { + finished = ETrue; + Stdin().ReadCancel(); + User::WaitForRequest(stdinReadStatus); + } + } + + CleanupStack::PopAndDestroy(&childProcess); + pthread_join(stdoutReaderThreadId, NULL); + pthread_join(stderrReaderThreadId, NULL); + Complete(childProcessStatus.Int()); + } + +EXE_BOILER_PLATE(CCmdPipsRun) +