# HG changeset patch # User Tom Sutcliffe # Date 1288281294 -3600 # Node ID b3ffff030d5c0373de33063ad4458a4c91ef62d8 # Parent 8df58d8c99e8ab0c241bd4edf9d64d6d73c20dce Pulled in from FCL: input, base64, fshell thread pool Also: * fed console size fixes * fzip smoketest * CBtraceAppStart diff -r 8df58d8c99e8 -r b3ffff030d5c build/common/common.mmh --- a/build/common/common.mmh Tue Oct 26 15:36:30 2010 +0100 +++ b/build/common/common.mmh Thu Oct 28 16:54:54 2010 +0100 @@ -571,6 +571,8 @@ #define FSHELL_UID_VT100USBCONS 0x10286F8A #define FSHELL_UID_WIN32CONS 0x10286F8B #define FSHELL_UID_SHOWDEBUG 0x10286F8D +#define FSHELL_UID_INPUT 0x10286B7D +#define FSHELL_UID_BASE64 0x10286B7E #else // Not FSHELL_PROTECTED_UIDS @@ -725,6 +727,8 @@ #define FSHELL_UID_VT100USBCONS 0xE0286F8A #define FSHELL_UID_WIN32CONS 0xE0286F8B #define FSHELL_UID_SHOWDEBUG 0xE0286F8D +#define FSHELL_UID_INPUT 0xE0286B7D +#define FSHELL_UID_BASE64 0xE0286B7E #endif // FSHELL_PROTECTED_UIDS diff -r 8df58d8c99e8 -r b3ffff030d5c commands/activeview/activeview.mmp --- a/commands/activeview/activeview.mmp Tue Oct 26 15:36:30 2010 +0100 +++ b/commands/activeview/activeview.mmp Thu Oct 28 16:54:54 2010 +0100 @@ -25,5 +25,5 @@ library euser.lib library iocli.lib library viewcli.lib -library qr3.lib +library QR3.lib diff -r 8df58d8c99e8 -r b3ffff030d5c commands/base64/base64.cif --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/commands/base64/base64.cif Thu Oct 28 16:54:54 2010 +0100 @@ -0,0 +1,84 @@ +# base64.cif +# +# Copyright (c) 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 +# + +==name base64 + +==short-description + +Encode to or decode from Base64. + +==long-description + +Turns binary data into an ASCII encoded form and vice versa. + + +==argument enum operation + +==enum-value decode + +Read lines from C until F or a blank line is read. Decode the read data and write the binary equivalent to the named file. + +==enum-value encode + +Read binary data from the named file, and write the encoded equivalent as lines to C. + + +==argument filename filename + +The name of the file to write when decoding. The name of the file to read when encoding. + + +==option bool v verbose + +Enable verbose output. + +==option bool o overwrite + +When decoding, overwrite the output file if it already exists. + + +==smoke-test + +exists base64_temp && rm -rf base64_temp +mkdir base64_temp +cd base64_temp + +echo -n 'A' > a.txt +base64 encode a.txt | base64 decode a2.txt +compare a.txt a2.txt || $Error + +echo -n 'AB' > ab.txt +base64 encode ab.txt | base64 decode ab2.txt +compare ab.txt ab2.txt || $Error + +echo -n 'ABC' > abc.txt +base64 encode abc.txt | base64 decode abc2.txt +compare abc.txt abc2.txt || $Error + +echo -n 'ABCD' > abcd.txt +base64 encode abcd.txt | base64 decode abcd2.txt +compare abcd.txt abcd2.txt || $Error + +echo -n 'ABCDE' > abcde.txt +base64 encode abcde.txt | base64 decode abcde2.txt +compare abcde.txt abcde2.txt || $Error + +# Assume fshell.cif is in same location as base64.cif (it's quite a bit bigger which is why we use it in preference) +base64 encode $SCRIPT_PATH\fshell.cif | base64 decode fshell2.cif +compare $SCRIPT_PATH\fshell.cif fshell2.cif || $Error + +cd .. +rm -rf base64_temp + +==copyright + +Copyright (c) 2010 Accenture. All rights reserved. diff -r 8df58d8c99e8 -r b3ffff030d5c commands/base64/base64.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/commands/base64/base64.cpp Thu Oct 28 16:54:54 2010 +0100 @@ -0,0 +1,433 @@ +// base64.cpp +// +// Copyright (c) 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 + +using namespace IoUtils; + +const TInt KBlockSize = 512; +const TInt KLineLength = 76; +const TUint8 KBase64Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +const TUint8 KPadCharacter = '='; + +const TUint8 KInvBase64[] = + { + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x3e, + 0x0, + 0x0, + 0x0, + 0x3f, + 0x34, + 0x35, + 0x36, + 0x37, + 0x38, + 0x39, + 0x3a, + 0x3b, + 0x3c, + 0x3d, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x1, + 0x2, + 0x3, + 0x4, + 0x5, + 0x6, + 0x7, + 0x8, + 0x9, + 0xa, + 0xb, + 0xc, + 0xd, + 0xe, + 0xf, + 0x10, + 0x11, + 0x12, + 0x13, + 0x14, + 0x15, + 0x16, + 0x17, + 0x18, + 0x19, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x1a, + 0x1b, + 0x1c, + 0x1d, + 0x1e, + 0x1f, + 0x20, + 0x21, + 0x22, + 0x23, + 0x24, + 0x25, + 0x26, + 0x27, + 0x28, + 0x29, + 0x2a, + 0x2b, + 0x2c, + 0x2d, + 0x2e, + 0x2f, + 0x30, + 0x31, + 0x32, + 0x33 + }; + +_LIT(KNewLine, "\r\n"); +_LIT(KCr, "\r"); +_LIT(KLf, "\n"); + + +class CCmdBase64 : public CCommandBase + { +public: + static CCommandBase* NewLC(); + ~CCmdBase64(); +private: + CCmdBase64(); + void DecodeL(); + void EncodeL(); +private: // From CCommandBase. + virtual const TDesC& Name() const; + virtual void DoRunL(); + virtual void ArgumentsL(RCommandArgumentList& aArguments); + virtual void OptionsL(RCommandOptionList& aOptions); +private: + enum + { + EDecode, + EEncode + } iOperation; + TFileName2 iFileName; + TBool iVerbose; + TBool iOverwrite; + }; + +EXE_BOILER_PLATE(CCmdBase64) + +CCommandBase* CCmdBase64::NewLC() + { + CCmdBase64* self = new(ELeave) CCmdBase64(); + CleanupStack::PushL(self); + self->BaseConstructL(); + return self; + } + +CCmdBase64::~CCmdBase64() + { + } + +CCmdBase64::CCmdBase64() + { + } + +void CCmdBase64::DecodeL() + { + if (!iOverwrite) + { + LeaveIfFileExists(iFileName); + } + + User::LeaveIfError(Stdin().CaptureAllKeys()); // To iosrv buffering incoming data if we're not keeping up. + Stdin().SetReadModeL(RIoReadHandle::ELine); + + RFile file; + LeaveIfErr(file.Replace(FsL(), iFileName, EFileWrite | EFileStream), _L("Unabled to open '%S' for writing"), &iFileName); + CleanupClosePushL(file); + + TBuf lineBuf; + TBuf8<(KLineLength / 4) * 3> outputBuf; + TBool finished(EFalse); + TBool started(EFalse); + while (!finished) + { + TInt err = Stdin().Read(lineBuf); + if (err == KErrNone) + { + if (iVerbose) + { + Printf(_L("Read %d chars:\r\n'%S'\r\n"), lineBuf.Length(), &lineBuf); + } + if ((lineBuf == KNewLine) || (lineBuf == KCr) || (lineBuf == KLf)) + { + if (started) + { + finished = ETrue; + } + } + else + { + if (lineBuf.Right(2) == KNewLine) + { + lineBuf.SetLength(lineBuf.Length() - 2); + } + if ((lineBuf.Right(1) == KCr) || (lineBuf.Right(1) == KLf)) + { + lineBuf.SetLength(lineBuf.Length() - 1); + } + const TInt lineLength = lineBuf.Length(); + if ((lineLength % 4) > 0) + { + LeaveIfErr(KErrArgument, _L("Invalid base 64 encoded line (not a multiple of 4 characters in length):\r\n%S\r\n"), &lineBuf); + } + + started = ETrue; + outputBuf.Zero(); + + for (TInt i = 0; i < lineLength; i += 4) + { + TInt n = ((TInt)KInvBase64[lineBuf[i]] << 18) + ((TInt)KInvBase64[lineBuf[i + 1]] << 12) + ((TInt)KInvBase64[lineBuf[i + 2]] << 6) + (TInt)KInvBase64[lineBuf[i + 3]]; + + if (lineBuf[i + 2] == KPadCharacter) + { + // Two pad characters + outputBuf.Append((n >> 16) & 0x000000FF); + } + else if (lineBuf[i + 3] == KPadCharacter) + { + // One pad character + outputBuf.Append((n >> 16) & 0x000000FF); + outputBuf.Append((n >> 8) & 0x000000FF); + } + else + { + outputBuf.Append((n >> 16) & 0x000000FF); + outputBuf.Append((n >> 8) & 0x000000FF); + outputBuf.Append(n & 0x000000FF); + } + } + + LeaveIfErr(file.Write(outputBuf), _L("Failed to write to '%S'"), &iFileName); + if (iVerbose) + { + Printf(_L("Wrote %d bytes to '%S'\r\n"), outputBuf.Length(), &iFileName); + } + } + } + else if (err == KErrEof) + { + finished = ETrue; + } + else + { + LeaveIfErr(err, _L("Couldn't read STDIN")); + } + } + + CleanupStack::PopAndDestroy(&file); + } + +void CCmdBase64::EncodeL() + { + LeaveIfFileNotFound(iFileName); + + RFile file; + User::LeaveIfError(file.Open(FsL(), iFileName, EFileRead | EFileStream)); + CleanupClosePushL(file); + + TBuf8 inputBuf; + TBuf outputBuf; + TBool finished(EFalse); + while (!finished) + { + TPtr8 ptr((TUint8*)inputBuf.Ptr() + inputBuf.Length(), 0, inputBuf.MaxLength() - inputBuf.Length()); + LeaveIfErr(file.Read(ptr), _L("Couldn't read from '%S'"), &iFileName); + + if (ptr.Length() > 0) + { + inputBuf.SetLength(inputBuf.Length() + ptr.Length()); + const TInt inputBufLength = inputBuf.Length(); + const TInt excess = inputBufLength % 3; + const TInt bytesToProcess = inputBufLength - excess; + + for (TInt i = 0; i < bytesToProcess; i += 3) + { + // Combine the next three bytes into a 24 bit number. + TInt n = ((TInt)inputBuf[i] << 16) + ((TInt)inputBuf[i + 1] << 8) + (TInt)inputBuf[i + 2]; + + // Split the 24-bit number into four 6-bit numbers. + TUint8 n0 = (TUint8)(n >> 18) & 0x3F; + TUint8 n1 = (TUint8)(n >> 12) & 0x3F; + TUint8 n2 = (TUint8)(n >> 6) & 0x3F; + TUint8 n3 = (TUint8)n & 0x3F; + + // Buffer the base64 encoded equivalent. + outputBuf.Append(KBase64Chars[n0]); + outputBuf.Append(KBase64Chars[n1]); + outputBuf.Append(KBase64Chars[n2]); + outputBuf.Append(KBase64Chars[n3]); + + // Flush output buffer if it's full. + if (outputBuf.Length() == KLineLength) + { + outputBuf.Append(KNewLine); + Write(outputBuf); + outputBuf.Zero(); + } + } + + inputBuf.Delete(0, inputBufLength - excess); + } + else + { + // Process what's left over in inputBuf from the previous successful read, padding as required. + const TInt inputBufLength = inputBuf.Length(); + if (inputBufLength > 0) + { + TInt n = (TInt)inputBuf[0] << 16; + if (inputBufLength > 1) + { + n += (TInt)inputBuf[1] << 8; + if (inputBufLength > 2) + { + n += (TInt)inputBuf[2]; + } + } + + TUint8 n0 = (TUint8)(n >> 18) & 0x3F; + TUint8 n1 = (TUint8)(n >> 12) & 0x3F; + TUint8 n2 = (TUint8)(n >> 6) & 0x3F; + TUint8 n3 = (TUint8)n & 0x3F; + + outputBuf.Append(KBase64Chars[n0]); + outputBuf.Append(KBase64Chars[n1]); + if (inputBufLength > 1) + { + outputBuf.Append(KBase64Chars[n2]); + if (inputBufLength > 2) + { + outputBuf.Append(KBase64Chars[n3]); + } + } + + for (TInt i = inputBufLength; i < 3; ++i) + { + outputBuf.Append('='); + } + } + + if (outputBuf.Length() > 0) + { + outputBuf.Append(KNewLine); + Write(outputBuf); + } + + finished = ETrue; + } + } + + CleanupStack::PopAndDestroy(&file); + } + +const TDesC& CCmdBase64::Name() const + { + _LIT(KName, "base64"); + return KName; + } + +void CCmdBase64::ArgumentsL(RCommandArgumentList& aArguments) + { + _LIT(KArgOperation, "operation"); + aArguments.AppendEnumL((TInt&)iOperation, KArgOperation); + + _LIT(KArgFilename, "filename"); + aArguments.AppendFileNameL(iFileName, KArgFilename); + } + +void CCmdBase64::OptionsL(RCommandOptionList& aOptions) + { + _LIT(KOptVerbose, "verbose"); + aOptions.AppendBoolL(iVerbose, KOptVerbose); + + _LIT(KOptOverwrite, "overwrite"); + aOptions.AppendBoolL(iOverwrite, KOptOverwrite); + } + +void CCmdBase64::DoRunL() + { + switch (iOperation) + { + case EDecode: + DecodeL(); + break; + case EEncode: + EncodeL(); + break; + default: + ASSERT(EFalse); + } + } diff -r 8df58d8c99e8 -r b3ffff030d5c commands/base64/base64.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/commands/base64/base64.mmp Thu Oct 28 16:54:54 2010 +0100 @@ -0,0 +1,27 @@ +// base64.mmp +// +// Copyright (c) 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 + +target fshell_base64.exe +targettype exe +uid FSHELL_UID2_FSHELL_EXE FSHELL_UID_BASE64 +capability FSHELL_CAP_MMP_NORMAL + +userinclude . +#include +sourcepath . +source base64.cpp + +library euser.lib +library efsrv.lib +library iocli.lib diff -r 8df58d8c99e8 -r b3ffff030d5c commands/btservices/btservices.mmp --- a/commands/btservices/btservices.mmp Tue Oct 26 15:36:30 2010 +0100 +++ b/commands/btservices/btservices.mmp Thu Oct 28 16:54:54 2010 +0100 @@ -24,7 +24,7 @@ sourcepath . source btservices.cpp BtServicesEng.cpp -library euser.lib bafl.lib charconv.lib +library euser.lib bafl.lib CHARCONV.lib library iocli.lib LIBRARY esock.lib sdpagent.lib sdpdatabase.lib btextnotifiers.lib btmanclient.lib bluetooth.lib btdevice.lib diff -r 8df58d8c99e8 -r b3ffff030d5c commands/cat/cat.mmp --- a/commands/cat/cat.mmp Tue Oct 26 15:36:30 2010 +0100 +++ b/commands/cat/cat.mmp Thu Oct 28 16:54:54 2010 +0100 @@ -30,7 +30,7 @@ library euser.lib library efsrv.lib library iocli.lib -library charconv.lib +library CHARCONV.lib library ltkutils.lib macro EXE_BUILD diff -r 8df58d8c99e8 -r b3ffff030d5c commands/drvinfo/drvinfo.cif --- a/commands/drvinfo/drvinfo.cif Tue Oct 26 15:36:30 2010 +0100 +++ b/commands/drvinfo/drvinfo.cif Thu Oct 28 16:54:54 2010 +0100 @@ -14,7 +14,7 @@ ==short-description -Display information about the currently installed drives. +Display information about the currently available drives. ==argument string drive_letter optional diff -r 8df58d8c99e8 -r b3ffff030d5c commands/fed/inc/screenmngr.h --- a/commands/fed/inc/screenmngr.h Tue Oct 26 15:36:30 2010 +0100 +++ b/commands/fed/inc/screenmngr.h Thu Oct 28 16:54:54 2010 +0100 @@ -27,7 +27,7 @@ { public: //Returns the TWindow occupied by the command window - const TWindow& GetCommandWindow() {return iCmdWnd;} + const TWindow& GetCommandWindow(); //Sets new coordinates of the screen available to this screen manager void ResizeScreenL(const TWindow& aWindow); //Resizes all Views to make space (if possible) for the new size of the command window. diff -r 8df58d8c99e8 -r b3ffff030d5c commands/fed/src/fed.cpp --- a/commands/fed/src/fed.cpp Tue Oct 26 15:36:30 2010 +0100 +++ b/commands/fed/src/fed.cpp Thu Oct 28 16:54:54 2010 +0100 @@ -232,7 +232,7 @@ OpenDocumentL(); break; case ECmdRefresh: - iScreenMngr.RefreshScreenL(); + RedrawEverythingL(); break; default: return EFalse; @@ -372,5 +372,9 @@ void CFed::RedrawEverythingL() { - ExecuteCommandL(ECmdRefresh); + // This is not very nice but the whole window management thing within fed needs gutting and simplifying + TSize size = iConsole.ScreenSize(); + iScreenMngr.ResizeScreenL(TWindow(0, 0, size.iWidth, size.iHeight)); + iCmdWindow->SetWindow(iScreenMngr.GetCommandWindow()); + iScreenMngr.RefreshScreenL(); } diff -r 8df58d8c99e8 -r b3ffff030d5c commands/fed/src/mainfshell.cpp --- a/commands/fed/src/mainfshell.cpp Tue Oct 26 15:36:30 2010 +0100 +++ b/commands/fed/src/mainfshell.cpp Thu Oct 28 16:54:54 2010 +0100 @@ -112,12 +112,9 @@ iFed->StartL(argsBuf); } -void CCmdFed::StdinChange(TUint aChange) +void CCmdFed::StdinChange(TUint /*aChange*/) { - if (aChange & RIoReadHandle::EGainedForeground) - { - iFed->RedrawEverythingL(); - } + iFed->RedrawEverythingL(); } void AssertionFail(const char* aAssertion, const char* aFile, TInt aLine) diff -r 8df58d8c99e8 -r b3ffff030d5c commands/fed/src/screenmngr.cpp --- a/commands/fed/src/screenmngr.cpp Tue Oct 26 15:36:30 2010 +0100 +++ b/commands/fed/src/screenmngr.cpp Thu Oct 28 16:54:54 2010 +0100 @@ -28,20 +28,14 @@ if(aWindow == iScreenWnd) return; - //We need to leave one char on each side for the border around the console window, so the width/height is actually less by 2 + // We need to leave one char on each side for the border around the console window, so the width/height is actually less by 2 + // (*if* we're running as a pure CConsoleBase app under tshell. Doesn't apply when built as an fshell app, as KConsoleWidthCorrection is zero in that case). iMainWnd.iX = iCmdWnd.iX = aWindow.iX; iMainWnd.iWidth = iCmdWnd.iWidth = aWindow.iWidth + KConsoleWidthCorrection; iMainWnd.iY = aWindow.iY; //Based on proportions of windows on the old screen calculate proportions on the new screen - TInt newcmdh = 1; - if(iScreenWnd.iHeight) - { - newcmdh = ((iCmdWnd.iHeight*KRM) * (aWindow.iHeight*KRM)) / iScreenWnd.iHeight*KRM*KRM; - if(newcmdh >= aWindow.iHeight) - newcmdh = aWindow.iHeight/2; - } - iCmdWnd.iHeight = newcmdh > 0 ? newcmdh : 1; + iCmdWnd.iWidth = aWindow.iWidth; iMainWnd.iHeight = aWindow.iHeight - iCmdWnd.iHeight + KConsoleWidthCorrection; iCmdWnd.iY = aWindow.iY + iMainWnd.iHeight; iScreenWnd = aWindow; @@ -50,6 +44,11 @@ iCurrentView->ResizeL(iMainWnd); } +const TWindow& CScreenManager::GetCommandWindow() + { + return iCmdWnd; + } + const TWindow& CScreenManager::ResizeCommandWindowL(TInt aHeight) { if(aHeight == iCmdWnd.iHeight) diff -r 8df58d8c99e8 -r b3ffff030d5c commands/fed/src/textview.cpp --- a/commands/fed/src/textview.cpp Tue Oct 26 15:36:30 2010 +0100 +++ b/commands/fed/src/textview.cpp Thu Oct 28 16:54:54 2010 +0100 @@ -84,24 +84,26 @@ } void CTextView::ResizeL(const TWindow& aWindow) -{ + { iActive = ETrue; TWindow oldWindow = iWindow; StoreWindow(aWindow); + iLine.Zero(); + iLine.ReAllocL(iConsole.ScreenSize().iWidth); DoResizeL(oldWindow); -} + } void CTextView::RedrawL(const TWindow& aWindow) -{ + { iActive = ETrue; StoreWindow(aWindow); DoRedrawL(); -} + } void CTextView::DeactivateL() -{ + { iActive = EFalse; -} + } //MSharedCacheClient void CTextView::InvalidateBuffer(TRequestStatus& aStatus) diff -r 8df58d8c99e8 -r b3ffff030d5c commands/fzip/fzip.cif --- a/commands/fzip/fzip.cif Tue Oct 26 15:36:30 2010 +0100 +++ b/commands/fzip/fzip.cif Thu Oct 28 16:54:54 2010 +0100 @@ -62,3 +62,29 @@ Copyright (c) 2008-2010 Accenture. All rights reserved. +==smoke-test + +export TESTDATA "This is some test data for fzip" +echo -n "$TESTDATA" > test.txt +rm test.txt.zip $Silent &| echo -n "" + +# Test zip +fzip --file test.txt +exists test.txt.zip || $Error +rm test.txt + +# Test unzip +fzip --unzip test.txt.zip +exists test.txt || $Error +cat -b test.txt | export -s RESULT +var RESULT == "$TESTDATA" || $Error + +# Test that we don't overwrite files unless --overwrite is specified +fzip --file test.txt $Silent &| var ? == "-11" || $Error +fzip --file test.txt --overwrite + +fzip --unzip test.txt.zip $Silent &| var ? == "-11" || $Error +fzip --unzip test.txt.zip --overwrite + +rm test.txt +rm test.txt.zip diff -r 8df58d8c99e8 -r b3ffff030d5c commands/fzip/fzip.cpp --- a/commands/fzip/fzip.cpp Tue Oct 26 15:36:30 2010 +0100 +++ b/commands/fzip/fzip.cpp Thu Oct 28 16:54:54 2010 +0100 @@ -374,8 +374,16 @@ if (aMember.Name()->Right(1) == _L("\\")) return; // It's a directory entry, nothing more to be done // prep. the stream - RZipFileMemberReaderStream* readStream; - aZip.GetInputStreamL(&aMember, readStream); + RZipFileMemberReaderStream* readStream = NULL; + err = aZip.GetInputStreamL(&aMember, readStream); + if (err == CZipFile::KCompressionMethodNotSupported) + { + LeaveIfErr(KErrNotSupported, _L("Zip compression method not supported")); + } + else + { + LeaveIfErr(err, _L("Unable to get input stream")); + } CleanupStack::PushL(readStream); if (iOverwrite) diff -r 8df58d8c99e8 -r b3ffff030d5c commands/glinfo/glinfo.mmp --- a/commands/glinfo/glinfo.mmp Tue Oct 26 15:36:30 2010 +0100 +++ b/commands/glinfo/glinfo.mmp Thu Oct 28 16:54:54 2010 +0100 @@ -27,9 +27,9 @@ library iocli.lib #ifdef FSHELL_EGL_SUPPORT -library libegl.lib +library libEGL.lib #endif #ifdef FSHELL_OPENVG_SUPPORT -library libopenvg.lib +library libOpenVG.lib #endif diff -r 8df58d8c99e8 -r b3ffff030d5c commands/group/bld.inf --- a/commands/group/bld.inf Tue Oct 26 15:36:30 2010 +0100 +++ b/commands/group/bld.inf Thu Oct 28 16:54:54 2010 +0100 @@ -37,6 +37,8 @@ ..\fed\group\fed.cif z:\resource\cif\fshell\fed.cif ..\snake\snake.cif z:\resource\cif\fshell\snake.cif ..\iniedit\iniedit.cif z:\resource\cif\fshell\iniedit.cif +..\input\input.cif z:\resource\cif\fshell\input.cif +..\base64\base64.cif z:\resource\cif\fshell\base64.cif PRJ_MMPFILES ..\cat\cat.mmp @@ -60,6 +62,8 @@ ..\fed\group\fed.mmp ..\snake\snake.mmp ..\iniedit\iniedit.mmp +..\input\input.mmp +..\base64\base64.mmp #ifdef FSHELL_CORE_SUPPORT_SWI PRJ_EXPORTS diff -r 8df58d8c99e8 -r b3ffff030d5c commands/group/fshell_commands.iby --- a/commands/group/fshell_commands.iby Tue Oct 26 15:36:30 2010 +0100 +++ b/commands/group/fshell_commands.iby Thu Oct 28 16:54:54 2010 +0100 @@ -110,6 +110,12 @@ FSHELL_EXECUTABLE_FILE(iniedit.exe) FSHELL_COMMAND_INFO_FILE(fshell,iniedit.cif) +FSHELL_EXECUTABLE_FILE(fshell_input.exe) +FSHELL_COMMAND_INFO_FILE(fshell,input.cif) + +FSHELL_EXECUTABLE_FILE(fshell_base64.exe) +FSHELL_COMMAND_INFO_FILE(fshell,base64.cif) + #ifdef FSHELL_CORE_SUPPORT_PATCHDATA FSHELL_EXECUTABLE_FILE(patchdata.exe) FSHELL_COMMAND_INFO_FILE(fshell,patchdata.cif) diff -r 8df58d8c99e8 -r b3ffff030d5c commands/input/input.cif --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/commands/input/input.cif Thu Oct 28 16:54:54 2010 +0100 @@ -0,0 +1,41 @@ +# input.cif +# +# Copyright (c) 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 +# + +==name input + +==short-description + +Simulate user input events. + +==long-description + +A command that converts console key presses into arbitrary user input events, typically Symbian OS key events. Note, similar functionality is available via Autometric. However, the Autometric command syntax is intended for scripting as so is verbose. By contrast this command accepts single character inputs making it better suited to interactive use. Also, Autometric can only be used if the btrace buffer is free. This command doesn't use btrace and so doesn't have this limitation. + +==option bool s show + +Show the key mappings available for this platform. + +==option uint k scan-code + +Input a specific keypress as a scan-code and then exit. + +==option uint m modifiers + +Must be used in conjunction with C<--scan-code>. Specifies a set of modifiers to be used with the scan-code (as defined in F). + +==argument uint key optional + +Simulate a single event and then exit. If not specified, continually reads keys from the console. 'q' causes the command to exit. + +==copyright + +Copyright (c) 2010 Accenture. All rights reserved. diff -r 8df58d8c99e8 -r b3ffff030d5c commands/input/input.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/commands/input/input.cpp Thu Oct 28 16:54:54 2010 +0100 @@ -0,0 +1,217 @@ +// input.cpp +// +// Copyright (c) 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 + +using namespace IoUtils; + + +class TKeyMapping + { +public: + TUint16 iConsoleKey; + TUint16 iScanCode; + TUint16 iModifiers; +#ifdef __WINS__ + const TText* iLabel; +#else + const wchar_t* iLabel; +#endif + }; + +const TKeyMapping KKeyMappings[] = + { + { '0', '0', 0, L"Zero" }, + { '1', '1', 0, L"One" }, + { '2', '2', 0, L"Two" }, + { '3', '3', 0, L"Three" }, + { '4', '4', 0, L"Four" }, + { '5', '5', 0, L"Five" }, + { '6', '6', 0, L"Six" }, + { '7', '7', 0, L"Seven" }, + { '8', '8', 0, L"Eight" }, + { '9', '9', 0, L"Nine" }, + { '*', '*', 0, L"Star" }, + { '#', '#', 0, L"Hash" }, + { EKeyUpArrow, EStdKeyUpArrow, 0, L"Up" }, + { EKeyDownArrow, EStdKeyDownArrow, 0, L"Down" }, + { EKeyLeftArrow, EStdKeyLeftArrow, 0, L"Left" }, + { EKeyRightArrow, EStdKeyRightArrow, 0, L"Right" }, +#ifdef LTK_PLATFORM_DCM + { EKeyEnter, 167, 0, L"Enter" }, + { 'o', 164, 0, L"Menu" }, + { 'p', 165, 0, L"Camera" }, + { 'l', 228, 0, L"Mail" }, + { ';', 229, 0, L"IMode" }, + { ',', 196, 0, L"Call" }, + { '.', EStdKeyBackspace, 0, L"Clear" }, + { '/', 197, 0, L"End" }, + { 'm', 230, 0, L"Multi" }, +#endif + }; +const TInt KNumKeyMappings = sizeof(KKeyMappings) / sizeof(TKeyMapping); + + +class CCmdInput : public CCommandBase + { +public: + static CCommandBase* NewLC(); + ~CCmdInput(); +private: + CCmdInput(); + void ShowKeyMappings(); + void SimulateKeyL(TInt aConsoleKey); +private: // From CCommandBase. + virtual const TDesC& Name() const; + virtual void DoRunL(); + virtual void ArgumentsL(RCommandArgumentList& aArguments); + virtual void OptionsL(RCommandOptionList& aOptions); +private: + TUint iConsoleKey; + TBool iShow; + TUint iScanCode; + TUint iModifiers; + }; + +EXE_BOILER_PLATE(CCmdInput) + +CCommandBase* CCmdInput::NewLC() + { + CCmdInput* self = new(ELeave) CCmdInput(); + CleanupStack::PushL(self); + self->BaseConstructL(); + return self; + } + +CCmdInput::~CCmdInput() + { + } + +CCmdInput::CCmdInput() + { + } + +void CCmdInput::ShowKeyMappings() + { + IoUtils::CTextBuffer* buf = IoUtils::CTextBuffer::NewLC(0x100); + + buf->AppendL(_L("Input key\tScan Code\tModifiers\tLabel\r\n")); + for (TInt i = 0; i < KNumKeyMappings; ++i) + { + const TKeyMapping& mapping = KKeyMappings[i]; + if (mapping.iConsoleKey == EKeyUpArrow) + { + buf->AppendFormatL(_L("Up (0x%x)\t0x%x\t0x%x\t%s\r\n"), mapping.iConsoleKey, mapping.iScanCode, mapping.iModifiers, mapping.iLabel); + } + else if (mapping.iConsoleKey == EKeyDownArrow) + { + buf->AppendFormatL(_L("Down (0x%x)\t0x%x\t0x%x\t%s\r\n"), mapping.iConsoleKey, mapping.iScanCode, mapping.iModifiers, mapping.iLabel); + } + else if (mapping.iConsoleKey == EKeyLeftArrow) + { + buf->AppendFormatL(_L("Left (0x%x)\t0x%x\t0x%x\t%s\r\n"), mapping.iConsoleKey, mapping.iScanCode, mapping.iModifiers, mapping.iLabel); + } + else if (mapping.iConsoleKey == EKeyRightArrow) + { + buf->AppendFormatL(_L("Right (0x%x)\t0x%x\t0x%x\t%s\r\n"), mapping.iConsoleKey, mapping.iScanCode, mapping.iModifiers, mapping.iLabel); + } + else if (mapping.iConsoleKey == EKeyEnter) + { + buf->AppendFormatL(_L("Enter (0x%x)\t0x%x\t0x%x\t%s\r\n"), mapping.iConsoleKey, mapping.iScanCode, mapping.iModifiers, mapping.iLabel); + } + else + { + buf->AppendFormatL(_L("%c (0x%x)\t0x%x\t0x%x\t%s\r\n"), mapping.iConsoleKey, mapping.iConsoleKey, mapping.iScanCode, mapping.iModifiers, mapping.iLabel); + } + } + + CTextFormatter* formatter = CTextFormatter::NewLC(Stdout()); + formatter->TabulateL(0, 2, buf->Descriptor()); + Write(formatter->Descriptor()); + + CleanupStack::PopAndDestroy(2, buf); + } + +void CCmdInput::SimulateKeyL(TInt aConsoleKey) + { + for (TInt i = 0; i < KNumKeyMappings; ++i) + { + const TKeyMapping& mapping = KKeyMappings[i]; + if (aConsoleKey == mapping.iConsoleKey) + { + LtkUtils::InjectRawKeyEvent(mapping.iScanCode, mapping.iModifiers, 0); + break; + } + } + } + +const TDesC& CCmdInput::Name() const + { + _LIT(KName, "input"); + return KName; + } + +void CCmdInput::ArgumentsL(RCommandArgumentList& aArguments) + { + aArguments.AppendUintL(iConsoleKey, _L("key")); + } + +void CCmdInput::OptionsL(RCommandOptionList& aOptions) + { + aOptions.AppendBoolL(iShow, _L("show")); + aOptions.AppendUintL(iScanCode, _L("scan-code")); + aOptions.AppendUintL(iModifiers, _L("modifiers")); + } + +void CCmdInput::DoRunL() + { + if (iShow) + { + ShowKeyMappings(); + } + else if (iOptions.IsPresent(&iScanCode)) + { + LtkUtils::InjectRawKeyEvent(iScanCode, iModifiers, 0); + } + else + { + if (iArguments.IsPresent(&iConsoleKey)) + { + SimulateKeyL(iConsoleKey); + } + else + { + RIoConsoleReadHandle& stdin = Stdin(); + stdin.SetReadModeL(RIoReadHandle::EFull); + TBuf<1> buf; + TInt err = KErrNone; + while (err == KErrNone) + { + err = stdin.Read(buf); + if (err == KErrNone) + { + if (buf[0] == 'q') + { + break; + } + else + { + SimulateKeyL(buf[0]); + } + } + } + } + } + } diff -r 8df58d8c99e8 -r b3ffff030d5c commands/input/input.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/commands/input/input.mmp Thu Oct 28 16:54:54 2010 +0100 @@ -0,0 +1,27 @@ +// input.mmp +// +// Copyright (c) 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 + +target fshell_input.exe +targettype exe +uid FSHELL_UID2_FSHELL_EXE FSHELL_UID_INPUT +capability FSHELL_CAP_MMP_NORMAL + +userinclude . +#include +sourcepath . +source input.cpp + +library euser.lib +library iocli.lib +library ltkutils.lib diff -r 8df58d8c99e8 -r b3ffff030d5c commands/kerninfo/kerninfo.mmp --- a/commands/kerninfo/kerninfo.mmp Tue Oct 26 15:36:30 2010 +0100 +++ b/commands/kerninfo/kerninfo.mmp Thu Oct 28 16:54:54 2010 +0100 @@ -26,7 +26,7 @@ library euser.lib library iocli.lib -library qr3.lib +library QR3.lib library ltkutils.lib #ifdef FSHELL_SPCRE_SUPPORT diff -r 8df58d8c99e8 -r b3ffff030d5c commands/leak/leak.mmp --- a/commands/leak/leak.mmp Tue Oct 26 15:36:30 2010 +0100 +++ b/commands/leak/leak.mmp Thu Oct 28 16:54:54 2010 +0100 @@ -31,7 +31,7 @@ #endif #ifdef FSHELL_QR3_SUPPORT_LOGGINGALLOCATOR -library loggingallocator.lib +library LoggingAllocator.lib #endif macro EXE_BUILD diff -r 8df58d8c99e8 -r b3ffff030d5c commands/pubsub/pubsub.mmp --- a/commands/pubsub/pubsub.mmp Tue Oct 26 15:36:30 2010 +0100 +++ b/commands/pubsub/pubsub.mmp Thu Oct 28 16:54:54 2010 +0100 @@ -25,7 +25,7 @@ library euser.lib library iocli.lib -library qr3.lib +library QR3.lib library ltkutils.lib library btrace_parser.lib FSHELL_TRACE_CONTROL_LIBRARY diff -r 8df58d8c99e8 -r b3ffff030d5c commands/snake/snake.cpp --- a/commands/snake/snake.cpp Tue Oct 26 15:36:30 2010 +0100 +++ b/commands/snake/snake.cpp Thu Oct 28 16:54:54 2010 +0100 @@ -439,8 +439,10 @@ void CCmdSnake::PlaceBait() { TBool ok; + TInt attempts = 0; do { + attempts++; ok = ETrue; iBait.iX = Math::Rand(iRandomSeed) % iBoardSize.iWidth; iBait.iY = Math::Rand(iRandomSeed) % iBoardSize.iHeight; @@ -453,6 +455,7 @@ if (iSnake[i] == iBait) ok = EFalse; } } + if (attempts >= iBoardSize.iWidth * iBoardSize.iHeight) return; // Snake has filled the entire board! Time to bail (the snake will run into itself right after we return here) } while (!ok); iCons.SetCursorPosAbs(iBait); iCons.Write(iUnicode ? KUnicodeBait : KBait); diff -r 8df58d8c99e8 -r b3ffff030d5c commands/tail/tail.mmp --- a/commands/tail/tail.mmp Tue Oct 26 15:36:30 2010 +0100 +++ b/commands/tail/tail.mmp Thu Oct 28 16:54:54 2010 +0100 @@ -30,6 +30,6 @@ library euser.lib library efsrv.lib library iocli.lib -library charconv.lib +library CHARCONV.lib macro EXE_BUILD diff -r 8df58d8c99e8 -r b3ffff030d5c commands/uidinfo/uidinfo.mmp --- a/commands/uidinfo/uidinfo.mmp Tue Oct 26 15:36:30 2010 +0100 +++ b/commands/uidinfo/uidinfo.mmp Thu Oct 28 16:54:54 2010 +0100 @@ -25,4 +25,4 @@ library euser.lib library iocli.lib -library ltkutils.lib qr3.lib \ No newline at end of file +library ltkutils.lib QR3.lib \ No newline at end of file diff -r 8df58d8c99e8 -r b3ffff030d5c core/builtins/source.cif --- a/core/builtins/source.cif Tue Oct 26 15:36:30 2010 +0100 +++ b/core/builtins/source.cif Thu Oct 28 16:54:54 2010 +0100 @@ -40,9 +40,9 @@ L -==argument filename script_file_name +==argument filename script_file_name optional -The name of the script file to be run. +The name of the script file to be run. If not specified (or specified with zero length, i.e. ''), the script will be read from C. ==argument string script_args optional last diff -r 8df58d8c99e8 -r b3ffff030d5c core/src/command_constructors.cpp --- a/core/src/command_constructors.cpp Tue Oct 26 15:36:30 2010 +0100 +++ b/core/src/command_constructors.cpp Thu Oct 28 16:54:54 2010 +0100 @@ -66,32 +66,32 @@ // CThreadCommandConstructor. // -CThreadCommandConstructor* CThreadCommandConstructor::NewLC(TCommandConstructor aConstructor, TUint aFlags) +CThreadCommandConstructor* CThreadCommandConstructor::NewLC(TCommandConstructor aConstructor, TUint aFlags, MTaskRunner* aTaskRunner) { CCommandBase* command = (*aConstructor)(); - CThreadCommandConstructor* self = CThreadCommandConstructor::NewLC(command->Name(), aConstructor, aFlags); + CThreadCommandConstructor* self = CThreadCommandConstructor::NewLC(command->Name(), aConstructor, aFlags, aTaskRunner); CleanupStack::Pop(self); CleanupStack::PopAndDestroy(command); CleanupStack::PushL(self); return self; } -CThreadCommandConstructor* CThreadCommandConstructor::NewLC(const TDesC& aCommandName, TCommandConstructor aConstructor, TUint aFlags) +CThreadCommandConstructor* CThreadCommandConstructor::NewLC(const TDesC& aCommandName, TCommandConstructor aConstructor, TUint aFlags, MTaskRunner* aTaskRunner) { - CThreadCommandConstructor* self = new(ELeave) CThreadCommandConstructor(aFlags, aConstructor); + CThreadCommandConstructor* self = new(ELeave) CThreadCommandConstructor(aFlags, aConstructor, aTaskRunner); CleanupStack::PushL(self); self->BaseConstructL(aCommandName); return self; } -CThreadCommandConstructor::CThreadCommandConstructor(TUint aFlags, TCommandConstructor aConstructor) - : CCommandConstructorBase(ETypeThread), iFlags(aFlags), iConstructor(aConstructor) +CThreadCommandConstructor::CThreadCommandConstructor(TUint aFlags, TCommandConstructor aConstructor, MTaskRunner* aTaskRunner) + : CCommandConstructorBase(ETypeThread), iFlags(aFlags), iConstructor(aConstructor), iTaskRunner(aTaskRunner) { } MCommand* CThreadCommandConstructor::ConstructCommandL() { - return CThreadCommand::NewL(CommandName(), iConstructor, iFlags); + return CThreadCommand::NewL(CommandName(), iConstructor, iFlags, iTaskRunner); } void CThreadCommandConstructor::AppendDescriptionL(RLtkBuf16& aBuf) const diff -r 8df58d8c99e8 -r b3ffff030d5c core/src/command_constructors.h --- a/core/src/command_constructors.h Tue Oct 26 15:36:30 2010 +0100 +++ b/core/src/command_constructors.h Thu Oct 28 16:54:54 2010 +0100 @@ -18,6 +18,8 @@ #include class MCommand; +class MTaskRunner; + namespace LtkUtils { class RLtkBuf16; } using LtkUtils::RLtkBuf16; @@ -61,16 +63,17 @@ class CThreadCommandConstructor : public CCommandConstructorBase { public: - static CThreadCommandConstructor* NewLC(TCommandConstructor aConstructor, TUint aFlags); - static CThreadCommandConstructor* NewLC(const TDesC& aCommandName, TCommandConstructor aConstructor, TUint aFlags); + static CThreadCommandConstructor* NewLC(TCommandConstructor aConstructor, TUint aFlags, MTaskRunner* aTaskRunner); + static CThreadCommandConstructor* NewLC(const TDesC& aCommandName, TCommandConstructor aConstructor, TUint aFlags, MTaskRunner* aTaskRunner); private: - CThreadCommandConstructor(TUint aFlags, TCommandConstructor aConstructor); + CThreadCommandConstructor(TUint aFlags, TCommandConstructor aConstructor, MTaskRunner* aTaskRunner); private: // From CCommandConstructorBase. virtual MCommand* ConstructCommandL(); virtual void AppendDescriptionL(RLtkBuf16& aBuf) const; private: TUint iFlags; TCommandConstructor iConstructor; + MTaskRunner* iTaskRunner; }; class CExeCommandConstructor : public CCommandConstructorBase diff -r 8df58d8c99e8 -r b3ffff030d5c core/src/command_factory.cpp --- a/core/src/command_factory.cpp Tue Oct 26 15:36:30 2010 +0100 +++ b/core/src/command_factory.cpp Thu Oct 28 16:54:54 2010 +0100 @@ -25,6 +25,7 @@ #include "ymodem.h" #include "version.h" #include "ciftest.h" +#include "worker_thread.h" // // Constants. @@ -84,6 +85,7 @@ Cancel(); iCommands.ResetAndDestroy(); iLock.Close(); + delete iThreadPool; } TInt CompareCommandNames(const CCommandConstructorBase& aCommand1, const CCommandConstructorBase& aCommand2) @@ -250,6 +252,7 @@ { User::LeaveIfError(iLock.CreateLocal()); User::LeaveIfError(iFs.DriveList(iDriveList)); + iThreadPool = CThreadPool::NewL(); AddThreadCommandL(CCmdExit::NewLC); // Note, this command should never execute as 'exit' has handled explicitly by CParser. It exists so that 'exit' appears in fshell's help list and also to support 'exit --help'. AddThreadCommandL(CCmdHelp::NewLC, CThreadCommand::ESharedHeap); @@ -429,14 +432,14 @@ void CCommandFactory::AddThreadCommandL(TCommandConstructor aConstructor, TUint aFlags) { - CCommandConstructorBase* constructor = CThreadCommandConstructor::NewLC(aConstructor, aFlags); + CCommandConstructorBase* constructor = CThreadCommandConstructor::NewLC(aConstructor, aFlags, iThreadPool); AddCommandL(constructor); CleanupStack::Pop(constructor); } void CCommandFactory::AddThreadCommandL(const TDesC& aCommandName, TCommandConstructor aConstructor, TUint aAttributes, TUint aFlags) { - CCommandConstructorBase* constructor = CThreadCommandConstructor::NewLC(aCommandName, aConstructor, aFlags); + CCommandConstructorBase* constructor = CThreadCommandConstructor::NewLC(aCommandName, aConstructor, aFlags, iThreadPool); constructor->SetAttributes(aAttributes); AddCommandL(constructor); CleanupStack::Pop(constructor); @@ -444,7 +447,7 @@ void CCommandFactory::AddAliasCommandL(const TDesC& aAliasName, TCommandConstructor aConstructor, const TDesC* aAdditionalArguments, const TDesC* aReplacementArguments, TUint aAttributes, TUint aFlags) { - CCommandConstructorBase* aliasedCommand = CThreadCommandConstructor::NewLC(aConstructor, aFlags); + CCommandConstructorBase* aliasedCommand = CThreadCommandConstructor::NewLC(aConstructor, aFlags, iThreadPool); CCommandConstructorBase* constructor = CAliasCommandConstructor::NewLC(aAliasName, aliasedCommand, aAdditionalArguments, aReplacementArguments); CleanupStack::Pop(2, aliasedCommand); // Now owned by "constructor". CleanupStack::PushL(constructor); diff -r 8df58d8c99e8 -r b3ffff030d5c core/src/command_factory.h --- a/core/src/command_factory.h Tue Oct 26 15:36:30 2010 +0100 +++ b/core/src/command_factory.h Thu Oct 28 16:54:54 2010 +0100 @@ -15,7 +15,9 @@ #define __COMMAND_FACTORY_H__ #include -#include "command_constructors.h" +#include "command_wrappers.h" +class CCommandConstructorBase; +class CThreadPool; #include "error.h" class RFs; @@ -51,6 +53,7 @@ virtual void RunL(); virtual void DoCancel(); virtual TInt RunError(TInt aError); + private: RFs& iFs; mutable RMutex iLock; @@ -60,6 +63,7 @@ TBool iFailedToScanFileSystem; TThreadId iFactoryThreadId; // The one the CCommandFactory active object lives in RAllocator* iFactoryAllocator; + CThreadPool* iThreadPool; }; diff -r 8df58d8c99e8 -r b3ffff030d5c core/src/command_wrappers.cpp --- a/core/src/command_wrappers.cpp Tue Oct 26 15:36:30 2010 +0100 +++ b/core/src/command_wrappers.cpp Thu Oct 28 16:54:54 2010 +0100 @@ -11,20 +11,14 @@ // #include "command_wrappers.h" - - -// -// Constants. -// - -const TInt KMaxHeapSize = 1024*1024; // 1 MB - +#include "worker_thread.h" // // CCommandWrapperBase. // CCommandWrapperBase::CCommandWrapperBase() + : CActive(CActive::EPriorityStandard) { } @@ -96,14 +90,23 @@ delete this; } +void CCommandWrapperBase::RunL() + { + // Optionally for use by subclasses + } + +void CCommandWrapperBase::DoCancel() + { + // Optionally for use by subclasses + } // // CThreadCommand. // -CThreadCommand* CThreadCommand::NewL(const TDesC& aName, TCommandConstructor aCommandConstructor, TUint aFlags) +CThreadCommand* CThreadCommand::NewL(const TDesC& aName, TCommandConstructor aCommandConstructor, TUint aFlags, MTaskRunner* aTaskRunner) { - CThreadCommand* self = new(ELeave) CThreadCommand(aCommandConstructor, aFlags); + CThreadCommand* self = new(ELeave) CThreadCommand(aCommandConstructor, aFlags, aTaskRunner); CleanupStack::PushL(self); self->ConstructL(aName); CleanupStack::Pop(self); @@ -112,14 +115,15 @@ CThreadCommand::~CThreadCommand() { - delete iWatcher; - delete iArgs; + Cancel(); + delete iCommandLine; iThread.Close(); } -CThreadCommand::CThreadCommand(TCommandConstructor aCommandConstructor, TUint aFlags) - : iFlags(aFlags), iCommandConstructor(aCommandConstructor) +CThreadCommand::CThreadCommand(TCommandConstructor aCommandConstructor, TUint aFlags, MTaskRunner* aTaskRunner) + : iFlags(aFlags), iCommandConstructor(aCommandConstructor), iTaskRunner(aTaskRunner) { + CActiveScheduler::Add(this); iThread.SetHandle(0); // By default RThread refers to the current thread. This results in fshell's thread exiting if this object gets killed before it has managed to open a real thread handle. if (iFlags & EUpdateEnvironment) iFlags |= ESharedHeap; // Update environment implies a shared heap, ever since we did away with the explict SwitchAllocator } @@ -127,66 +131,31 @@ void CThreadCommand::ConstructL(const TDesC& aName) { BaseConstructL(aName); - iWatcher = CThreadWatcher::NewL(); } -void CommandThreadStartL(CThreadCommand::TArgs& aArgs) +void CThreadCommand::DoCommandThreadStartL(TAny* aSelf) { - if (aArgs.iFlags & CThreadCommand::ESharedHeap) - { - // If we're sharing the main fshell heap, we have to play by the rules and not crash - User::SetCritical(User::EProcessCritical); - } - - CActiveScheduler* scheduler = new(ELeave) CActiveScheduler; - CleanupStack::PushL(scheduler); - CActiveScheduler::Install(scheduler); - - HBufC* commandLine = aArgs.iCommandLine.AllocLC(); + CThreadCommand* self = static_cast(aSelf); IoUtils::CEnvironment* env; - if (aArgs.iFlags & CThreadCommand::EUpdateEnvironment) + if (self->iFlags & CThreadCommand::EUpdateEnvironment) { - env = aArgs.iEnv.CreateSharedEnvironmentL(); + env = self->iSuppliedEnv->CreateSharedEnvironmentL(); } else { // A straight-forward copy - env = IoUtils::CEnvironment::NewL(aArgs.iEnv); + env = IoUtils::CEnvironment::NewL(*self->iSuppliedEnv); } CleanupStack::PushL(env); - CCommandBase* command = (*aArgs.iCommandConstructor)(); - RThread parentThread; - User::LeaveIfError(parentThread.Open(aArgs.iParentThreadId)); - parentThread.RequestComplete(aArgs.iParentStatus, KErrNone); - parentThread.Close(); - - command->RunCommandL(commandLine, env); - CleanupStack::PopAndDestroy(4, scheduler); // env, command, commandline, scheduler + CCommandBase* command = (*self->iCommandConstructor)(); + //RDebug::Print(_L("5. DoCommandThreadStartL rendezvousing for %S %S"), &self->CmndName(), self->iCommandLine); + RThread::Rendezvous(KErrNone); + command->RunCommandL(self->iCommandLine, env); + CleanupStack::PopAndDestroy(2, env); // command, env } -TInt CommandThreadStart(TAny* aPtr) - { - CThreadCommand::TArgs args = *(CThreadCommand::TArgs*)aPtr; - TBool sharedHeap = (args.iFlags & CThreadCommand::ESharedHeap); - if (!sharedHeap) - { - __UHEAP_MARK; - } - TInt err = KErrNoMemory; - CTrapCleanup* cleanup = CTrapCleanup::New(); - if (cleanup) - { - TRAP(err, CommandThreadStartL(args)); - delete cleanup; - } - if (!sharedHeap) - { - __UHEAP_MARKEND; - } - return err; - } void SetHandleOwnersL(TThreadId aThreadId, RIoReadHandle& aStdin, RIoWriteHandle& aStdout, RIoWriteHandle& aStderr) { @@ -199,64 +168,36 @@ { ASSERT(iObserver == NULL); - TRequestStatus status(KRequestPending); - iArgs = new TArgs(iFlags, aEnv, iCommandConstructor, aCommandLine, status); - if (iArgs == NULL) + MThreadedTask* thread = NULL; + TRAPD(err, thread = iTaskRunner->NewTaskInSeparateThreadL(CmndName(), iFlags & ESharedHeap, &DoCommandThreadStartL, this)); + if (err) return err; + + TRAP(err, SetHandleOwnersL(thread->GetThreadId(), CmndStdin(), CmndStdout(), CmndStderr())); + + if (!err) { - return KErrNoMemory; + iCommandLine = aCommandLine.Alloc(); + if (!iCommandLine) err = KErrNoMemory; } - TInt i = 0; - TName threadName; - TInt err = KErrNone; - do + if (!err) { - const TDesC& name = CmndName(); - threadName.Format(_L("%S_%02d"), &name, i++); - if (iFlags & ESharedHeap) - { - err = iThread.Create(threadName, CommandThreadStart, KDefaultStackSize, NULL, iArgs); - } - else - { - err = iThread.Create(threadName, CommandThreadStart, KDefaultStackSize, KMinHeapSize, KMaxHeapSize, iArgs); - } - } - while (err == KErrAlreadyExists); - - if (err) - { - return err; + err = iThread.Open(thread->GetThreadId()); } - err = iWatcher->Logon(*this, iThread, aObserver); - if (err) + if (!err) { - iThread.Kill(0); - iThread.Close(); - return err; + iSuppliedEnv = &aEnv; + iObserver = &aObserver; + thread->ExecuteTask(iStatus); + SetActive(); + } + else + { + thread->AbortTask(); } - TThreadId threadId = iThread.Id(); - TRAP(err, SetHandleOwnersL(threadId, CmndStdin(), CmndStdout(), CmndStderr())); - if (err) - { - iThread.Kill(0); - iThread.Close(); - return err; - } - - iThread.Resume(); - User::WaitForRequest(status, iWatcher->iStatus); - if (status == KRequestPending) - { - iThread.Close(); - return iWatcher->iStatus.Int(); - } - - iWatcher->SetActive(); - iObserver = &aObserver; - return KErrNone; + return err; } void CThreadCommand::CmndForeground() @@ -300,71 +241,14 @@ return iThread.ExitCategory(); } - -// -// CThreadCommand::TArgs. -// - -CThreadCommand::TArgs::TArgs(TUint aFlags, IoUtils::CEnvironment& aEnv, TCommandConstructor aCommandConstructor, const TDesC& aCommandLine, TRequestStatus& aParentStatus) - : iFlags(aFlags), iEnv(aEnv), iCommandConstructor(aCommandConstructor), iCommandLine(aCommandLine), iParentStatus(&aParentStatus), iParentThreadId(RThread().Id()) +void CThreadCommand::RunL() { - } - - -// -// CThreadCommand::CThreadWatcher. -// - -CThreadCommand::CThreadWatcher* CThreadCommand::CThreadWatcher::NewL() - { - return new(ELeave) CThreadWatcher(); - } - -CThreadCommand::CThreadWatcher::~CThreadWatcher() - { - Cancel(); - } - -CThreadCommand::CThreadWatcher::CThreadWatcher() - : CActive(CActive::EPriorityStandard) - { - CActiveScheduler::Add(this); + iObserver->HandleCommandComplete(*this, iStatus.Int()); } -TInt CThreadCommand::CThreadWatcher::Logon(CThreadCommand& aCommand, RThread& aThread, MCommandObserver& aObserver) +void CThreadCommand::DoCancel() { - TInt ret = KErrNone; - aThread.Logon(iStatus); - if (iStatus != KRequestPending) - { - User::WaitForRequest(iStatus); - ret = iStatus.Int(); - } - else - { - iCommand = &aCommand; - iThread = &aThread; - iObserver = &aObserver; - } - return ret; - } - -void CThreadCommand::CThreadWatcher::SetActive() - { - CActive::SetActive(); - } - -void CThreadCommand::CThreadWatcher::RunL() - { - iObserver->HandleCommandComplete(*iCommand, iStatus.Int()); - } - -void CThreadCommand::CThreadWatcher::DoCancel() - { - if (iThread) - { - iThread->LogonCancel(iStatus); - } + CmndKill(); // This is a bit drastic, but effective... } diff -r 8df58d8c99e8 -r b3ffff030d5c core/src/command_wrappers.h --- a/core/src/command_wrappers.h Tue Oct 26 15:36:30 2010 +0100 +++ b/core/src/command_wrappers.h Thu Oct 28 16:54:54 2010 +0100 @@ -55,8 +55,7 @@ virtual void HandleCommandComplete(MCommand& aCommand, TInt aError) = 0; }; - -class CCommandWrapperBase : public CBase, public MCommand +class CCommandWrapperBase : public CActive, public MCommand { protected: CCommandWrapperBase(); @@ -74,6 +73,10 @@ virtual void CmndDisown(); private: // From MCommand. virtual void CmndRelease(); +protected: // From CActive + void RunL(); + void DoCancel(); + private: HBufC* iName; ///< This is used by concrete classes as they see fit. RIoReadHandle iStdin; @@ -91,11 +94,14 @@ ESharedHeap = 0x00000002, // Any command that accesses gShell must have this set }; public: - static CThreadCommand* NewL(const TDesC& aName, TCommandConstructor aCommandConstructor, TUint aFlags); + static CThreadCommand* NewL(const TDesC& aName, TCommandConstructor aCommandConstructor, TUint aFlags, MTaskRunner* aTaskRunner); ~CThreadCommand(); private: - CThreadCommand(TCommandConstructor aCommandConstructor, TUint aFlags); + CThreadCommand(TCommandConstructor aCommandConstructor, TUint aFlags, MTaskRunner* aTaskRunner); void ConstructL(const TDesC& aName); + void RunL(); + void DoCancel(); + static void DoCommandThreadStartL(TAny* aSelf); private: // From MCommand. virtual TInt CmndRun(const TDesC& aCommandLine, IoUtils::CEnvironment& aEnv, MCommandObserver& aObserver, RIoSession& aIoSession); virtual void CmndForeground(); @@ -105,43 +111,14 @@ virtual TInt CmndResume(); virtual TExitType CmndExitType() const; virtual TExitCategoryName CmndExitCategory() const; -public: - class TArgs - { - public: - TArgs(TUint aFlags, CEnvironment& aEnv, TCommandConstructor aCommandConstructor, const TDesC& aCommandLine, TRequestStatus& aParentStatus); - public: - TUint iFlags; - CEnvironment& iEnv; - TCommandConstructor iCommandConstructor; - const TPtrC iCommandLine; - TRequestStatus* iParentStatus; - TThreadId iParentThreadId; - }; - class CThreadWatcher : public CActive - { - public: - static CThreadWatcher* NewL(); - ~CThreadWatcher(); - TInt Logon(CThreadCommand& aCommand, RThread& aThread, MCommandObserver& aObserver); - void SetActive(); - private: - CThreadWatcher(); - private: // From CActive. - virtual void RunL(); - virtual void DoCancel(); - private: - CThreadCommand* iCommand; - RThread* iThread; - MCommandObserver* iObserver; - }; private: TUint iFlags; TCommandConstructor iCommandConstructor; MCommandObserver* iObserver; - TArgs* iArgs; RThread iThread; - CThreadWatcher* iWatcher; + MTaskRunner* iTaskRunner; + CEnvironment* iSuppliedEnv; + HBufC* iCommandLine; }; diff -r 8df58d8c99e8 -r b3ffff030d5c core/src/commands.cpp --- a/core/src/commands.cpp Tue Oct 26 15:36:30 2010 +0100 +++ b/core/src/commands.cpp Thu Oct 28 16:54:54 2010 +0100 @@ -3492,8 +3492,11 @@ CCmdSource::~CCmdSource() { delete iArgs; - delete iScriptData; delete iParser; + if (iCloseScriptHandle) + { + iScriptHandle.Close(); + } } CCmdSource::CCmdSource() : CCommandBase(EManualComplete) @@ -3502,11 +3505,28 @@ void CCmdSource::DoRunL() { - TIoHandleSet ioHandles(IoSession(), Stdin(), Stdout(), Stderr()); - TBool helpPrinted; - iScriptData = CShell::ReadScriptL(iFileName, iArgs, Env(), FsL(), ioHandles, helpPrinted); - - if (helpPrinted) + TBool abort(EFalse); + + if (iFileName.Length() > 0) + { + TIoHandleSet ioHandles(IoSession(), Stdin(), Stdout(), Stderr()); + iScriptHandle = CShell::OpenScriptL(iFileName, iArgs, Env(), FsL(), ioHandles, abort); + iCloseScriptHandle = ETrue; + } + else + { + iScriptHandle = Stdin(); + Env().SetLocalL(KScriptName); + Env().SetLocalL(KScriptPath); + Env().SetLocalL(KScriptLine); + Env().SetLocalL(_L("0")); + _LIT(KStdin, "STDIN"); + Env().SetL(KScriptName, KStdin); + Env().SetL(KScriptPath, KNullDesC); + Env().SetL(_L("0"), KStdin); + } + + if (abort) { Complete(); } @@ -3517,7 +3537,7 @@ { mode |= CParser::EKeepGoing; } - iParser = CParser::NewL(mode, *iScriptData, IoSession(), Stdin(), Stdout(), Stderr(), Env(), gShell->CommandFactory(), this); + iParser = CParser::NewL(mode, iScriptHandle, IoSession(), Stdin(), Stdout(), Stderr(), Env(), gShell->CommandFactory(), this); iParser->Start(); } } @@ -4040,9 +4060,9 @@ CCmdDebug::~CCmdDebug() { - delete iScriptData; delete iParser; delete iArgs; + iScriptHandle.Close(); } CCmdDebug::CCmdDebug() : CCommandBase(EManualComplete) @@ -4053,7 +4073,7 @@ { TIoHandleSet ioHandles(IoSession(), Stdin(), Stdout(), Stderr()); TBool helpPrinted; - iScriptData = CShell::ReadScriptL(iFileName, iArgs, Env(), FsL(), ioHandles, helpPrinted); + iScriptHandle = CShell::OpenScriptL(iFileName, iArgs, Env(), FsL(), ioHandles, helpPrinted); if (helpPrinted) { Complete(); @@ -4065,7 +4085,7 @@ { mode |= CParser::EKeepGoing; } - iParser = CParser::NewL(mode, *iScriptData, IoSession(), Stdin(), Stdout(), Stderr(), Env(), gShell->CommandFactory(), this); + iParser = CParser::NewL(mode, iScriptHandle, IoSession(), Stdin(), Stdout(), Stderr(), Env(), gShell->CommandFactory(), this); iParser->Start(); } } @@ -5993,7 +6013,7 @@ if (iErrorText) { - LeaveIfErr(iErrorVal, _L("%S"), iErrorText); + LeaveIfErr(iErrorVal, *iErrorText); } else { @@ -6080,8 +6100,7 @@ { if (!aFirstTime) Env().RemoveAll(); // Remove all only does locals - delete iScriptData; - iScriptData = NULL; + iScriptHandle.Close(); delete iParser; iParser = NULL; @@ -6105,7 +6124,7 @@ TIoHandleSet ioHandles(IoSession(), Stdin(), Stdout(), Stderr()); TBool helpPrinted; - iScriptData = CShell::ReadScriptL(iFileName, iArgs, Env(), FsL(), ioHandles, helpPrinted, &extraArgs); + iScriptHandle = CShell::OpenScriptL(iFileName, iArgs, Env(), FsL(), ioHandles, helpPrinted, &extraArgs); CleanupStack::PopAndDestroy(&extraArgs); if (helpPrinted) { @@ -6118,7 +6137,7 @@ { mode |= CParser::EKeepGoing; } - iParser = CParser::NewL(mode, *iScriptData, IoSession(), Stdin(), Stdout(), Stderr(), Env(), gShell->CommandFactory(), this); + iParser = CParser::NewL(mode, iScriptHandle, IoSession(), Stdin(), Stdout(), Stderr(), Env(), gShell->CommandFactory(), this); iParser->Start(); } } @@ -6139,6 +6158,11 @@ } LeaveIfErr(iDir.Open(FsL(), iDirName, KEntryAttNormal | KEntryAttDir), _L("Couldn't open directory '%S'"), &iDirName); + if (iFileName.Length() == 0) + { + LeaveIfErr(KErrArgument, _L("Invalid script file name")); + } + DoNextL(ETrue); } diff -r 8df58d8c99e8 -r b3ffff030d5c core/src/commands.h --- a/core/src/commands.h Tue Oct 26 15:36:30 2010 +0100 +++ b/core/src/commands.h Thu Oct 28 16:54:54 2010 +0100 @@ -765,7 +765,8 @@ TFileName2 iFileName; HBufC* iArgs; TBool iKeepGoing; - HBufC* iScriptData; + TBool iCloseScriptHandle; + RIoReadHandle iScriptHandle; CParser* iParser; }; @@ -886,7 +887,7 @@ TFileName2 iFileName; HBufC* iArgs; TBool iKeepGoing; - HBufC* iScriptData; + RIoReadHandle iScriptHandle; CParser* iParser; }; diff -r 8df58d8c99e8 -r b3ffff030d5c core/src/error.h --- a/core/src/error.h Tue Oct 26 15:36:30 2010 +0100 +++ b/core/src/error.h Thu Oct 28 16:54:54 2010 +0100 @@ -32,9 +32,8 @@ EFailedToCreatePipeLine, EFailedToConstructCommand, EFailedToRunCommand, - EFailedToSetChildErrorVar, + EPipelineCompletionError, ECommandError, - EFailedToSetScriptLineVar, }; public: TError(RIoWriteHandle& aStderr, IoUtils::CEnvironment& aEnv); diff -r 8df58d8c99e8 -r b3ffff030d5c core/src/fshell.cpp --- a/core/src/fshell.cpp Tue Oct 26 15:36:30 2010 +0100 +++ b/core/src/fshell.cpp Thu Oct 28 16:54:54 2010 +0100 @@ -117,8 +117,7 @@ break; } case EFailedToCreatePipeLine: - case EFailedToSetChildErrorVar: - case EFailedToSetScriptLineVar: + case EPipelineCompletionError: case EUnknown: default: { @@ -200,8 +199,7 @@ CASE_RETURN_LIT(EFailedToCreatePipeLine); CASE_RETURN_LIT(EFailedToConstructCommand); CASE_RETURN_LIT(EFailedToRunCommand); - CASE_RETURN_LIT(EFailedToSetChildErrorVar); - CASE_RETURN_LIT(EFailedToSetScriptLineVar); + CASE_RETURN_LIT(EPipelineCompletionError); CASE_RETURN_LIT(ECommandError); DEFAULT_RETURN_LIT("*** REASON UNKNOWN ***"); } @@ -296,6 +294,7 @@ CShell::~CShell() { + iScriptHandle.Close(); iJobsLock.Close(); iJobs.ResetAndDestroy(); delete iScriptArgs; @@ -303,7 +302,6 @@ delete iLineCompleter; delete iConsole; delete iCommandFactory; - delete iScriptData; delete iOneLiner; delete iParser; } @@ -515,7 +513,7 @@ { TIoHandleSet ioHandles(IoSession(), Stdin(), Stdout(), Stderr()); TBool helpPrinted; - iScriptData = ReadScriptL(iScriptName, iScriptArgs, Env(), FsL(), ioHandles, helpPrinted); + iScriptHandle = OpenScriptL(iScriptName, iScriptArgs, Env(), FsL(), ioHandles, helpPrinted); if (helpPrinted) { Complete(); @@ -527,7 +525,7 @@ { mode |= CParser::EKeepGoing; } - iParser = CParser::NewL(mode, *iScriptData, IoSession(), Stdin(), Stdout(), Stderr(), Env(), *iCommandFactory, this); + iParser = CParser::NewL(mode, iScriptHandle, IoSession(), Stdin(), Stdout(), Stderr(), Env(), *iCommandFactory, this); RProcess::Rendezvous(KErrNone); iParser->Start(); } @@ -641,8 +639,12 @@ return KErrNotFound; } -HBufC* CShell::ReadScriptL(const TDesC& aScriptName, const TDesC* aArguments, IoUtils::CEnvironment& aEnv, RFs& aFs, TIoHandleSet& aIoHandles, TBool& aHelpPrinted, RPointerArray* aAdditionalPrefixArguments) +RIoReadHandle CShell::OpenScriptL(const TDesC& aScriptName, const TDesC* aArguments, IoUtils::CEnvironment& aEnv, RFs& aFs, TIoHandleSet& aIoHandles, TBool& aHelpPrinted, RPointerArray* aAdditionalPrefixArguments) { + RIoReadHandle readHandle; + readHandle.CreateL(aIoHandles.IoSession()); + CleanupClosePushL(readHandle); + TFileName2 scriptName(aScriptName); // Check the scripts dirs in case it wasn't given as an absolute path (although iocli will have made it absolute relative to the pwd) @@ -670,12 +672,12 @@ } } - RFile scriptFile; + RIoFile scriptFile; TInt err; TInt retries = 5; do { - err = scriptFile.Open(aFs, scriptName, EFileRead | EFileShareReadersOnly); + err = scriptFile.Create(aIoHandles.IoSession(), scriptName, RIoFile::ERead); if ((err == KErrNone) || (err != KErrInUse)) { break; @@ -686,14 +688,9 @@ while (retries >= 0); StaticLeaveIfErr(err, _L("Couldn't open script file %S"), &scriptName); CleanupClosePushL(scriptFile); - TInt scriptFileSize; - User::LeaveIfError(scriptFile.Size(scriptFileSize)); - HBufC8* scriptData = HBufC8::NewLC(scriptFileSize); - TPtr8 scriptDataPtr(scriptData->Des()); - User::LeaveIfError(scriptFile.Read(scriptDataPtr)); - HBufC* decodedScriptData = LtkUtils::DecodeUtf8L(*scriptData); - CleanupStack::PopAndDestroy(2, &scriptFile); - CleanupStack::PushL(decodedScriptData); + scriptFile.AttachL(readHandle, RIoEndPoint::EForeground); + CleanupStack::PopAndDestroy(&scriptFile); + aEnv.SetLocalL(KScriptName); aEnv.SetLocalL(KScriptPath); aEnv.SetLocalL(KScriptLine); @@ -701,6 +698,7 @@ aEnv.SetL(KScriptName, scriptName.NameAndExt()); aEnv.SetL(KScriptPath, scriptName.DriveAndPath()); aEnv.SetL(_L("0"), scriptName); + CScriptCommand* scriptCommand = CScriptCommand::NewLC(scriptName, aIoHandles); TRAP(err, scriptCommand->ParseCommandLineArgsL(aArguments ? *aArguments : KNullDesC(), aEnv, aAdditionalPrefixArguments)); if (err == KErrArgument || scriptCommand->ShouldDisplayHelp()) @@ -723,8 +721,8 @@ } User::LeaveIfError(err); // Propagate error CleanupStack::PopAndDestroy(scriptCommand); - CleanupStack::Pop(decodedScriptData); - return decodedScriptData; + CleanupStack::Pop(&readHandle); + return readHandle; } void CShell::SetToForeground() diff -r 8df58d8c99e8 -r b3ffff030d5c core/src/fshell.h --- a/core/src/fshell.h Tue Oct 26 15:36:30 2010 +0100 +++ b/core/src/fshell.h Thu Oct 28 16:54:54 2010 +0100 @@ -46,7 +46,7 @@ const RPointerArray& Jobs() const; CJob* Job(TInt aId); TInt DisownJob(TInt aId); - static HBufC* ReadScriptL(const TDesC& aScriptName, const TDesC* aArguments, IoUtils::CEnvironment& aEnv, RFs& aFs, TIoHandleSet& aIoHandles, TBool& aHelpPrinted, RPointerArray* aAdditionalPrefixArguments=NULL); + static RIoReadHandle OpenScriptL(const TDesC& aScriptName, const TDesC* aArguments, IoUtils::CEnvironment& aEnv, RFs& aFs, TIoHandleSet& aIoHandles, TBool& aHelpPrinted, RPointerArray* aAdditionalPrefixArguments=NULL); private: CShell(); void ConstructL(); @@ -79,7 +79,7 @@ CLineCompleter* iLineCompleter; CCommandFactory* iCommandFactory; RPointerArray iJobs; - HBufC* iScriptData; + RIoReadHandle iScriptHandle; CParser* iParser; TInt iForegroundJobId; TInt iNextJobId; diff -r 8df58d8c99e8 -r b3ffff030d5c core/src/fshell.mmp --- a/core/src/fshell.mmp Tue Oct 26 15:36:30 2010 +0100 +++ b/core/src/fshell.mmp Thu Oct 28 16:54:54 2010 +0100 @@ -65,6 +65,7 @@ source lexer.cpp source file_reader.cpp source script_command.cpp +source worker_thread.cpp sourcepath ..\builtins source hello.cpp diff -r 8df58d8c99e8 -r b3ffff030d5c core/src/lexer.cpp --- a/core/src/lexer.cpp Tue Oct 26 15:36:30 2010 +0100 +++ b/core/src/lexer.cpp Thu Oct 28 16:54:54 2010 +0100 @@ -12,6 +12,8 @@ #include "lexer.h" +const TInt KMaxReadLength = 512; + // // TToken @@ -52,6 +54,231 @@ // +// CLex - A cut down version of the TLex API that supports reading data incrementally from an RIoReadHandle. +// + +class CLex : public CBase + { +public: + static CLex* NewL(); + ~CLex(); + void Set(const TDesC& aDes); + void Set(RIoReadHandle& aHandle); + void Purge(); + void SkipToEnd(); + TBool EosL(); + void Mark(); + void IncL(TInt aNumber); + TChar GetL(); + TChar Peek() const; + TPtrC RemainderL(TInt aMinLength); + void UnGet(); + TInt Offset() const; + TInt MarkedOffset() const; + TPtrC MarkedToken() const; + const TUint16* Ptr() const; +private: + CLex(); + void DoReadL(); +private: + TLex iLex; + TInt iMarkedOffset; + TPtrC iLexPtr; + RBuf iLexBuf; + TBuf iReadBuf; + RIoReadHandle iHandle; + TBool iUsingHandle; + TBool iEos; + }; + +CLex* CLex::NewL() + { + return new(ELeave) CLex(); + } + +CLex::CLex() : iLexPtr(NULL, 0) + { + } + +CLex::~CLex() + { + iLexBuf.Close(); + } + +void CLex::Set(const TDesC& aDes) + { + iEos = EFalse; + iUsingHandle = EFalse; + iMarkedOffset = 0; + iLexPtr.Set(aDes); + iLex = iLexPtr; + } + +void CLex::Set(RIoReadHandle& aHandle) + { + iEos = EFalse; + iUsingHandle = ETrue; + iMarkedOffset = 0; + iHandle = aHandle; + iHandle.SetReadMode(RIoReadHandle::EOneOrMore); + iLexBuf.Zero(); + iLex = iLexBuf; + } + +void CLex::Purge() + { + if (iUsingHandle) + { + iLexBuf.Delete(0, iLex.Offset()); + iLex = iLexBuf; + } + + iMarkedOffset = 0; + } + +void CLex::SkipToEnd() + { + iEos = ETrue; + } + +TBool CLex::EosL() + { + if (!iEos) + { + if (!iLex.Eos()) + { + // If iLex still has data, then we're definately not at the end of the string. + // Do nothing. This test avoids us doing I/O handle reads before draining using the existing data. + } + else if (iUsingHandle) + { + DoReadL(); + } + else + { + iEos = ETrue; + } + } + return iEos; + } + +void CLex::Mark() + { + iMarkedOffset = iLex.Offset(); + } + +void CLex::IncL(TInt aNumber) + { + if (iUsingHandle) + { + while (!iEos && (iLex.Remainder().Length() < aNumber)) + { + DoReadL(); + } + } + + iLex.Inc(aNumber); + } + +TChar CLex::GetL() + { + if (iUsingHandle && !iEos && (iLex.Remainder().Length() < 1)) + { + DoReadL(); + } + return iLex.Get(); + } + +TChar CLex::Peek() const + { + return iLex.Peek(); + } + +TPtrC CLex::RemainderL(TInt aMinLength) + { + if (iUsingHandle) + { + while (!iEos && (iLex.Remainder().Length() < aMinLength)) + { + DoReadL(); + } + } + return iLex.Remainder(); + } + +void CLex::UnGet() + { + iLex.UnGet(); + } + +TInt CLex::Offset() const + { + return iLex.Offset(); + } + +TInt CLex::MarkedOffset() const + { + return iMarkedOffset; + } + +TPtrC CLex::MarkedToken() const + { + if (iUsingHandle) + { + return TPtrC(iReadBuf.Ptr() + iMarkedOffset, iLex.Offset() - iMarkedOffset); + } + else + { + return TPtrC(iLexPtr.Ptr() + iMarkedOffset, iLex.Offset() - iMarkedOffset); + } + } + +const TUint16* CLex::Ptr() const + { + if (iUsingHandle) + { + return iLexBuf.Ptr(); + } + else + { + return iLexPtr.Ptr(); + } + + } + +void CLex::DoReadL() + { + ASSERT(iUsingHandle); + + if (!iEos) + { + if (iReadBuf.Length() == 0) // iReadBuf may contain data if a realloc of iLexBuf failed previously. + { + TInt err = iHandle.Read(iReadBuf); + if (err == KErrEof) + { + iEos = ETrue; + } + else + { + User::LeaveIfError(err); + } + } + + TInt offset = iLex.Offset(); + if ((iLexBuf.MaxLength() - iLexBuf.Length()) < iReadBuf.Length()) + { + iLexBuf.ReAllocL(iLexBuf.Length() + iReadBuf.Length()); + } + iLexBuf.Append(iReadBuf); + iReadBuf.Zero(); + iLex = iLexBuf; + iLex.Inc(offset); + } + } + + +// // CReservedLookup // @@ -84,6 +311,7 @@ void DefineTokenTypeL(TToken::TType aTokenType, const TDesC& aString); void Reset(); TResult Lookup(const TDesC& aDes); + TInt Longest() const; private: class TReserved { @@ -95,6 +323,7 @@ }; private: RArray iList; + TInt iLongest; }; CReservedLookup* CReservedLookup::NewL() @@ -110,6 +339,10 @@ void CReservedLookup::DefineTokenTypeL(TToken::TType aTokenType, const TDesC& aString) { User::LeaveIfError(iList.Append(TReserved(aTokenType, aString))); + if (aString.Length() > iLongest) + { + iLongest = aString.Length(); + } } CReservedLookup::TResult CReservedLookup::Lookup(const TDesC& aDes) @@ -133,6 +366,11 @@ return result; } +TInt CReservedLookup::Longest() const + { + return iLongest; + } + CReservedLookup::TReserved::TReserved(TToken::TType aType, const TDesC& aString) : iType(aType), iString(aString) { @@ -180,6 +418,7 @@ CLexer::~CLexer() { + delete iLex; delete iReservedLookup; } @@ -190,91 +429,112 @@ void CLexer::Set(const TDesC& aDes, const TChar& aEscapeChar) { - iLex = aDes; + iLex->Set(aDes); + iEscapeChar = aEscapeChar; + } + +void CLexer::Set(RIoReadHandle& aHandle, const TChar& aEscapeChar) + { + iLex->Set(aHandle); iEscapeChar = aEscapeChar; } -TToken CLexer::NextToken() +void CLexer::Purge() + { + iLex->Purge(); + } + +void CLexer::SkipToEnd() { - SkipWhiteSpace(); - iLex.Mark(); + iLex->SkipToEnd(); + } + +TToken CLexer::NextTokenL() + { + SkipWhiteSpaceL(); + iLex->Mark(); TToken::TType type(TToken::ENull); - while (!iLex.Eos()) + while (!iLex->EosL()) { type = TToken::EString; - TChar c = iLex.Get(); + TChar c = iLex->GetL(); if (c == iEscapeChar) { - iLex.Get(); + iLex->GetL(); } else if ((c == '\'') && (iBehaviour & EHandleSingleQuotes)) { - SkipSingleQuotedChars(); + SkipSingleQuotedCharsL(); } else if ((c == '\"') && (iBehaviour & EHandleDoubleQuotes)) { - SkipDoubleQuotedChars(); + SkipDoubleQuotedCharsL(); } else if ((c == '#') && (iBehaviour & EHandleComments)) { - if (iLex.MarkedToken().Length() > 1) + if (iLex->MarkedToken().Length() > 1) { - iLex.UnGet(); + iLex->UnGet(); break; } else { - SkipComment(); - if (iLex.Eos()) + SkipCommentL(); + if (iLex->EosL()) { type = TToken::ENull; break; } else { - iLex.Mark(); + iLex->Mark(); } } } else if (c.IsSpace() && (c != '\n') && (c != '\r')) { - iLex.UnGet(); + iLex->UnGet(); break; } else { - iLex.UnGet(); - CReservedLookup::TResult result = iReservedLookup->Lookup(iLex.Remainder()); + iLex->UnGet(); + CReservedLookup::TResult result = iReservedLookup->Lookup(iLex->RemainderL(iReservedLookup->Longest())); if (result.iResultType == CReservedLookup::TResult::EMatch) { - if (iLex.MarkedToken().Length() > 0) + if (iLex->MarkedToken().Length() > 0) { break; } else { - iLex.Inc(result.iTokenLength); + iLex->IncL(result.iTokenLength); type = result.iTokenType; break; } } - iLex.Get(); + iLex->GetL(); } } - return TToken(type, iLex.MarkedToken(), iLex.MarkedOffset()); + return TToken(type, iLex->MarkedToken(), iLex->MarkedOffset()); } TInt CLexer::CurrentOffset() const { - return iLex.Offset(); + return iLex->Offset(); } -TBool CLexer::More() +TBool CLexer::MoreL() { - SkipWhiteSpace(); - return !iLex.Eos(); + SkipWhiteSpaceL(); + return !iLex->EosL(); + } + +const TUint16* CLexer::Ptr() const + { + return iLex->Ptr(); } CLexer::CLexer(TUint aBehaviour) @@ -284,18 +544,19 @@ void CLexer::ConstructL() { + iLex = CLex::NewL(); iReservedLookup = CReservedLookup::NewL(); } -void CLexer::SkipSingleQuotedChars() +void CLexer::SkipSingleQuotedCharsL() { - while (!iLex.Eos()) + while (!iLex->EosL()) { - TChar c = iLex.Get(); - if ((c == iEscapeChar) && !iLex.Eos() && (iLex.Peek() == '\'')) + TChar c = iLex->GetL(); + if ((c == iEscapeChar) && !iLex->EosL() && (iLex->Peek() == '\'')) { // Allow quoted single quote characters. Note, the is a departure from Bash behaviour, but is in line with Perl and is generally helpful. - iLex.Get(); + iLex->GetL(); } else if (c == '\'') { @@ -304,14 +565,14 @@ } } -void CLexer::SkipDoubleQuotedChars() +void CLexer::SkipDoubleQuotedCharsL() { - while (!iLex.Eos()) + while (!iLex->EosL()) { - TChar c = iLex.Get(); - if ((c == iEscapeChar) && !iLex.Eos()) + TChar c = iLex->GetL(); + if ((c == iEscapeChar) && !iLex->EosL()) { - iLex.Get(); + iLex->GetL(); } else if (c == '"') { @@ -320,27 +581,27 @@ } } -void CLexer::SkipComment() +void CLexer::SkipCommentL() { - while (!iLex.Eos()) + while (!iLex->EosL()) { - TChar c = iLex.Get(); + TChar c = iLex->GetL(); if ((c == '\n') || (c == '\r')) { - iLex.UnGet(); + iLex->UnGet(); break; } } } -void CLexer::SkipWhiteSpace() +void CLexer::SkipWhiteSpaceL() { - while (!iLex.Eos()) + while (!iLex->EosL()) { - TChar c = iLex.Get(); + TChar c = iLex->GetL(); if (!c.IsSpace() || (c == '\n') || (c == '\r')) { - iLex.UnGet(); + iLex->UnGet(); break; } } diff -r 8df58d8c99e8 -r b3ffff030d5c core/src/lexer.h --- a/core/src/lexer.h Tue Oct 26 15:36:30 2010 +0100 +++ b/core/src/lexer.h Thu Oct 28 16:54:54 2010 +0100 @@ -14,7 +14,9 @@ #define __LEXER_H__ #include +#include +class CLex; class CReservedLookup; @@ -72,20 +74,24 @@ ~CLexer(); void DefineTokenTypeL(TToken::TType aTokenType, const TDesC& aString); void Set(const TDesC& aDes, const TChar& aEscapeChar); - TToken NextToken(); + void Set(RIoReadHandle& aHandle, const TChar& aEscapeChar); + void Purge(); + void SkipToEnd(); + TToken NextTokenL(); TInt CurrentOffset() const; - TBool More(); + TBool MoreL(); + const TUint16* Ptr() const; private: CLexer(TUint aBehaviour); void ConstructL(); - void SkipSingleQuotedChars(); - void SkipDoubleQuotedChars(); - void SkipComment(); - void SkipWhiteSpace(); + void SkipSingleQuotedCharsL(); + void SkipDoubleQuotedCharsL(); + void SkipCommentL(); + void SkipWhiteSpaceL(); private: TUint iBehaviour; TChar iEscapeChar; - TLex iLex; + CLex* iLex; CReservedLookup* iReservedLookup; }; diff -r 8df58d8c99e8 -r b3ffff030d5c core/src/line_completer.cpp --- a/core/src/line_completer.cpp Tue Oct 26 15:36:30 2010 +0100 +++ b/core/src/line_completer.cpp Thu Oct 28 16:54:54 2010 +0100 @@ -49,15 +49,15 @@ void CLineCompleter::LcCompleteLineL(TConsoleLine& aLine, const TChar& aEscapeChar) { iLexer->Set(aLine.ContentsToCursor(), aEscapeChar); - TToken token(iLexer->NextToken()); + TToken token(iLexer->NextTokenL()); TToken firstToken = token; TToken prevToken(TToken::EString, KNullDesC, aLine.ContentsToCursor().Length()); TInt lastTokenIdx = 0; - while (iLexer->More()) + while (iLexer->MoreL()) { // More than one token - skip to last. prevToken = token; - token = iLexer->NextToken(); + token = iLexer->NextTokenL(); lastTokenIdx++; } diff -r 8df58d8c99e8 -r b3ffff030d5c core/src/parser.cpp --- a/core/src/parser.cpp Tue Oct 26 15:36:30 2010 +0100 +++ b/core/src/parser.cpp Thu Oct 28 16:54:54 2010 +0100 @@ -54,9 +54,18 @@ CParser* CParser::NewL(TUint aMode, const TDesC& aDes, RIoSession& aIoSession, RIoReadHandle& aStdin, RIoWriteHandle& aStdout, RIoWriteHandle& aStderr, IoUtils::CEnvironment& aEnv, CCommandFactory& aFactory, MParserObserver* aObserver, TInt aStartingLineNumber) { - CParser* self = new(ELeave) CParser(aMode, aDes, aIoSession, aStdin, aStdout, aStderr, aEnv, aFactory, aObserver, aStartingLineNumber); + CParser* self = new(ELeave) CParser(aMode, aIoSession, aStdin, aStdout, aStderr, aEnv, aFactory, aObserver, aStartingLineNumber); CleanupStack::PushL(self); - self->ConstructL(); + self->ConstructL(&aDes, NULL); + CleanupStack::Pop(); + return self; + } + +CParser* CParser::NewL(TUint aMode, RIoReadHandle& aSourceHandle, RIoSession& aIoSession, RIoReadHandle& aStdin, RIoWriteHandle& aStdout, RIoWriteHandle& aStderr, IoUtils::CEnvironment& aEnv, CCommandFactory& aFactory, MParserObserver* aObserver) + { + CParser* self = new(ELeave) CParser(aMode, aIoSession, aStdin, aStdout, aStderr, aEnv, aFactory, aObserver); + CleanupStack::PushL(self); + self->ConstructL(NULL, &aSourceHandle); CleanupStack::Pop(); return self; } @@ -78,12 +87,12 @@ } } -CParser::CParser(TUint aMode, const TDesC& aDes, RIoSession& aIoSession, RIoReadHandle& aStdin, RIoWriteHandle& aStdout, RIoWriteHandle& aStderr, IoUtils::CEnvironment& aEnv, CCommandFactory& aFactory, MParserObserver* aObserver, TInt aStartingLineNumber) - : iMode(aMode), iData(aDes), iIoSession(aIoSession), iStdin(aStdin), iStdout(aStdout), iStderr(aStderr), iEnv(aEnv), iFactory(aFactory), iObserver(aObserver), iCompletionError(aStderr, aEnv), iNextLineNumber(aStartingLineNumber) +CParser::CParser(TUint aMode, RIoSession& aIoSession, RIoReadHandle& aStdin, RIoWriteHandle& aStdout, RIoWriteHandle& aStderr, IoUtils::CEnvironment& aEnv, CCommandFactory& aFactory, MParserObserver* aObserver, TInt aStartingLineNumber) + : iMode(aMode), iIoSession(aIoSession), iStdin(aStdin), iStdout(aStdout), iStderr(aStderr), iEnv(aEnv), iFactory(aFactory), iObserver(aObserver), iCompletionError(aStderr, aEnv), iNextLineNumber(aStartingLineNumber) { } -void CParser::ConstructL() +void CParser::ConstructL(const TDesC* aDes, RIoReadHandle* aSourceHandle) { if (iObserver) { @@ -100,7 +109,14 @@ iLexer1->DefineTokenTypeL(TToken::ENewLine, KNewLine3); iLexer1->DefineTokenTypeL(TToken::ENewLine, KNewLine4); iLexer1->DefineTokenTypeL(TToken::ESemicolon, KSemicolon); - iLexer1->Set(iData, iEnv.EscapeChar()); + if (aDes) + { + iLexer1->Set(*aDes, iEnv.EscapeChar()); + } + else + { + iLexer1->Set(*aSourceHandle, iEnv.EscapeChar()); + } iLexer2 = CLexer::NewL(CLexer::EHandleSingleQuotes | CLexer::EHandleDoubleQuotes); iLexer2->DefineTokenTypeL(TToken::EPipe, KPipe); @@ -350,10 +366,10 @@ } else { - if (aLexer.More()) + if (aLexer.MoreL()) { redirection->iType = ((aTokenType == TToken::ERedirectStdoutToFileAppend) || (aTokenType == TToken::ERedirectStderrToFileAppend)) ? RPipeSection::TRedirection::EFileAppend : RPipeSection::TRedirection::EFile; - TToken fileName(aLexer.NextToken()); + TToken fileName(aLexer.NextTokenL()); redirection->SetFileNameL(aCwd, fileName.String()); } else @@ -412,14 +428,14 @@ CleanupClosePushL(pipeSection); TInt offset = iLexer2->CurrentOffset(); TBool background(EFalse); - while (iLexer2->More()) + while (iLexer2->MoreL()) { - TToken token(iLexer2->NextToken()); + TToken token(iLexer2->NextTokenL()); switch (token.Type()) { case TToken::EPipe: { - pipeSection.iFullName.Set(iData.Ptr() + offset, iLexer2->CurrentOffset() - offset - token.String().Length()); + pipeSection.iFullName.Set(iLexer2->Ptr() + offset, iLexer2->CurrentOffset() - offset - token.String().Length()); offset = iLexer2->CurrentOffset(); User::LeaveIfError(pipeSections.Append(pipeSection)); new(&pipeSection) RPipeSection; @@ -485,7 +501,7 @@ } else { - pipeSection.iFullName.Set(iData.Ptr() + offset, iLexer2->CurrentOffset() - offset); + pipeSection.iFullName.Set(iLexer2->Ptr() + offset, iLexer2->CurrentOffset() - offset); User::LeaveIfError(pipeSections.Append(pipeSection)); CleanupStack::Pop(&pipeSection); if ((iMode & EDebug) && iObserver) @@ -504,11 +520,11 @@ iForegroundPipeLine = CPipeLine::NewL(iIoSession, iStdin, iStdout, iStderr, iEnv, iFactory, pipeSections, background, this, iCompletionError); } CleanupStack::PopAndDestroy(&pipeSections); - if (aIsForeground && !iLexer1->More()) + if (aIsForeground && !iLexer1->MoreL()) { *aIsForeground = !background; } - if (background && iLexer1->More()) + if (background && iLexer1->MoreL()) { iNextPipeLineCallBack->Call(); } @@ -535,14 +551,16 @@ { aReachedLineEnd = EFalse; aCondition = ENone; + + iLexer1->Purge(); TInt startOffset = iLexer1->CurrentOffset(); TInt endOffset = -1; TBool foundSomething(EFalse); - while (iLexer1->More()) + while (iLexer1->MoreL()) { TBool finished(EFalse); - TToken token(iLexer1->NextToken()); + TToken token(iLexer1->NextTokenL()); switch (token.Type()) { @@ -616,7 +634,7 @@ if (foundSomething) { - aData.Set(iData.Ptr() + startOffset, endOffset - startOffset); + aData.Set(iLexer1->Ptr() + startOffset, endOffset - startOffset); } else { @@ -636,7 +654,7 @@ aLexer.Set(*buf, escapeChar); FOREVER { - TToken token(aLexer.NextToken()); + TToken token(aLexer.NextTokenL()); if (token.Type() == TToken::ENull) { break; @@ -715,7 +733,7 @@ lexer1->Set(*buf, iEnv.EscapeChar()); FOREVER { - TToken token(lexer1->NextToken()); + TToken token(lexer1->NextTokenL()); if (token.Type() == TToken::ENull) { break; @@ -756,35 +774,35 @@ return buf; } -TInt CParser::SkipLineRemainder() +void CParser::SkipLineRemainderL() { - while (iLexer1->More()) + TRAPD(err, DoSkipLineRemainderL()); + if (err) { - TToken token(iLexer1->NextToken()); + SkipToEnd(); + User::Leave(err); + } + } + +void CParser::DoSkipLineRemainderL() + { + while (iLexer1->MoreL()) + { + TToken token(iLexer1->NextTokenL()); if (token.Type() == TToken::ENewLine) { if (iMode & EExportLineNumbers) { - // can we do something better with errors here? - TRAPD(err, iEnv.SetL(KScriptLine, iNextLineNumber++)); - if (err!=KErrNone) - { - iCompletionError.Set(err, TError::EFailedToSetScriptLineVar); - return err; - } + iEnv.SetL(KScriptLine, iNextLineNumber++); } break; } } - return KErrNone; } void CParser::SkipToEnd() { - while (iLexer1->More()) - { - iLexer1->NextToken(); - } + iLexer1->SkipToEnd(); } TInt CParser::CompletionCallBack(TAny* aSelf) @@ -809,13 +827,18 @@ void CParser::HandlePipeLineComplete(CPipeLine& aPipeLine, const TError& aError) { - TRAPD(err, iEnv.SetL(KChildError, aError.Error())); + TRAPD(err, HandlePipeLineCompleteL(aPipeLine, aError)); if (err) { - iCompletionError.Set(err, TError::EFailedToSetChildErrorVar); + iCompletionError.Set(err, TError::EPipelineCompletionError); iCompletionCallBack->CallBack(); return; } + } + +void CParser::HandlePipeLineCompleteL(CPipeLine& aPipeLine, const TError& aError) + { + iEnv.SetL(KChildError, aError.Error()); if ((iMode & EDebug) && iObserver) { @@ -844,8 +867,7 @@ } else if (aError.Error() != KErrNone) { - TInt err = SkipLineRemainder(); - if (err!=KErrNone) SkipToEnd(); + SkipLineRemainderL(); } break; } @@ -857,8 +879,7 @@ } else if (aError.Error() == KErrNone) { - TInt err = SkipLineRemainder(); - if (err!=KErrNone) SkipToEnd(); + SkipLineRemainderL(); } break; } @@ -879,7 +900,7 @@ delete iForegroundPipeLine; iForegroundPipeLine = NULL; - if (iLexer1->More()) + if (iLexer1->MoreL()) { iNextPipeLineCallBack->Call(); } @@ -896,7 +917,7 @@ delete &aPipeLine; } - if (iObserver && !iLexer1->More() && (iForegroundPipeLine == NULL) && (iBackgroundPipeLines.Count() == 0)) + if (iObserver && !iLexer1->MoreL() && (iForegroundPipeLine == NULL) && (iBackgroundPipeLines.Count() == 0)) { iCompletionCallBack->CallBack(); } diff -r 8df58d8c99e8 -r b3ffff030d5c core/src/parser.h --- a/core/src/parser.h Tue Oct 26 15:36:30 2010 +0100 +++ b/core/src/parser.h Thu Oct 28 16:54:54 2010 +0100 @@ -42,6 +42,7 @@ }; public: static CParser* NewL(TUint aMode, const TDesC& aDes, RIoSession& aIoSession, RIoReadHandle& aStdin, RIoWriteHandle& aStdout, RIoWriteHandle& aStderr, IoUtils::CEnvironment& aEnv, CCommandFactory& aFactory, MParserObserver* aObserver, TInt aStartingLineNumber = 1); + static CParser* NewL(TUint aMode, RIoReadHandle& aSourceHandle, RIoSession& aIoSession, RIoReadHandle& aStdin, RIoWriteHandle& aStdout, RIoWriteHandle& aStderr, IoUtils::CEnvironment& aEnv, CCommandFactory& aFactory, MParserObserver* aObserver); ~CParser(); void Start(); void Start(TBool& aIsForeground); @@ -62,14 +63,17 @@ EAndOr }; private: - CParser(TUint aMode, const TDesC& aDes, RIoSession& aIoSession, RIoReadHandle& aStdin, RIoWriteHandle& aStdout, RIoWriteHandle& aStderr, IoUtils::CEnvironment& aEnv, CCommandFactory& aFactory, MParserObserver* aObserver, TInt aStartingLineNumber=1); - void ConstructL(); + CParser(TUint aMode, RIoSession& aIoSession, RIoReadHandle& aStdin, RIoWriteHandle& aStdout, RIoWriteHandle& aStderr, IoUtils::CEnvironment& aEnv, CCommandFactory& aFactory, MParserObserver* aObserver, TInt aStartingLineNumber=1); + void ConstructL(const TDesC* aDes, RIoReadHandle* aSourceHandle); void CreateNextPipeLine(TBool* aIsForeground); void CreateNextPipeLineL(TBool* aIsForeground); void FindNextPipeLineL(TPtrC& aData, TCondition& aCondition, TBool& aReachedLineEnd); HBufC* ExpandVariablesLC(const TDesC& aData); - TInt SkipLineRemainder(); + void SkipLineRemainderL(); + void DoSkipLineRemainderL(); void SkipToEnd(); + TBool MoreSourceData() const; + void HandlePipeLineCompleteL(CPipeLine& aPipeLine, const TError& aError); static TInt CompletionCallBack(TAny* aSelf); static TInt NextCallBack(TAny* aSelf); static TInt ExitCallBack(TAny* aSelf); @@ -77,7 +81,6 @@ virtual void HandlePipeLineComplete(CPipeLine& aPipeLine, const TError& aError); private: const TUint iMode; - const TPtrC iData; TCondition iCondition; RIoSession& iIoSession; RIoReadHandle iStdin; diff -r 8df58d8c99e8 -r b3ffff030d5c core/src/pipe_line.cpp --- a/core/src/pipe_line.cpp Tue Oct 26 15:36:30 2010 +0100 +++ b/core/src/pipe_line.cpp Thu Oct 28 16:54:54 2010 +0100 @@ -601,7 +601,7 @@ TOverflowTruncate overflow; buf.AppendFormat(KFormat, &overflow, thisPipedCommand.iCommandName, aError); iStderr.Write(buf); - if (aError >= 0) + if (aError >= 0) { // Terminate 0 shouldn't equate to a completionError of KErrNone aError = KErrDied; diff -r 8df58d8c99e8 -r b3ffff030d5c core/src/worker_thread.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/worker_thread.cpp Thu Oct 28 16:54:54 2010 +0100 @@ -0,0 +1,744 @@ +// worker_thread.cpp +// +// Copyright (c) 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 +// + +/* + +Some notes on how CThreadPool works: + * There are 2 types of CWorkerThread - ones that share a specific heap, and those that have their own heap. + * Tasks that need a shared heap can only be run using a CWorkerThread that is bound to that heap (one will be created if necessary) + * Tasks that don't need a shared heap can be run on any CWorkerThread that has its own heap. + * Excess CWorkerThreads are deleted after they've been idle for KCacheTime. + * CThreadPool uses an RFastLock on all operations that could be called from multiple threads. + * All member data of CThreadPool (including CWorkerThreads and their members) is kept on iThreadPoolAllocator, which was the heap + that the CThreadPool was created on. User::SwitchAllocator() is used where necessary to manipulate CThreadPool data from other threads + while the Lock is held + * When a task is queued, a non-busy CWorkerThread is found (or created). + * When a task is completed in a worker thread, it calls iParentThread.RequestComplete(iCompletionStatus, err). It then calls + CThreadPool::WorkerFinished() to set the CWorkerThread to be non-busy again. + * When a CWorkerThread is created it arranges (via SignalSelf()) to add a CThreadDeathWatcher to the main thread. + It follows that notifications about tasks failed because of thread death are always serviced by the main thread, which must therefore + remain responsive. (In the non-dead case, the completion notification is sent directly from the worker thread). + +*/ + +#include "worker_thread.h" +#include + +#define WT_LOG(args...) + +// These defines are for debugging only +//#define WT_LOG(args...) RDebug::Print(args) +// These probably don't even work any more - use with extreme caution! +//#define NO_REUSE +//#define IMMEDIATE_CLEANUP + +const TInt KCacheTime = 1000000; // 1 second + +// Thread death watchers run in the context of the thread pool main thread +class CThreadDeathWatcher : public CActive + { +public: + CThreadDeathWatcher(CWorkerThread* aWorker) + : CActive(CActive::EPriorityHigh), iWorker(aWorker) + { + } + ~CThreadDeathWatcher() + { + WT_LOG(_L("Deleting thread death watcher for worker %d"), TUint(iWorker->GetThreadId())); + Cancel(); + } + void StartWatching() + { + CActiveScheduler::Add(this); + iWorker->iWorkerThread.Logon(iStatus); + SetActive(); + } + CWorkerThread* WorkerThread() const + { + return iWorker; + } +private: + void DoCancel() + { + iWorker->iWorkerThread.LogonCancel(iStatus); + } + void RunL() + { + iWorker->SignalClientThatThreadHasDied(); + iWorker->iParentPool->WorkerDied(iWorker); + // WorkerDied may cause this object to be deleted, so don't add anything that accesses member data below this point! + } + +private: + CWorkerThread* iWorker; + }; + +// + + + +CThreadPool* CThreadPool::NewL() + { + CThreadPool* self = new(ELeave) CThreadPool(); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +CThreadPool::CThreadPool() + : CActive(CActive::EPriorityLow) // Cleanup doesn't need to be a priority + { + CActiveScheduler::Add(this); + } + +void CThreadPool::ConstructL() + { + User::LeaveIfError(iMainThread.Open(RThread().Id())); + iIdleTimer = CPeriodic::NewL(CActive::EPriorityLow-1); // Interactions around iPendingThreadLogons mean it's probably a good idea to have this priority below that of CThreadPool itself + iThreadPoolAllocator = &User::Allocator(); + User::LeaveIfError(iLock.CreateLocal()); + iThreads.ReserveL(2); + iThreadDeathWatchers.ReserveL(2); + // We don't create any workers by default + } + +CThreadPool::~CThreadPool() + { + WT_LOG(_L("Deleting thread pool. %d threads created during its lifetime, %d currently and %d watchers"), iCountThreadsCreated, iThreads.Count(), iThreadDeathWatchers.Count()); + Cancel(); + for (TInt i = 0; i < iThreads.Count(); i++) + { + iThreads[i]->Shutdown(); + } + iThreadDeathWatchers.ResetAndDestroy(); + iThreads.ResetAndDestroy(); + iLock.Close(); + delete iIdleTimer; + iMainThread.Close(); + iPendingThreadLogons.Close(); + } + +void CThreadPool::Lock() + { + WT_LOG(_L("Getting lock from thread %d"), TUint(RThread().Id())); + iLock.Wait(); + WT_LOG(_L("Got lock from thread %d"), TUint(RThread().Id())); + } + +void CThreadPool::SwitchToThreadPoolHeap() + { + //ASSERT(iLock.IsHeld()); + RAllocator* allocator = &User::Allocator(); + if (allocator != iThreadPoolAllocator) + { + WT_LOG(_L("Thread %d switching from 0x%x to thread pool allocator 0x%x"), TUint(RThread().Id()), allocator, iThreadPoolAllocator); + iTempThreadAllocator = User::SwitchAllocator(iThreadPoolAllocator); + } + } + +void CThreadPool::RestoreHeap() + { + if (iTempThreadAllocator) + { + WT_LOG(_L("Thread %d restoring heap 0x%x"), TUint(RThread().Id()), iTempThreadAllocator); + User::SwitchAllocator(iTempThreadAllocator); + iTempThreadAllocator = NULL; + } + } + +void CThreadPool::Unlock() + { + RestoreHeap(); + WT_LOG(_L("Releasing lock from thread %d"), TUint(RThread().Id())); + iLock.Signal(); + } + +void CThreadPool::LockLC() + { + Lock(); + CleanupStack::PushL(TCleanupItem(&DoUnlock, &iLock)); + } + +#define _LOFF(p,T,f) ((T*)(((TUint8*)(p))-_FOFF(T,f))) // Why isn't this defined user-side? + +void CThreadPool::DoUnlock(TAny* aLock) + { + CThreadPool* self = _LOFF(aLock, CThreadPool, iLock); + self->Unlock(); + } + +MThreadedTask* CThreadPool::NewTaskInSeparateThreadL(const TDesC& aThreadName, TBool aSharedHeap, MTaskRunner::TThreadFunctionL aThreadFunction, TAny* aThreadContext) + { + WT_LOG(_L("1. NewTaskInSeparateThreadL task %d (%S)"), iTaskCounter, &aThreadName); + + LockLC(); + // Hunt for a non-busy thread + CWorkerThread* foundThread = NULL; + RAllocator* requiredAllocator = aSharedHeap ? &User::Allocator() : NULL; +#ifndef NO_REUSE // This code normally does run, except during debugging when NO_REUSE is defined + for (TInt i = 0; i < iThreads.Count(); i++) + { + CWorkerThread* thread = iThreads[i]; + if (!thread->Busy() && thread->SharedAllocator() == requiredAllocator) + { + // If the worker thread is sharing an allocator, it must be sharing the *same* one as this current thread + ASSERT(thread->Running()); + foundThread = thread; + break; + } + } +#endif + + if (foundThread == NULL) + { + SwitchToThreadPoolHeap(); + iPendingThreadLogons.ReserveL(iPendingThreadLogons.Count() + 1); // So the Append below can't fail + iThreadDeathWatchers.ReserveL(iThreadDeathWatchers.Count() + 1); + iThreads.ReserveL(iThreads.Count() + 1); + foundThread = CWorkerThread::NewLC(this, requiredAllocator); + CThreadDeathWatcher* threadWatcher = new(ELeave) CThreadDeathWatcher(foundThread); + iCountThreadsCreated++; + WT_LOG(_L("Created new worker thread %d"), TUint(foundThread->GetThreadId())); + iThreads.Append(foundThread); + iPendingThreadLogons.Append(threadWatcher); + iThreadDeathWatchers.Append(threadWatcher); + CleanupStack::Pop(foundThread); + + SignalSelf(); // So the iPendingThreadLogons gets sorted out in context of main thread + RestoreHeap(); + } + + WT_LOG(_L("Using worker thread %d for task %d (%S)"), TUint(foundThread->GetThreadId()), iTaskCounter, &aThreadName); + + User::LeaveIfError(foundThread->Setup(iTaskCounter, aThreadName, aThreadFunction, aThreadContext)); + foundThread->SetBusy(ETrue); + iTaskCounter++; + CleanupStack::PopAndDestroy(&iLock); + return foundThread; + } + +void CThreadPool::WorkerDied(CWorkerThread* aWorker) + { + Lock(); + // This is now always called in the main thread + ASSERT(RThread().Id() == iMainThread.Id()); + + for (TInt i = 0; i < iThreadDeathWatchers.Count(); i++) + { + if (iThreadDeathWatchers[i]->WorkerThread() == aWorker) + { + // Clean up the watcher first + delete iThreadDeathWatchers[i]; + iThreadDeathWatchers.Remove(i); + + // The indexes in both arrays are guaranteed to be the same + ASSERT(iThreads[i] == aWorker); + delete aWorker; + iThreads.Remove(i); + + break; + } + } + Unlock(); + } + +void CThreadPool::WorkerFinished(CWorkerThread* aWorker) + { + Lock(); + aWorker->SetBusy(EFalse); +#if defined(NO_REUSE) + // Nothing +#else + // This is the normal case - queue ourself to run (on the main thread) so we can trigger the idle timer from our RunL + // Can't do that directly as timers are all thread-local + SignalSelf(); +#endif + Unlock(); + } + + +void CThreadPool::SignalSelf() + { + // TODO: Optimise if we actually are the main thread? + + // Must be holding lock + iPendingCallbacks++; + TRequestStatus* stat = &iStatus; + if (iPendingCallbacks == 1) // Can't use IsActive() as we might not be in the same thread + { + iStatus = KRequestPending; + SetActive(); + } + iMainThread.RequestComplete(stat, KErrNone); // Fortunately RThread::RequestComplete doesn't set the status to KRequestPending before completing it (unlike User::RequestComplete) + } + +void CThreadPool::CleanupAnyWorkersSharingAllocator(RAllocator* aAllocator) + { + Lock(); + //SwitchToThreadPoolHeap(); // Not necessary, Shutdown doesn't alloc + for (TInt i = iThreads.Count() - 1; i >= 0; i--) + { + CWorkerThread* worker = iThreads[i]; + if (worker->SharedAllocator() == aAllocator) + { + WT_LOG(_L("Shutting down worker thread id %d because it shares allocator %x"), (TUint)worker->GetThreadId(), aAllocator); + ASSERT(!worker->Busy()); + worker->Shutdown(); + // We don't delete the worker here, let CThreadDeathWatcher handle that + } + } + Unlock(); + } + +void CThreadPool::PerformHouseKeeping() + { + // Time to do some housekeeping. Algorithm is: + // * Keep a single spare non-busy shared worker around, but only for the main heap (ie a CWorkerThread whose SharedAllocator() equals iThreadPoolAllocator) + // * Bin everything else that isn't busy + + WT_LOG(_L("Idle timer expired, cleaning up spare workers")); + Lock(); + ASSERT(&User::Allocator() == iThreadPoolAllocator); // We're running in the thread pool's main thread so no need to switch allocators + +#ifdef IMMEDIATE_CLEANUP + // Everything gets nuked if this is defined + TBool foundSpareWorker = ETrue; +#else + TBool foundSpareWorker = EFalse; +#endif + for (TInt i = iThreads.Count() - 1; i >= 0; i--) + { + CWorkerThread* worker = iThreads[i]; + if (!worker->Busy()) + { + RAllocator* allocator = worker->SharedAllocator(); + if (allocator == iThreadPoolAllocator && !foundSpareWorker) + { + // This one can stay + foundSpareWorker = ETrue; + } + else + { + // Everything else (that isn't busy) gets cleaned up + delete iThreadDeathWatchers[i]; + iThreadDeathWatchers.Remove(i); + worker->Shutdown(); + delete worker; + iThreads.Remove(i); + } + } + } + Unlock(); + } + +void CThreadPool::DoCancel() + { + // There's nothing we can cancel as we complete ourself + } + +void CThreadPool::RunL() + { + Lock(); + iPendingCallbacks--; + while (iPendingCallbacks) + { + // Consume any further signals currently pending - we're somewhat abusing the active scheduler by completing the same repeatedly without it running in between so we have to consume the abuse here to balance things + User::WaitForRequest(iStatus); + iPendingCallbacks--; + } + + // We kinda overload our RunL, using it for both registering logons and triggering the idle cleanup. Ah well. + + if (iPendingThreadLogons.Count()) + { + for (TInt i = 0; i < iPendingThreadLogons.Count(); i++) + { + iPendingThreadLogons[i]->StartWatching(); + } + SwitchToThreadPoolHeap(); + iPendingThreadLogons.Reset(); + } + +#ifdef IMMEDIATE_CLEANUP + Unlock(); + // Delete the thread straight away + PerformHouseKeeping(); +#else + // Normally go through the timer + iIdleTimer->Cancel(); // Reset it if it's already counting + iIdleTimer->Start(KCacheTime, KCacheTime, TCallBack(&TimerCallback, this)); + Unlock(); +#endif + } + +TInt CThreadPool::TimerCallback(TAny* aSelf) + { + CThreadPool* self = static_cast(aSelf); + self->iIdleTimer->Cancel(); // Stop the thing being periodic + self->PerformHouseKeeping(); + return 0; + } + +TBool CThreadPool::SharesThreadPoolAllocator(CWorkerThread* aWorker) const + { + return aWorker->SharedAllocator() == iThreadPoolAllocator; + } + +//// + +const TInt KMaxHeapSize = 1024 * 1024; + +// CWorkerThreadDispatchers run in the context of the worker thread they're owned by +class CWorkerThreadDispatcher : public CActive + { +public: + CWorkerThreadDispatcher(CWorkerThread* aThread) + : CActive(CActive::EPriorityStandard), iThread(aThread) + { + CActiveScheduler::Add(this); + iStatus = KRequestPending; + SetActive(); + } + + void RunL() + { + if (iStatus.Int() == KErrNone) + { + iStatus = KRequestPending; + SetActive(); + iThread->ThreadRun(); + } + else + { + // Time to die + iThread->iAsWait.AsyncStop(); + } + } + + void DoCancel() {} // Can never happen because we can only ever be destroyed as a result of the AsyncStop in RunL from which we can never be active + +private: + CWorkerThread* iThread; + }; + +CWorkerThread* CWorkerThread::NewLC(CThreadPool* aParentPool, RAllocator* aSharedAllocator) + { + CWorkerThread* self = new(ELeave) CWorkerThread(aParentPool, aSharedAllocator); + CleanupStack::PushL(self); + self->ConstructL(); + return self; + } + +CWorkerThread::CWorkerThread(CThreadPool* aParentPool, RAllocator* aSharedAllocator) + : iParentPool(aParentPool), iSharedAllocator(aSharedAllocator) + { + iWorkerThread.SetHandle(0); + } + +void CWorkerThread::ConstructL() + { + TInt err = KErrAlreadyExists; + TInt nonce = 0; + while (err == KErrAlreadyExists) + { + TName name; + if (nonce == 0) + { + name.Format(_L("WorkerThread_%x"), this); + } + else + { + name.Format(_L("WorkerThread_%x_%d"), this, nonce); + } + nonce++; + if (iSharedAllocator) + { + err = iWorkerThread.Create(name, &ThreadFn, KDefaultStackSize, iSharedAllocator, this); + } + else + { + // Create a new heap with default heap size + err = iWorkerThread.Create(name, &ThreadFn, KDefaultStackSize, KMinHeapSize, KMaxHeapSize, this); + } + } + User::LeaveIfError(err); + + TRequestStatus stat; + iWorkerThread.Rendezvous(stat); + + ASSERT(stat == KRequestPending); + if (stat == KRequestPending) + { + iWorkerThread.Resume(); + } + else + { + iWorkerThread.Kill(stat.Int()); + } + + User::WaitForRequest(stat); + User::LeaveIfError(stat.Int()); + // Thread is now ready to do stuff + } + +CWorkerThread::~CWorkerThread() + { + if (iWorkerThread.Handle()) + { + WT_LOG(_L("Deleting worker thread %d"), TUint(GetThreadId())); + } + else + { + // Haven't constructed the thread yet, so all we have available to log is our this pointer + WT_LOG(_L("Deleting worker thread 0x%08x"), this); + } + ASSERT(iWorkerThread.Handle() == 0 || iWorkerThread.ExitType() != EExitPending); + iParentThread.Close(); + iWorkerThread.Close(); + } + +TInt CWorkerThread::Setup(TInt aTaskId, const TDesC& aThreadName, MTaskRunner::TThreadFunctionL aThreadFunction, TAny* aThreadContext) + { + ASSERT(!Busy()); + + // Things to do in preparation for running a command: + // 1. Check what thread we're running in now and set ourselves and our thread death watcher on its scheduler (may not be the thread that created us originally) + // 2. Store the required context for the worker thread to access + + TInt err = iParentThread.Open(RThread().Id()); + if (!err) + { + iTaskId = aTaskId; + iName = aThreadName.Left(iName.MaxLength()); + iFn = aThreadFunction; + iContext = aThreadContext; + } + return err; + } + +TInt CWorkerThread::ExecuteTask(TRequestStatus& aCompletionStatus) + { + WT_LOG(_L("2. + Go task %d (%S)"), iTaskId, &iName); + + ASSERT(iCompletionStatus == NULL); + aCompletionStatus = KRequestPending; + iCompletionStatus = &aCompletionStatus; + + // Setup rendezvous and completion requestStatuses before signalling iDispatchStatus + TRequestStatus rendezvousStat; + iWorkerThread.Rendezvous(rendezvousStat); + + // Signal the worker thread to do its thing + TRequestStatus* dispatchStat = iDispatchStatus; + iWorkerThread.RequestComplete(dispatchStat, KErrNone); + + User::WaitForRequest(rendezvousStat); + + TInt err = rendezvousStat.Int(); + if (iWorkerThread.ExitType() != EExitPending && rendezvousStat.Int() >= 0) + { + err = KErrDied; + } + + WT_LOG(_L("6. - Go task %d (%S) err=%d"), iTaskId, &iName, err); + + if (err != KErrNone) + { + // We don't signal completion if there was an error prior to the rendezvous, we just return it here + iCompletionStatus = NULL; + } + return err; + } + +TThreadId CWorkerThread::GetThreadId() const + { + return iWorkerThread.Id(); + } + +void CWorkerThread::AbortTask() + { + // Undo setup + iName.Zero(); + iFn = NULL; + iContext = NULL; + iParentThread.Close(); + iParentPool->WorkerFinished(this); + } + +void CWorkerThread::ThreadRun() + { + // Runs in the worker thread + + if (!UsingSharedAllocator()) + { + __UHEAP_MARK; + } + + TInt i = 0; + TInt err = KErrNone; + do + { + TName threadName; + threadName.Format(_L("%S_%02d"), &iName, i++); + err = User::RenameThread(threadName); + if (err == KErrNone) + { + WT_LOG(_L("3. Running thread for task %d (%S)"), iTaskId, &threadName); + } + } + while (err == KErrAlreadyExists); + + // Execute the actual function + WT_LOG(_L("4. + ThreadRun for task %d (%S)"), iTaskId, &iName); + TRAP(err, (*iFn)(iContext)); + WT_LOG(_L("7. - ThreadRun for task %d (%S) signalling thread %d with err=%d"), iTaskId, &iName, TUint(iParentThread.Id()), err); + + if (!UsingSharedAllocator()) + { + // Do this before saying we've actually finished the task, otherwise we risk deadlocking on the thread pool lock when IMMEDIATE_CLEANUP is defined + // because CleanupAnyWorkersSharingAllocator takes the lock, but the lock can already be held by that point around the Shutdown that IMMEDIATE_CLEANUP does. + iParentPool->CleanupAnyWorkersSharingAllocator(&User::Allocator()); // Otherwise the heap check will fail + } + + // And signal back the result + iParentPool->WorkerFinished(this); + CompleteParentRequest(err); + + // Finally put our name back to what it was +#ifdef _DEBUG + _LIT(KDebugName, "WorkerThread_%x (was %S)"); + TName threadName = RThread().Name(); + TPtrC oldName = threadName.Left(threadName.MaxLength() - KDebugName().Length()); + TName newName; + newName.Format(KDebugName, this, &oldName); + User::RenameThread(newName); +#else + TName threadName; + threadName.Format(_L("WorkerThread_%x"), this); + User::RenameThread(threadName); +#endif + + if (!UsingSharedAllocator()) + { + __UHEAP_MARKEND; + } + } + +TBool CWorkerThread::Busy() const + { + return iBusy; + } + +void CWorkerThread::SetBusy(TBool aBusy) + { + iBusy = aBusy; + } + +TBool CWorkerThread::UsingSharedAllocator() const + { + return iSharedAllocator != NULL; + } + +RAllocator* CWorkerThread::SharedAllocator() const + { + return iSharedAllocator; + } + +void CWorkerThread::SignalClientThatThreadHasDied() + { + WT_LOG(_L("Task %d died with exittype %d reason %d"), iTaskId, iWorkerThread.ExitType(), iWorkerThread.ExitReason()); + TInt err = iWorkerThread.ExitReason(); + if (err >= 0) err = KErrDied; + CompleteParentRequest(err); + } + +TInt CWorkerThread::ThreadFn(TAny* aSelf) + { + CWorkerThread* self = static_cast(aSelf); + if (self->iParentPool->SharesThreadPoolAllocator(self)) + { + // If we're sharing the main fshell heap, we have to play by the rules and not crash + User::SetCritical(User::EProcessCritical); + } + else + { + __UHEAP_MARK; + } + TInt err = KErrNoMemory; + CTrapCleanup* cleanup = CTrapCleanup::New(); + //WT_LOG(_L("Worker thread %d creating trapcleanup 0x%x"), TUint(RThread().Id()), cleanup); + if (cleanup) + { + TRAP(err, self->ThreadFnL()); + //WT_LOG(_L("Worker thread %d deleting trapcleanup 0x%x"), TUint(RThread().Id()), cleanup); + delete cleanup; + } + if (!self->UsingSharedAllocator()) + { + __UHEAP_MARKEND; + } + return err; + } + +void CWorkerThread::ThreadFnL() + { + CActiveScheduler* scheduler = new(ELeave) CActiveScheduler; + CleanupStack::PushL(scheduler); + CActiveScheduler::Install(scheduler); + + CWorkerThreadDispatcher* dispatcher = new(ELeave) CWorkerThreadDispatcher(this); + CleanupStack::PushL(dispatcher); + iDispatchStatus = &dispatcher->iStatus; + RThread::Rendezvous(KErrNone); + iAsWait.Start(); + CleanupStack::PopAndDestroy(2, scheduler); // dispatcher, scheduler + } + +void CWorkerThread::CompleteParentRequest(TInt aError) + { + if (iCompletionStatus) + { + // If the parent thread has died, then the completion status pointer might no longer be valid (as it would point into the parent's heap + // that might now no longer exist) so we can't safely use it in that case + if (iParentThread.ExitType() == EExitPending) + { + iParentThread.RequestComplete(iCompletionStatus, aError); + } + else + { + iCompletionStatus = NULL; + } + } + } + +void CWorkerThread::Shutdown() + { + // Can be called from (potentially) any thread. Don't alloc or delete as might not be switched to the thread pool allocator + WT_LOG(_L("Shutting down worker thread %d whose exittype is %d"), TUint(GetThreadId()), iWorkerThread.ExitType()); + + if (Busy()) + { + WT_LOG(_L("Thread is still busy - killing it")); + iWorkerThread.Kill(KErrAbort); + // The thread death watcher should take care of everything else, eventually + } + else if (iWorkerThread.ExitType() == EExitPending) + { + TRequestStatus stat; + iWorkerThread.Logon(stat); + iWorkerThread.RequestComplete(iDispatchStatus, KErrCancel); + User::WaitForRequest(stat); + WT_LOG(_L("Shut down worker %d exit=%d"), TUint(GetThreadId()), iWorkerThread.ExitType()); + } + } + diff -r 8df58d8c99e8 -r b3ffff030d5c core/src/worker_thread.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/worker_thread.h Thu Oct 28 16:54:54 2010 +0100 @@ -0,0 +1,132 @@ +// worker_thread.h +// +// Copyright (c) 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 +// + +#ifndef WORKER_THREAD_H +#define WORKER_THREAD_H + +#include + +class MThreadedTask + { +public: + virtual TThreadId GetThreadId() const=0; + virtual TInt ExecuteTask(TRequestStatus& aCompletionStatus)=0; + virtual void AbortTask()=0; // If you decide you don't want to call ExecuteTask + }; + +class MTaskRunner + { +public: + typedef void (*TThreadFunctionL)(TAny*); + virtual MThreadedTask* NewTaskInSeparateThreadL(const TDesC& aThreadName, TBool aSharedHeap, TThreadFunctionL aThreadFunction, TAny* aThreadContext)=0; + }; + +class CWorkerThread; +class CThreadDeathWatcher; + +class CThreadPool : public CActive, public MTaskRunner + { +public: + static CThreadPool* NewL(); + ~CThreadPool(); + void WorkerDied(CWorkerThread* aWorker); + void WorkerFinished(CWorkerThread* aWorker); + void CleanupAnyWorkersSharingAllocator(RAllocator* aAllocator); + TBool SharesThreadPoolAllocator(CWorkerThread* aWorker) const; + +public: // From MTaskRunner + virtual MThreadedTask* NewTaskInSeparateThreadL(const TDesC& aThreadName, TBool aSharedHeap, TThreadFunctionL aThreadFunction, TAny* aThreadContext); + +private: + CThreadPool(); + void ConstructL(); + static TInt TimerCallback(TAny* aSelf); + void PerformHouseKeeping(); + void RunL(); + void DoCancel(); + void SignalSelf(); + + void Lock(); + void LockLC(); + void SwitchToThreadPoolHeap(); + void RestoreHeap(); + void Unlock(); + static void DoUnlock(TAny* aLock); + +private: + RFastLock iLock; // Thread pool is shared between eg fshell main thread and any source threads, so needs locking around WorkerFinished and NewTaskInSeparateThreadL etc + RAllocator* iThreadPoolAllocator; // The thread pool can be modified from a thread that isn't using the main heap, so we need to track that and use User::SwitchAllocator as needed + RAllocator* iTempThreadAllocator; // Only used while lock is held + RPointerArray iThreads; + TInt iTaskCounter; + RThread iMainThread; + TInt iPendingCallbacks; + CPeriodic* iIdleTimer; + TInt iCountThreadsCreated; // This is for statistics gathering, not involved in the logic + RArray iPendingThreadLogons; // Not owned + RPointerArray iThreadDeathWatchers; + }; + +class CWorkerThread : public CBase, public MThreadedTask + { +public: + static CWorkerThread* NewLC(CThreadPool* aParentPool, RAllocator* aSharedAllocator); + // For safety these 2 need to be called with the thread pool lock held + TBool Busy() const; + void SetBusy(TBool aBusy); + + TBool UsingSharedAllocator() const; + RAllocator* SharedAllocator() const; + TInt Setup(TInt aTaskId, const TDesC& aThreadName, MTaskRunner::TThreadFunctionL aThreadFunction, TAny* aThreadContext); + void Shutdown(); + ~CWorkerThread(); + + TBool Running() const { return iWorkerThread.Handle() && iWorkerThread.ExitType() == EExitPending; } + +public: // From MThreadedTask + TThreadId GetThreadId() const; + TInt ExecuteTask(TRequestStatus& aCompletionStatus); + void AbortTask(); + +public: // For CThreadDeathWatcher to use + void SignalClientThatThreadHasDied(); + +private: + CWorkerThread(CThreadPool* aParentPool, RAllocator* aSharedAllocator); + void ConstructL(); + void ThreadRun(); + static TInt ThreadFn(TAny* aSelf); + void ThreadFnL(); + void CompleteParentRequest(TInt aError); + +private: + CThreadPool* iParentPool; + RThread iWorkerThread; + RAllocator* iSharedAllocator; + TRequestStatus* iDispatchStatus; + CActiveSchedulerWait iAsWait; // Use a CActiveSchedulerWait to protect ourselves from whatever aThreadFunction may try and do + CThreadDeathWatcher* iThreadDeathWatcher; + TBool iBusy; + + // Things specific to the task currently being executed + RThread iParentThread; // Worker needs this to signal completion to us + TName iName; + MTaskRunner::TThreadFunctionL iFn; + TAny* iContext; + TInt iTaskId; + TRequestStatus* iCompletionStatus; + + friend class CWorkerThreadDispatcher; + friend class CThreadDeathWatcher; + }; + +#endif diff -r 8df58d8c99e8 -r b3ffff030d5c documentation/change_history.pod --- a/documentation/change_history.pod Tue Oct 26 15:36:30 2010 +0100 +++ b/documentation/change_history.pod Thu Oct 28 16:54:54 2010 +0100 @@ -46,10 +46,33 @@ Updated chkdeps command so that it works with byte-pair compressed binaries (experimental). +=item * + +Added L command to redirect RDebug::Print()s to the console. + +=item * + +Added L command to allow hardware key presses to be easily simulated via a console. + +=item * + +Added L command for encoding to and decoding from Base64. =item * -Added L command to redirect RDebug::Print()s to the console. +Added C to btrace_parser.dll. Also changed the interface of C to use window group name patterns rather than process ids (to make it consistent with other parts of the API). + +=item * + +Fshell now reuses threads for built-in commands that execute in quick succession. The thread pool takes into account the requirements of the command when assigning a thread (eg whether it needs to share a heap with its parent command) and creates a new one if necessary. Excess threads are cleaned up after a short idle period (currently 1 second). + +=item * + +Added support for L reading from C (primarily to better support remote execution of scripts). + +=item * + +Fixed a bug in iocli.dll that could cause environment variable updates to be ignored. =back diff -r 8df58d8c99e8 -r b3ffff030d5c documentation/cif_syntax.pod --- a/documentation/cif_syntax.pod Tue Oct 26 15:36:30 2010 +0100 +++ b/documentation/cif_syntax.pod Thu Oct 28 16:54:54 2010 +0100 @@ -119,6 +119,10 @@ L, L +=head3 ==smoke-test + +Commands may optionally specify a snippet of code to test the basic functionality of the command. See the L documentation for more details. + =head2 The enum type The C type can be used for an option or argument that takes a limited number of named values, in much the same was as C/C++ enums are used. For an option or argument of type C you must specify the possible values that the enum can take using the C<==enum-value> keyword. These may optionally have a separate description per value. If any value has an individual description, they all must. diff -r 8df58d8c99e8 -r b3ffff030d5c libraries/btrace_parser/bwins/btrace_parseru.def --- a/libraries/btrace_parser/bwins/btrace_parseru.def Tue Oct 26 15:36:30 2010 +0100 +++ b/libraries/btrace_parser/bwins/btrace_parseru.def Thu Oct 28 16:54:54 2010 +0100 @@ -27,7 +27,7 @@ ??0TBtraceIdBase@@IAE@XZ @ 26 NONAME ; TBtraceIdBase::TBtraceIdBase(void) ??1CBtraceDomainEvent@@UAE@XZ @ 27 NONAME ; CBtraceDomainEvent::~CBtraceDomainEvent(void) ?NewL@CBtraceGeneric@@SAPAV1@AAVCBtraceReader@@@Z @ 28 NONAME ; class CBtraceGeneric * CBtraceGeneric::NewL(class CBtraceReader &) - ?NewL@CBtraceAppResponse@@SAPAV1@AAVCBtraceReader@@@Z @ 29 NONAME ; class CBtraceAppResponse * CBtraceAppResponse::NewL(class CBtraceReader &) + ?NewL@CBtraceAppResponse@@SAPAV1@AAVCBtraceReader@@AAVCBtraceContext@@@Z @ 29 NONAME ; class CBtraceAppResponse * CBtraceAppResponse::NewL(class CBtraceReader &, class CBtraceContext &) ?FlushL@CBtraceReader@@QAEXXZ @ 30 NONAME ; void CBtraceReader::FlushL(void) ?FindThreadsL@CBtraceContext@@QBEXABVTDesC16@@AAV?$RArray@VTBtraceThreadId@@@@@Z @ 31 NONAME ; void CBtraceContext::FindThreadsL(class TDesC16 const &, class RArray &) const ??1CBtraceTextOnScreen@@UAE@XZ @ 32 NONAME ; CBtraceTextOnScreen::~CBtraceTextOnScreen(void) @@ -100,7 +100,7 @@ ?DecRef@CRefCountedObject@@QAEXXZ @ 99 NONAME ; void CRefCountedObject::DecRef(void) ??1CBtraceAppResponse@@UAE@XZ @ 100 NONAME ; CBtraceAppResponse::~CBtraceAppResponse(void) ?CurrentTickCount@CBtraceReader@@QBEABVTBtraceTickCount@@XZ @ 101 NONAME ; class TBtraceTickCount const & CBtraceReader::CurrentTickCount(void) const - ?NotifyAppResponseL@CBtraceAppResponse@@QAEXAAVMBtraceAppResponseObserver@@ABVTProcessId@@W4TBtraceNotificationPersistence@@@Z @ 102 NONAME ; void CBtraceAppResponse::NotifyAppResponseL(class MBtraceAppResponseObserver &, class TProcessId const &, enum TBtraceNotificationPersistence) + ?NotifyAppResponseL@CBtraceAppResponse@@QAEXAAVMBtraceAppResponseObserver@@ABVTDesC16@@W4TBtraceNotificationPersistence@@@Z @ 102 NONAME ; void CBtraceAppResponse::NotifyAppResponseL(class MBtraceAppResponseObserver &, class TDesC16 const &, enum TBtraceNotificationPersistence) ?NotifyContextSwitchL@CBtraceCpuUsage@@QAEXABVTBtraceThreadId@@AAVMBtraceCpuUsageObserver@@@Z @ 103 NONAME ; void CBtraceCpuUsage::NotifyContextSwitchL(class TBtraceThreadId const &, class MBtraceCpuUsageObserver &) ??PTBtraceTickCount@@QBEHABV0@@Z @ 104 NONAME ; int TBtraceTickCount::operator>=(class TBtraceTickCount const &) const ?CancelNotifyUnclassifiedData@CBtraceKeyPress@@QAEXAAVMBtraceKeyPressObserver@@@Z @ 105 NONAME ; void CBtraceKeyPress::CancelNotifyUnclassifiedData(class MBtraceKeyPressObserver &) @@ -112,7 +112,7 @@ ?NewL@CBtraceTextOnScreen@@SAPAV1@AAVCBtraceReader@@@Z @ 111 NONAME ; class CBtraceTextOnScreen * CBtraceTextOnScreen::NewL(class CBtraceReader &) ??0TBtraceWindowGroupId@@QAE@ABV0@@Z @ 112 NONAME ; TBtraceWindowGroupId::TBtraceWindowGroupId(class TBtraceWindowGroupId const &) ?NotifyCpuUsageL@CBtraceCpuUsage@@QAEXKVTTimeIntervalMicroSeconds32@@AAVMBtraceCpuUsageObserver@@@Z @ 113 NONAME ; void CBtraceCpuUsage::NotifyCpuUsageL(unsigned long, class TTimeIntervalMicroSeconds32, class MBtraceCpuUsageObserver &) - ?NotifyAppResponseL@CBtraceAppResponse@@QAEXAAVMBtraceAppResponseObserver@@ABVTProcessId@@@Z @ 114 NONAME ; void CBtraceAppResponse::NotifyAppResponseL(class MBtraceAppResponseObserver &, class TProcessId const &) + ?NotifyAppResponseL@CBtraceAppResponse@@QAEXAAVMBtraceAppResponseObserver@@ABVTDesC16@@@Z @ 114 NONAME ; void CBtraceAppResponse::NotifyAppResponseL(class MBtraceAppResponseObserver &, class TDesC16 const &) ?ProcessName@CBtraceContext@@QBEABVTDesC16@@ABVTBtraceProcessId@@@Z @ 115 NONAME ; class TDesC16 const & CBtraceContext::ProcessName(class TBtraceProcessId const &) const ?EnableCategoryL@CBtraceReader@@QAEXI@Z @ 116 NONAME ; void CBtraceReader::EnableCategoryL(unsigned int) ?NotifyGenericEventL@CBtraceGeneric@@QAEXAAVMBtraceGenericObserver@@@Z @ 117 NONAME ; void CBtraceGeneric::NotifyGenericEventL(class MBtraceGenericObserver &) @@ -152,4 +152,9 @@ ?SetMultipartReassemblyL@CBtraceReader@@QAEXH@Z @ 151 NONAME ; void CBtraceReader::SetMultipartReassemblyL(int) ?MicroSecondsToNanoTicks@TBtraceUtils@@SAKVTTimeIntervalMicroSeconds32@@@Z @ 152 NONAME ; unsigned long TBtraceUtils::MicroSecondsToNanoTicks(class TTimeIntervalMicroSeconds32) ?Start@CBtraceReader@@QAEXABVTBtraceTickCount@@VTTimeIntervalMicroSeconds32@@@Z @ 153 NONAME ; void CBtraceReader::Start(class TBtraceTickCount const &, class TTimeIntervalMicroSeconds32) + ??1CBtraceAppStart@@UAE@XZ @ 154 NONAME ; CBtraceAppStart::~CBtraceAppStart(void) + ?CancelNotifyAppStart@CBtraceAppStart@@QAEXAAVMBtraceAppStartObserver@@@Z @ 155 NONAME ; void CBtraceAppStart::CancelNotifyAppStart(class MBtraceAppStartObserver &) + ?NewL@CBtraceAppStart@@SAPAV1@AAVCBtraceReader@@AAVCBtraceContext@@@Z @ 156 NONAME ; class CBtraceAppStart * CBtraceAppStart::NewL(class CBtraceReader &, class CBtraceContext &) + ?NotifyAppStartL@CBtraceAppStart@@QAEXAAVMBtraceAppStartObserver@@ABVTDesC16@@@Z @ 157 NONAME ; void CBtraceAppStart::NotifyAppStartL(class MBtraceAppStartObserver &, class TDesC16 const &) + ?NotifyAppStartL@CBtraceAppStart@@QAEXAAVMBtraceAppStartObserver@@ABVTDesC16@@W4TBtraceNotificationPersistence@@@Z @ 158 NONAME ; void CBtraceAppStart::NotifyAppStartL(class MBtraceAppStartObserver &, class TDesC16 const &, enum TBtraceNotificationPersistence) diff -r 8df58d8c99e8 -r b3ffff030d5c libraries/btrace_parser/eabi/btrace_parseru.def --- a/libraries/btrace_parser/eabi/btrace_parseru.def Tue Oct 26 15:36:30 2010 +0100 +++ b/libraries/btrace_parser/eabi/btrace_parseru.def Thu Oct 28 16:54:54 2010 +0100 @@ -109,10 +109,10 @@ _ZN16TBtraceTickCountC2Ev @ 108 NONAME _ZN17CRefCountedObject6DecRefEv @ 109 NONAME _ZN17CRefCountedObject6IncRefEv @ 110 NONAME - _ZN18CBtraceAppResponse18NotifyAppResponseLER26MBtraceAppResponseObserverRK10TProcessId @ 111 NONAME - _ZN18CBtraceAppResponse18NotifyAppResponseLER26MBtraceAppResponseObserverRK10TProcessId30TBtraceNotificationPersistence @ 112 NONAME + _ZN18CBtraceAppResponse18NotifyAppResponseLER26MBtraceAppResponseObserverRK7TDesC16 @ 111 NONAME + _ZN18CBtraceAppResponse18NotifyAppResponseLER26MBtraceAppResponseObserverRK7TDesC1630TBtraceNotificationPersistence @ 112 NONAME _ZN18CBtraceAppResponse23CancelNotifyAppResponseER26MBtraceAppResponseObserver @ 113 NONAME - _ZN18CBtraceAppResponse4NewLER13CBtraceReader @ 114 NONAME + _ZN18CBtraceAppResponse4NewLER13CBtraceReaderR14CBtraceContext @ 114 NONAME _ZN18CBtraceAppResponseD0Ev @ 115 NONAME _ZN18CBtraceAppResponseD1Ev @ 116 NONAME _ZN18CBtraceAppResponseD2Ev @ 117 NONAME @@ -189,4 +189,11 @@ _ZTI22MBtraceContextObserver @ 188 NONAME _ZTV22MBtraceContextObserver @ 189 NONAME _ZN13CBtraceReader5StartERK16TBtraceTickCount27TTimeIntervalMicroSeconds32 @ 190 NONAME + _ZN15CBtraceAppStart15NotifyAppStartLER23MBtraceAppStartObserverRK7TDesC16 @ 191 NONAME + _ZN15CBtraceAppStart15NotifyAppStartLER23MBtraceAppStartObserverRK7TDesC1630TBtraceNotificationPersistence @ 192 NONAME + _ZN15CBtraceAppStart20CancelNotifyAppStartER23MBtraceAppStartObserver @ 193 NONAME + _ZN15CBtraceAppStart4NewLER13CBtraceReaderR14CBtraceContext @ 194 NONAME + _ZN15CBtraceAppStartD0Ev @ 195 NONAME + _ZN15CBtraceAppStartD1Ev @ 196 NONAME + _ZN15CBtraceAppStartD2Ev @ 197 NONAME diff -r 8df58d8c99e8 -r b3ffff030d5c libraries/btrace_parser/inc/btrace_parser.h --- a/libraries/btrace_parser/inc/btrace_parser.h Tue Oct 26 15:36:30 2010 +0100 +++ b/libraries/btrace_parser/inc/btrace_parser.h Thu Oct 28 16:54:54 2010 +0100 @@ -770,6 +770,43 @@ }; +class MBtraceAppStartObserver + { +public: + virtual void HandleAppStartL(const TBtraceTickCount& aTickCount) = 0; + }; + +NONSHARABLE_CLASS(CBtraceAppStart) : public CRefCountedObject, public MBtraceObserver + { +public: + IMPORT_C static CBtraceAppStart* NewL(CBtraceReader& aReader, CBtraceContext& aContext); + IMPORT_C ~CBtraceAppStart(); + IMPORT_C void NotifyAppStartL(MBtraceAppStartObserver& aObserver, const TDesC& aWindowGroupNamePattern); + IMPORT_C void NotifyAppStartL(MBtraceAppStartObserver& aObserver, const TDesC& aWindowGroupNamePattern, TBtraceNotificationPersistence aPersistence); + IMPORT_C void CancelNotifyAppStart(MBtraceAppStartObserver& aObserver); +private: + CBtraceAppStart(CBtraceReader& aReader, CBtraceContext& aContext); + void ConstructL(); + void SeenAppStartL(const TBtraceTickCount& aTickCount, TInt aWindowGroupId); +private: // From MBtraceObserver. + virtual void HandleBtraceFrameL(const TBtraceFrame& aFrame); +private: + class TAppStartNotif + { + public: + TAppStartNotif(MBtraceAppStartObserver& aObserver, const TDesC& aWindowGroupNamePattern, TBtraceNotificationPersistence aPersistence); + public: + MBtraceAppStartObserver& iObserver; + TPtrC iWindowGroupNamePattern; + TBtraceNotificationPersistence iPersistence; + }; +private: + CBtraceReader& iReader; + CBtraceContext& iContext; + RArray iNotifs; + }; + + class MBtraceAppResponseObserver { public: @@ -779,29 +816,30 @@ NONSHARABLE_CLASS(CBtraceAppResponse) : public CRefCountedObject, public MBtraceObserver { public: - IMPORT_C static CBtraceAppResponse* NewL(CBtraceReader& aReader); + IMPORT_C static CBtraceAppResponse* NewL(CBtraceReader& aReader, CBtraceContext& aContext); IMPORT_C ~CBtraceAppResponse(); - IMPORT_C void NotifyAppResponseL(MBtraceAppResponseObserver& aObserver, const TProcessId& aProcessId); - IMPORT_C void NotifyAppResponseL(MBtraceAppResponseObserver& aObserver, const TProcessId& aProcessId, TBtraceNotificationPersistence aPersistence); + IMPORT_C void NotifyAppResponseL(MBtraceAppResponseObserver& aObserver, const TDesC& aWindowGroupNamePattern); + IMPORT_C void NotifyAppResponseL(MBtraceAppResponseObserver& aObserver, const TDesC& aWindowGroupNamePattern, TBtraceNotificationPersistence aPersistence); IMPORT_C void CancelNotifyAppResponse(MBtraceAppResponseObserver& aObserver); private: - CBtraceAppResponse(CBtraceReader& aReader); + CBtraceAppResponse(CBtraceReader& aReader, CBtraceContext& aContext); void ConstructL(); - void SeenAppResponseL(const TBtraceTickCount& aTickCount, const TProcessId& aProcessId); + void SeenAppResponseL(const TBtraceTickCount& aTickCount, TInt aWindowGroupId); private: // From MBtraceObserver. virtual void HandleBtraceFrameL(const TBtraceFrame& aFrame); private: class TAppResponseNotif { public: - TAppResponseNotif(MBtraceAppResponseObserver& aObserver, const TProcessId& aProcessId, TBtraceNotificationPersistence aPersistence); + TAppResponseNotif(MBtraceAppResponseObserver& aObserver, const TDesC& aWindowGroupNamePattern, TBtraceNotificationPersistence aPersistence); public: MBtraceAppResponseObserver& iObserver; - TProcessId iProcessId; + TPtrC iWindowGroupNamePattern; TBtraceNotificationPersistence iPersistence; }; private: CBtraceReader& iReader; + CBtraceContext& iContext; RArray iNotifs; }; diff -r 8df58d8c99e8 -r b3ffff030d5c libraries/btrace_parser/inc/btrace_parser_defs.h --- a/libraries/btrace_parser/inc/btrace_parser_defs.h Tue Oct 26 15:36:30 2010 +0100 +++ b/libraries/btrace_parser/inc/btrace_parser_defs.h Thu Oct 28 16:54:54 2010 +0100 @@ -58,8 +58,9 @@ EAmTraceEventEvCaptureKeyPress = 2, EAmTraceEventEvCapturePointer = 3, EAmTraceEventEvCaptureUnclassified = 4, - EAmTraceEventEvCaptureSystemAppResponse = 5, + EAmTraceEventEvCaptureAppResponse = 5, EAmTraceEventEvCaptureRawScan = 6, + EAmTraceEventEvCaptureAppStart = 7, }; diff -r 8df58d8c99e8 -r b3ffff030d5c libraries/btrace_parser/src/btrace_appresponse.cpp --- a/libraries/btrace_parser/src/btrace_appresponse.cpp Tue Oct 26 15:36:30 2010 +0100 +++ b/libraries/btrace_parser/src/btrace_appresponse.cpp Thu Oct 28 16:54:54 2010 +0100 @@ -18,17 +18,17 @@ // CBtraceAppResponse // -EXPORT_C CBtraceAppResponse* CBtraceAppResponse::NewL(CBtraceReader& aReader) +EXPORT_C CBtraceAppResponse* CBtraceAppResponse::NewL(CBtraceReader& aReader, CBtraceContext& aContext) { - CBtraceAppResponse* self = new (ELeave) CBtraceAppResponse(aReader); + CBtraceAppResponse* self = new (ELeave) CBtraceAppResponse(aReader, aContext); CleanupStack::PushL(self); self->ConstructL(); CleanupStack::Pop(self); return self; } -CBtraceAppResponse::CBtraceAppResponse(CBtraceReader& aReader) - : iReader(aReader) +CBtraceAppResponse::CBtraceAppResponse(CBtraceReader& aReader, CBtraceContext& aContext) + : iReader(aReader), iContext(aContext) { } @@ -53,14 +53,13 @@ { const TUint32* data = reinterpret_cast(aFrame.iData.Ptr()); const TAmTraceEventEvCapture event = static_cast(*data++); - const TUint32 processIdLowWord = *data++; - const TUint32 processIdHighWord = *data++; switch (event) { - case EAmTraceEventEvCaptureSystemAppResponse: + case EAmTraceEventEvCaptureAppResponse: { - SeenAppResponseL(aFrame.iTickCount, MAKE_TUINT64(processIdHighWord, processIdLowWord)); + const TInt32 wgId = *data++; + SeenAppResponseL(aFrame.iTickCount, wgId); } break; @@ -77,32 +76,36 @@ }; } -void CBtraceAppResponse::SeenAppResponseL(const TBtraceTickCount& aTickCount, const TProcessId& aProcessId) +void CBtraceAppResponse::SeenAppResponseL(const TBtraceTickCount& aTickCount, TInt aWindowGroupId) { - TInt ii = iNotifs.Count(); - while (--ii >= 0) + const TBtraceWindowGroupId* btraceWgId = iContext.FindWindowGroup(aWindowGroupId); + if (btraceWgId) { - TAppResponseNotif& nt = iNotifs[ii]; - if (nt.iProcessId == aProcessId) + TInt ii = iNotifs.Count(); + while (--ii >= 0) { - MBtraceAppResponseObserver& observer = nt.iObserver; - if (nt.iPersistence == ENotificationOneShot) + TAppResponseNotif& nt = iNotifs[ii]; + if (iContext.WindowGroupName(*btraceWgId).MatchF(nt.iWindowGroupNamePattern) != KErrNotFound) { - iNotifs.Remove(ii); + MBtraceAppResponseObserver& observer = nt.iObserver; + if (nt.iPersistence == ENotificationOneShot) + { + iNotifs.Remove(ii); + } + observer.HandleAppResponseSeenL(aTickCount); } - observer.HandleAppResponseSeenL(aTickCount); } - } + } } -EXPORT_C void CBtraceAppResponse::NotifyAppResponseL(MBtraceAppResponseObserver& aObserver, const TProcessId& aProcessId) +EXPORT_C void CBtraceAppResponse::NotifyAppResponseL(MBtraceAppResponseObserver& aObserver, const TDesC& aWindowGroupNamePattern) { - NotifyAppResponseL(aObserver, aProcessId, ENotificationOneShot); + NotifyAppResponseL(aObserver, aWindowGroupNamePattern, ENotificationOneShot); } -EXPORT_C void CBtraceAppResponse::NotifyAppResponseL(MBtraceAppResponseObserver& aObserver, const TProcessId& aProcessId, TBtraceNotificationPersistence aPersistence) +EXPORT_C void CBtraceAppResponse::NotifyAppResponseL(MBtraceAppResponseObserver& aObserver, const TDesC& aWindowGroupNamePattern, TBtraceNotificationPersistence aPersistence) { - TAppResponseNotif notify(aObserver, aProcessId, aPersistence); + TAppResponseNotif notify(aObserver, aWindowGroupNamePattern, aPersistence); User::LeaveIfError(iNotifs.Append(notify)); } @@ -122,7 +125,7 @@ // CBtraceAppResponse::TAppResponseNotif // -CBtraceAppResponse::TAppResponseNotif::TAppResponseNotif(MBtraceAppResponseObserver& aObserver, const TProcessId& aProcessId, TBtraceNotificationPersistence aPersistence) - : iObserver(aObserver), iProcessId(aProcessId), iPersistence(aPersistence) +CBtraceAppResponse::TAppResponseNotif::TAppResponseNotif(MBtraceAppResponseObserver& aObserver, const TDesC& aWindowGroupNamePattern, TBtraceNotificationPersistence aPersistence) + : iObserver(aObserver), iWindowGroupNamePattern(aWindowGroupNamePattern), iPersistence(aPersistence) { } diff -r 8df58d8c99e8 -r b3ffff030d5c libraries/btrace_parser/src/btrace_appstart.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libraries/btrace_parser/src/btrace_appstart.cpp Thu Oct 28 16:54:54 2010 +0100 @@ -0,0 +1,131 @@ +// btrace_appstart.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 "btrace_parser.h" +#include + + +// +// CBtraceAppStart +// + +EXPORT_C CBtraceAppStart* CBtraceAppStart::NewL(CBtraceReader& aReader, CBtraceContext& aContext) + { + CBtraceAppStart* self = new (ELeave) CBtraceAppStart(aReader, aContext); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +CBtraceAppStart::CBtraceAppStart(CBtraceReader& aReader, CBtraceContext& aContext) + : iReader(aReader), iContext(aContext) + { + } + +EXPORT_C CBtraceAppStart::~CBtraceAppStart() + { + iReader.RemoveObserver(KAmTraceCategory, *this); + iNotifs.Close(); + } + +void CBtraceAppStart::ConstructL() + { + iReader.AddObserverL(KAmTraceCategory, *this); + } + +void CBtraceAppStart::HandleBtraceFrameL(const TBtraceFrame& aFrame) + { + if (aFrame.iCategory != KAmTraceCategory) return; + + switch (aFrame.iSubCategory) + { + case EAmTraceSubCategoryEvCapture: + { + const TUint32* data = reinterpret_cast(aFrame.iData.Ptr()); + const TAmTraceEventEvCapture event = static_cast(*data++); + + switch (event) + { + case EAmTraceEventEvCaptureAppStart: + { + const TInt32 wgId = *data++; + SeenAppStartL(aFrame.iTickCount, wgId); + } + break; + + default: + // ignore the event + break; + }; + } + break; + + default: + // ignore anything we don't know about. + break; + }; + } + +void CBtraceAppStart::SeenAppStartL(const TBtraceTickCount& aTickCount, TInt aWindowGroupId) + { + const TBtraceWindowGroupId* btraceWgId = iContext.FindWindowGroup(aWindowGroupId); + if (btraceWgId) + { + TInt ii = iNotifs.Count(); + while (--ii >= 0) + { + TAppStartNotif& nt = iNotifs[ii]; + if (iContext.WindowGroupName(*btraceWgId).MatchF(nt.iWindowGroupNamePattern) != KErrNotFound) + { + MBtraceAppStartObserver& observer = nt.iObserver; + if (nt.iPersistence == ENotificationOneShot) + { + iNotifs.Remove(ii); + } + observer.HandleAppStartL(aTickCount); + } + } + } + } + +EXPORT_C void CBtraceAppStart::NotifyAppStartL(MBtraceAppStartObserver& aObserver, const TDesC& aWindowGroupNamePattern) + { + NotifyAppStartL(aObserver, aWindowGroupNamePattern, ENotificationOneShot); + } + +EXPORT_C void CBtraceAppStart::NotifyAppStartL(MBtraceAppStartObserver& aObserver, const TDesC& aWindowGroupNamePattern, TBtraceNotificationPersistence aPersistence) + { + TAppStartNotif notify(aObserver, aWindowGroupNamePattern, aPersistence); + User::LeaveIfError(iNotifs.Append(notify)); + } + +EXPORT_C void CBtraceAppStart::CancelNotifyAppStart(MBtraceAppStartObserver& aObserver) + { + for (TInt i = (iNotifs.Count() - 1); i >= 0; --i) + { + if (&iNotifs[i].iObserver == &aObserver) + { + iNotifs.Remove(i); + } + } + } + + +// +// CBtraceAppStart::TAppStartNotif +// + +CBtraceAppStart::TAppStartNotif::TAppStartNotif(MBtraceAppStartObserver& aObserver, const TDesC& aWindowGroupNamePattern, TBtraceNotificationPersistence aPersistence) + : iObserver(aObserver), iWindowGroupNamePattern(aWindowGroupNamePattern), iPersistence(aPersistence) + { + } diff -r 8df58d8c99e8 -r b3ffff030d5c libraries/btrace_parser/src/btrace_parser.mmp --- a/libraries/btrace_parser/src/btrace_parser.mmp Tue Oct 26 15:36:30 2010 +0100 +++ b/libraries/btrace_parser/src/btrace_parser.mmp Thu Oct 28 16:54:54 2010 +0100 @@ -29,6 +29,7 @@ source btrace_textonscreen.cpp source btrace_generic.cpp source btrace_appresponse.cpp +source btrace_appstart.cpp source btrace_screenupdate.cpp source btrace_pubsub.cpp source btrace_domainevent.cpp diff -r 8df58d8c99e8 -r b3ffff030d5c libraries/iosrv/client/env.cpp --- a/libraries/iosrv/client/env.cpp Tue Oct 26 15:36:30 2010 +0100 +++ b/libraries/iosrv/client/env.cpp Thu Oct 28 16:54:54 2010 +0100 @@ -141,33 +141,37 @@ WaitLC(); HBufC** valPtr = iVars.Find(aKey); - HBufC* currentValue = NULL; - if (valPtr) currentValue = *valPtr; if (valPtr == NULL && iParentEnv) { // If we don't have it, and we have a parent env, we should pass the request through to it. iParentEnv->SetL(aKey, aValue); } + else if (valPtr) + { + // The key is present in the hash. + HBufC* currentValue = *valPtr; + if (currentValue && (currentValue->Des().MaxLength() >= aValue.Length())) + { + // If the existing HBufC is big enough, simply copy. + // Note, currentValue will be NULL if this is the first time a 'local' variable is being set. + currentValue->Des().Copy(aValue); + } + else + { + // Otherwise allocate a new HBufC. + *valPtr = aValue.AllocL(); + delete currentValue; + } + } else { - if (currentValue) - { - // If we already have a value in the hash, just update it if possible - TPtr ptr = currentValue->Des(); - if (ptr.MaxLength() >= aValue.Length()) - { - ptr.Copy(aValue); - CleanupStack::PopAndDestroy(); // Release lock - return; - } - } + // New key. + HBufC* newVal = aValue.AllocLC(); + iVars.InsertL(aKey, newVal); + CleanupStack::Pop(newVal); } - HBufC* newVal = aValue.AllocLC(); - iVars.InsertL(aKey, newVal); - delete currentValue; - CleanupStack::Pop(newVal); CleanupStack::PopAndDestroy(); // Release lock } diff -r 8df58d8c99e8 -r b3ffff030d5c libraries/iosrv/server/file.cpp --- a/libraries/iosrv/server/file.cpp Tue Oct 26 15:36:30 2010 +0100 +++ b/libraries/iosrv/server/file.cpp Thu Oct 28 16:54:54 2010 +0100 @@ -93,7 +93,7 @@ { case RIoFile::ERead: { - User::LeaveIfError(iFile.Open(aFs, aName, EFileRead)); + User::LeaveIfError(iFile.Open(aFs, aName, EFileRead | EFileShareReadersOnly)); break; } case RIoFile::EOverwrite: