# HG changeset patch # User Tom Sutcliffe # Date 1284751470 -3600 # Node ID 3c3961c1ae26574cb0e6345868a47cfdae18b401 # Parent 264162c6ed9178e746652619819f92c24906976a Fixed threadpool hang and added lots of smoketests. * Fixed bug in threadpool logic when calling CleanupAnyWorkersSharingAllocator - this was deleting the worker's thread death notifier in the context of a worker thread (which is only allowed from the context of the main thread). * Added lots more smoketests * Added --overwrite option to fzip (previously unzipping would always overwrite) diff -r 264162c6ed91 -r 3c3961c1ae26 commands/focus/focus.cif --- a/commands/focus/focus.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/commands/focus/focus.cif Fri Sep 17 20:24:30 2010 +0100 @@ -44,3 +44,6 @@ Copyright (c) 2008-2010 Accenture. All rights reserved. +==smoke-test + +focus $Quiet diff -r 264162c6ed91 -r 3c3961c1ae26 commands/fzip/fzip.cif --- a/commands/fzip/fzip.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/commands/fzip/fzip.cif Fri Sep 17 20:24:30 2010 +0100 @@ -20,9 +20,9 @@ Generates compressed archives of files or extracts files from a compressed archive. Both 'zip' and 'gzip' file formats are support ('zip' is used by default). -==argument filename archive optional +==argument filename zipfile optional -The zip archive to create or extract. +The zip archive to create or extract. If the zipfile argument is not specified when creating a zip, the first C argument's name is used with a .zip or .gz extension appended. ==option bool v verbose @@ -30,11 +30,11 @@ ==option bool u unzip -Extract files from the specified archive. +Extract files from the specified zipfile. ==option filename d directory -The directory to extract files into. Must be used in conjunction with '--unzip'. +The directory to extract files into. Must be used in conjunction with C<--unzip>. If not specified, the current working directory is used. ==option bool r recurse @@ -42,7 +42,7 @@ ==option filename f file multiple -A file or directory to archive. Only applicable when creating a new archive. If a directory is specified then it and any files contained immediately within that directory are archived. Use --recurse to archive all sub-directories and files within the directory. +A file or directory to add to the zipfile. Only applicable when creating a new archive. If a directory is specified then it and any files contained immediately within that directory are archived. Use --recurse to archive all sub-directories and files within the directory. ==option enum t compression-type @@ -54,7 +54,37 @@ GNU Zip format. Note, this format can only handle a single file. +==option bool o overwrite + +By default fzip will exit with an error if a file it is creating already exists on disk. Use this flag to silently overwrite instead. + ==copyright 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 264162c6ed91 -r 3c3961c1ae26 commands/fzip/fzip.cpp --- a/commands/fzip/fzip.cpp Wed Sep 15 00:45:50 2010 +0100 +++ b/commands/fzip/fzip.cpp Fri Sep 17 20:24:30 2010 +0100 @@ -15,6 +15,7 @@ #include "fzip.h" _LIT(KGzExtension, ".gz"); +_LIT(KZipExtension, ".zip"); CCommandBase* CCmdZip::NewLC() { @@ -26,8 +27,7 @@ CCmdZip::~CCmdZip() { - if (iFileToZip.Count() > 0) - iFileToZip.Close(); + iFileToZip.Close(); } CCmdZip::CCmdZip() : CCommandBase(CCommandBase::EManualComplete) @@ -55,11 +55,11 @@ // command-line sanity checks if (iFileToZip.Count() > 0) { - PrintWarning(_L("Ignoring \'-f\' file option.")); + PrintWarning(_L("--file option is not relevant when unzipping.")); } if (iRecurse) { - PrintWarning(_L("Ignoring \'-r\' recurse option.")); + PrintWarning(_L("--recurse option is not relevant when unzipping.")); } } ExpandArchiveL(); @@ -71,21 +71,14 @@ // command-line sanity checks if (iUnzipPath.Length() > 0) { - PrintWarning(_L("Ignoring '-d' directory option.")); + PrintWarning(_L("--directory option is not relevant when zipping.")); } } if (iFileToZip.Count() == 0) { - PrintError(KErrArgument, _L("Use '-f' to specify source files.")); - User::Leave(KErrArgument); + LeaveIfErr(KErrArgument, _L("Specify some files to zip up using --file option.")); } - TRAPD(err, CreateArchiveL()); - if (err != KErrNone) - { - PrintError(err, _L("Couldn't create archive")); - Fs().Delete(iArchive); // ignore error - User::Leave(err); - } + TRAPL(CreateArchiveL(), _L("Couldn't create %S"), &iArchive); } if (iVerbose) { @@ -96,7 +89,7 @@ void CCmdZip::ArgumentsL(RCommandArgumentList& aArguments) { - _LIT(KArg1, "archive"); + _LIT(KArg1, "zipfile"); aArguments.AppendFileNameL(iArchive, KArg1); } @@ -119,6 +112,9 @@ _LIT(KOptCompressionType, "compression-type"); aOptions.AppendEnumL((TInt&)iCompressionType, KOptCompressionType); + + _LIT(KOptOverwrite, "overwrite"); + aOptions.AppendBoolL(iOverwrite, KOptOverwrite); } @@ -132,6 +128,24 @@ // void CCmdZip::CreateArchiveL() { + if (iArchive.Length() == 0) + { + iArchive = iFileToZip[0]; + iArchive.Append(iCompressionType == EGZip ? KGzExtension() : KZipExtension()); + } + + if (iArchive.Exists(FsL())) + { + if (iOverwrite) + { + FsL().Delete(iArchive); + } + else + { + LeaveIfErr(KErrAlreadyExists, _L("File %S already exists on disk. Use --overwrite or specify a different file"), &iArchive); + } + } + if (iCompressionType == EGZip) { CreateGzArchiveL(); @@ -158,23 +172,17 @@ LeaveIfErr(KErrArgument, _L("GNU Zip format can only handle a single file")); } - if (iArchive.Length() == 0) - { - iArchive = iFileToZip[0]; - iArchive.Append(KGzExtension); - } - - RFile input; if (iVerbose) { Printf(_L("Creating '%S'\r\n"), &iArchive); } // open the input file - User::LeaveIfError(input.Open(Fs(), iFileToZip[0], EFileStream | EFileRead | EFileShareAny)); + RFile input; + User::LeaveIfError(input.Open(FsL(), iFileToZip[0], EFileStream | EFileRead | EFileShareAny)); CleanupClosePushL(input); - CEZFileToGZip* zip = CEZFileToGZip::NewLC(Fs(), iArchive, input); + CEZFileToGZip* zip = CEZFileToGZip::NewLC(FsL(), iArchive, input); while (zip->DeflateL()) { // do nothing @@ -297,7 +305,15 @@ { LeaveIfErr(err, _L("Couldn't create path '%S'"), &dest); } - User::LeaveIfError(newFile.Replace(Fs(), dest, EFileStream | EFileRead | EFileShareAny)); + if (iOverwrite) + { + err = newFile.Replace(FsL(), dest, EFileStream | EFileRead | EFileWrite | EFileShareAny); + } + else + { + err = newFile.Create(FsL(), dest, EFileStream | EFileRead | EFileWrite | EFileShareAny); + } + LeaveIfErr(err, _L("Couldn't create file %S"), &dest); CleanupClosePushL(newFile); // inflate the compressed file @@ -362,7 +378,15 @@ aZip.GetInputStreamL(&aMember, readStream); CleanupStack::PushL(readStream); - LeaveIfErr(newFile.Replace(Fs(), dest, EFileShareExclusive), _L("Couldn't create file %S"), &dest); + if (iOverwrite) + { + err = newFile.Replace(Fs(), dest, EFileShareExclusive); + } + else + { + err = newFile.Create(Fs(), dest, EFileShareExclusive); + } + LeaveIfErr(err, _L("Couldn't create file %S"), &dest); CleanupClosePushL(newFile); if (iVerbose) { diff -r 264162c6ed91 -r 3c3961c1ae26 commands/fzip/fzip.h --- a/commands/fzip/fzip.h Wed Sep 15 00:45:50 2010 +0100 +++ b/commands/fzip/fzip.h Fri Sep 17 20:24:30 2010 +0100 @@ -56,6 +56,7 @@ TFileName2 iArchive; TFileName2 iUnzipPath; RArray iFileToZip; + TBool iOverwrite; }; diff -r 264162c6ed91 -r 3c3961c1ae26 commands/grabscreen/grabscreen.cif --- a/commands/grabscreen/grabscreen.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/commands/grabscreen/grabscreen.cif Fri Sep 17 20:24:30 2010 +0100 @@ -58,3 +58,6 @@ Copyright (c) 2008-2010 Accenture. All rights reserved. +==smoke-test + +grabscreen > /dev/null diff -r 264162c6ed91 -r 3c3961c1ae26 commands/iap/iap.cif --- a/commands/iap/iap.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/commands/iap/iap.cif Fri Sep 17 20:24:30 2010 +0100 @@ -20,8 +20,10 @@ Add a dummy IAP for use with WinSockPrt (an ESock protocol module that replaces Symbian's TCP/IP stack with a shim over Microsoft's WinSock API). - ==copyright Copyright (c) 2008-2010 Accenture. All rights reserved. +==smoke-test + +iap $Quiet diff -r 264162c6ed91 -r 3c3961c1ae26 commands/listapps/listapps.cif --- a/commands/listapps/listapps.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/commands/listapps/listapps.cif Fri Sep 17 20:24:30 2010 +0100 @@ -36,9 +36,10 @@ Display the details of the application with the specified window group identifier. If not specified, details of all currently running applications are displayed. - - ==copyright Copyright (c) 2007-2010 Accenture. All rights reserved. +==smoke-test + +listapps $Quiet diff -r 264162c6ed91 -r 3c3961c1ae26 commands/localdrive/localdrive.cif --- a/commands/localdrive/localdrive.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/commands/localdrive/localdrive.cif Fri Sep 17 20:24:30 2010 +0100 @@ -50,3 +50,6 @@ Copyright (c) 2010 Accenture. All rights reserved. +==smoke-test + +localdrive $Silent # Localdrive can print errors for drives that are ejected, etc diff -r 264162c6ed91 -r 3c3961c1ae26 commands/localdrive/localdrive.cpp --- a/commands/localdrive/localdrive.cpp Wed Sep 15 00:45:50 2010 +0100 +++ b/commands/localdrive/localdrive.cpp Fri Sep 17 20:24:30 2010 +0100 @@ -226,7 +226,12 @@ if (err == KErrNone) { TPckg capsBuf(iCaps); - LeaveIfErr(iDrive.Caps(capsBuf), _L("Opened drive %d but couldn't read caps"), aDrive); + err = iDrive.Caps(capsBuf); + if (err) + { + iDrive.Close(); + if (aLeaveOnConnectErr) LeaveIfErr(err, _L("Opened drive %d but couldn't read caps"), aDrive); + } } else if (aLeaveOnConnectErr) { diff -r 264162c6ed91 -r 3c3961c1ae26 commands/mrouter/mrouter.cif --- a/commands/mrouter/mrouter.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/commands/mrouter/mrouter.cif Fri Sep 17 20:24:30 2010 +0100 @@ -20,3 +20,7 @@ Copyright (c) 2007-2010 Accenture. All rights reserved. +==smoke-test + +# Do any platforms still support this command? +mrouter diff -r 264162c6ed91 -r 3c3961c1ae26 commands/screenmode/screenmode.cif --- a/commands/screenmode/screenmode.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/commands/screenmode/screenmode.cif Fri Sep 17 20:24:30 2010 +0100 @@ -48,3 +48,6 @@ Copyright (c) 2009-2010 Accenture. All rights reserved. +==smoke-test + +screenmode list $Quiet diff -r 264162c6ed91 -r 3c3961c1ae26 commands/swi/swi.cif --- a/commands/swi/swi.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/commands/swi/swi.cif Fri Sep 17 20:24:30 2010 +0100 @@ -56,3 +56,6 @@ Copyright (c) 2008-2010 Accenture. All rights reserved. +==smoke-test + +swi list $Quiet diff -r 264162c6ed91 -r 3c3961c1ae26 commands/usb/usb.cif --- a/commands/usb/usb.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/commands/usb/usb.cif Fri Sep 17 20:24:30 2010 +0100 @@ -24,3 +24,6 @@ Copyright (c) 2010 Accenture. All rights reserved. +==smoke-test + +usb $Quiet diff -r 264162c6ed91 -r 3c3961c1ae26 commands/variant/variant.cif --- a/commands/variant/variant.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/commands/variant/variant.cif Fri Sep 17 20:24:30 2010 +0100 @@ -50,3 +50,11 @@ Copyright (c) 2008-2010 Accenture. All rights reserved. +==smoke-test + +variant $Quiet + +# One of these has to be true +variant wins || variant target || $Error +# But they can't both be +variant wins && variant target && $Error diff -r 264162c6ed91 -r 3c3961c1ae26 commands/wslog/wslog.cif --- a/commands/wslog/wslog.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/commands/wslog/wslog.cif Fri Sep 17 20:24:30 2010 +0100 @@ -42,3 +42,6 @@ Copyright (c) 2009-2010 Accenture. All rights reserved. +==smoke-test + +wslog status $Quiet diff -r 264162c6ed91 -r 3c3961c1ae26 core/builtins/chunkinfo.cif --- a/core/builtins/chunkinfo.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/core/builtins/chunkinfo.cif Fri Sep 17 20:24:30 2010 +0100 @@ -48,3 +48,9 @@ Copyright (c) 2006-2010 Accenture. All rights reserved. +==smoke-test + +# This should fail with KErrNotFound, but shouldn't crash +chunkinfo 1 $Silent &| var ? == "-1" || $Error + +chunkinfo $Quiet diff -r 264162c6ed91 -r 3c3961c1ae26 core/builtins/ciftest.cif --- a/core/builtins/ciftest.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/core/builtins/ciftest.cif Fri Sep 17 20:24:30 2010 +0100 @@ -92,3 +92,7 @@ ==copyright Copyright (c) 2010 Accenture. All rights reserved. + +==smoke-test + +# Ciftest itself doesn't have a smoketest! diff -r 264162c6ed91 -r 3c3961c1ae26 core/builtins/ciftest.cpp --- a/core/builtins/ciftest.cpp Wed Sep 15 00:45:50 2010 +0100 +++ b/core/builtins/ciftest.cpp Fri Sep 17 20:24:30 2010 +0100 @@ -89,7 +89,9 @@ { if (iVerbose) { - Printf(_L("%d tests run, %d passes %d failures. %d commands have no tests defined.\r\n"), iPasses + iFailures, iPasses, iFailures, iCifFiles.Count() - iPasses - iFailures); + Printf(_L("%d tests run, %d passes %d failures."), iPasses + iFailures, iPasses, iFailures); + if (iCifFiles.Count()) Printf(_L(" %d commands have no tests defined."), iCifFiles.Count() - iPasses - iFailures); + Printf(_L("\r\n")); } Complete(KErrNone); } diff -r 264162c6ed91 -r 3c3961c1ae26 core/builtins/clear.cif --- a/core/builtins/clear.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/core/builtins/clear.cif Fri Sep 17 20:24:30 2010 +0100 @@ -28,3 +28,6 @@ Copyright (c) 2006-2010 Accenture. All rights reserved. +==smoke-test + +cls --formfeed $Quiet diff -r 264162c6ed91 -r 3c3961c1ae26 core/builtins/compare.cif --- a/core/builtins/compare.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/core/builtins/compare.cif Fri Sep 17 20:24:30 2010 +0100 @@ -36,3 +36,15 @@ Copyright (c) 2006-2010 Accenture. All rights reserved. +==smoke-test + +date --timestamp | export -s TIMESTAMP +export Temp compare-test-$TIMESTAMP- +echo "Stuff" > $Temp1 +echo "Stuff" > $Temp2 +echo "Stuff thats different" > $Temp3 + +compare $Temp1 $Temp2 || $Error # Should be same +compare $Temp1 $Temp3 && $Error # Should be different + +rm $Temp1 $Temp2 $Temp3 diff -r 264162c6ed91 -r 3c3961c1ae26 core/builtins/console.cif --- a/core/builtins/console.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/core/builtins/console.cif Fri Sep 17 20:24:30 2010 +0100 @@ -40,3 +40,6 @@ Copyright (c) 2006-2010 Accenture. All rights reserved. +==smoke-test + +console $Quiet diff -r 264162c6ed91 -r 3c3961c1ae26 core/builtins/date.cif --- a/core/builtins/date.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/core/builtins/date.cif Fri Sep 17 20:24:30 2010 +0100 @@ -85,3 +85,8 @@ Copyright (c) 2006-2010 Accenture. All rights reserved. +==smoke-test + +date $Quiet +date --raw $Quiet +date --timestamp $Quiet diff -r 264162c6ed91 -r 3c3961c1ae26 core/builtins/dialog.cif --- a/core/builtins/dialog.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/core/builtins/dialog.cif Fri Sep 17 20:24:30 2010 +0100 @@ -62,3 +62,9 @@ Copyright (c) 2006-2010 Accenture. All rights reserved. +==smoke-test + +# Don't actually post a dialog, the tests need to be unobtrusive (and non-blocking) +export DIALOG_IMPL null +dialog "Some question which isn't important" +var ? == 0 || $Error diff -r 264162c6ed91 -r 3c3961c1ae26 core/builtins/driver.cif --- a/core/builtins/driver.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/core/builtins/driver.cif Fri Sep 17 20:24:30 2010 +0100 @@ -48,3 +48,6 @@ Copyright (c) 2006-2010 Accenture. All rights reserved. +==smoke-test + +driver list logical $Quiet \ No newline at end of file diff -r 264162c6ed91 -r 3c3961c1ae26 core/builtins/dump.cif --- a/core/builtins/dump.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/core/builtins/dump.cif Fri Sep 17 20:24:30 2010 +0100 @@ -28,3 +28,7 @@ Copyright (c) 2006-2010 Accenture. All rights reserved. +==smoke-test + +echo "123" | dump | export -s RESULT +var RESULT == "00000000: 31 00 32 00 33 00 0D 00 0A 00 1.2.3.....^r^n" || $Error diff -r 264162c6ed91 -r 3c3961c1ae26 core/builtins/echo.cif --- a/core/builtins/echo.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/core/builtins/echo.cif Fri Sep 17 20:24:30 2010 +0100 @@ -102,3 +102,6 @@ Copyright (c) 2006-2010 Accenture. All rights reserved. +==smoke-test + +# Tested by fshell-basic-test.script, this section is just so ciftest doesn't report it as a command without any tests diff -r 264162c6ed91 -r 3c3961c1ae26 core/builtins/exists.cif --- a/core/builtins/exists.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/core/builtins/exists.cif Fri Sep 17 20:24:30 2010 +0100 @@ -28,3 +28,6 @@ Copyright (c) 2006-2010 Accenture. All rights reserved. +==smoke-test + +# Tested by fshell-basic-test.script, this section is just so ciftest doesn't report it as a command without any tests diff -r 264162c6ed91 -r 3c3961c1ae26 core/builtins/exit.cif --- a/core/builtins/exit.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/core/builtins/exit.cif Fri Sep 17 20:24:30 2010 +0100 @@ -20,8 +20,11 @@ Note, this causes fshell's command history to be persisted to a file. - ==copyright Copyright (c) 2006-2010 Accenture. All rights reserved. +==smoke-test + +# This used to cause fshell problems +fshell -e exit diff -r 264162c6ed91 -r 3c3961c1ae26 core/builtins/match.cif --- a/core/builtins/match.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/core/builtins/match.cif Fri Sep 17 20:24:30 2010 +0100 @@ -43,3 +43,13 @@ ==see-also L + +==smoke-test + +echo "Test line of some sort^r^nIsn't fshell great?^r^nSome other line" | export -s TESTDATA +echo "$TESTDATA" | match *fshell* | export -s RESULT +var RESULT == "Isn't fshell great?^r^n" || $Error + +# Test anchored search +echo "$TESTDATA" | match Some* | export -s RESULT +var RESULT == "Some other line^r^n" || $Error diff -r 264162c6ed91 -r 3c3961c1ae26 core/builtins/ps.cif --- a/core/builtins/ps.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/core/builtins/ps.cif Fri Sep 17 20:24:30 2010 +0100 @@ -104,3 +104,6 @@ Copyright (c) 2005-2010 Accenture. All rights reserved. +==smoke-test + +ps $Quiet diff -r 264162c6ed91 -r 3c3961c1ae26 core/builtins/repeat.cif --- a/core/builtins/repeat.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/core/builtins/repeat.cif Fri Sep 17 20:24:30 2010 +0100 @@ -40,3 +40,6 @@ Copyright (c) 2006-2010 Accenture. All rights reserved. +==smoke-test + +# Tested by fshell-last-test.script, this section is just so ciftest doesn't report it as a command without any tests \ No newline at end of file diff -r 264162c6ed91 -r 3c3961c1ae26 core/builtins/rm.cif --- a/core/builtins/rm.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/core/builtins/rm.cif Fri Sep 17 20:24:30 2010 +0100 @@ -36,3 +36,6 @@ Copyright (c) 2006-2010 Accenture. All rights reserved. +==smoke-test + +# Tested by fshell-basic-test.script, this section is just so ciftest doesn't report it as a command without any tests diff -r 264162c6ed91 -r 3c3961c1ae26 core/builtins/rom.cif --- a/core/builtins/rom.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/core/builtins/rom.cif Fri Sep 17 20:24:30 2010 +0100 @@ -28,3 +28,6 @@ Copyright (c) 2006-2010 Accenture. All rights reserved. +==smoke-test + +variant target && rom --verbose $Quiet diff -r 264162c6ed91 -r 3c3961c1ae26 core/builtins/sort.cif --- a/core/builtins/sort.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/core/builtins/sort.cif Fri Sep 17 20:24:30 2010 +0100 @@ -24,9 +24,11 @@ Reverse the sort order. - - ==copyright Copyright (c) 2006-2010 Accenture. All rights reserved. +==smoke-test + +echo "wonderful^r^nfshell^r^njust^r^nis" | sort | export -s RESULT +var RESULT == "fshell^r^nis^r^njust^r^nwonderful^r^n" || $Error diff -r 264162c6ed91 -r 3c3961c1ae26 core/builtins/source.cif --- a/core/builtins/source.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/core/builtins/source.cif Fri Sep 17 20:24:30 2010 +0100 @@ -56,3 +56,6 @@ Copyright (c) 2006-2010 Accenture. All rights reserved. +==smoke-test + +# Tested by fshell-basic-test.script, this section is just so ciftest doesn't report it as a command without any tests diff -r 264162c6ed91 -r 3c3961c1ae26 core/builtins/svrinfo.cif --- a/core/builtins/svrinfo.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/core/builtins/svrinfo.cif Fri Sep 17 20:24:30 2010 +0100 @@ -28,3 +28,6 @@ Copyright (c) 2006-2010 Accenture. All rights reserved. +==smoke-test + +svrinfo $Quiet diff -r 264162c6ed91 -r 3c3961c1ae26 core/builtins/touch.cif --- a/core/builtins/touch.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/core/builtins/touch.cif Fri Sep 17 20:24:30 2010 +0100 @@ -24,9 +24,15 @@ The file to touch. - - ==copyright Copyright (c) 2006-2010 Accenture. All rights reserved. +==smoke-test + +date --timestamp | export -s TIMESTAMP +export TEMPFILE temp$TIMESTAMP +exists $TEMPFILE && $Error +touch $TEMPFILE +exists $TEMPFILE || $Error +rm $TEMPFILE diff -r 264162c6ed91 -r 3c3961c1ae26 core/builtins/var.cif --- a/core/builtins/var.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/core/builtins/var.cif Fri Sep 17 20:24:30 2010 +0100 @@ -76,3 +76,6 @@ Copyright (c) 2006-2010 Accenture. All rights reserved. +==smoke-test + +# Tested by fshell-basic-test.script, this section is just so ciftest doesn't report it as a command without any tests \ No newline at end of file diff -r 264162c6ed91 -r 3c3961c1ae26 core/builtins/version.cif --- a/core/builtins/version.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/core/builtins/version.cif Fri Sep 17 20:24:30 2010 +0100 @@ -24,3 +24,6 @@ Copyright (c) 2008-2010 Accenture. All rights reserved. +==smoke-test + +version $Quiet diff -r 264162c6ed91 -r 3c3961c1ae26 core/builtins/which.cif --- a/core/builtins/which.cif Wed Sep 15 00:45:50 2010 +0100 +++ b/core/builtins/which.cif Fri Sep 17 20:24:30 2010 +0100 @@ -24,3 +24,7 @@ Copyright (c) 2006-2010 Accenture. All rights reserved. +==smoke-test + +which which | export -s RESULT +var RESULT == "which: built-in command 'which'^r^n" || $Error diff -r 264162c6ed91 -r 3c3961c1ae26 core/src/worker_thread.cpp --- a/core/src/worker_thread.cpp Wed Sep 15 00:45:50 2010 +0100 +++ b/core/src/worker_thread.cpp Fri Sep 17 20:24:30 2010 +0100 @@ -43,6 +43,49 @@ 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(); @@ -65,17 +108,19 @@ 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"), iCountThreadsCreated); + 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; @@ -85,7 +130,9 @@ 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() @@ -112,6 +159,7 @@ void CThreadPool::Unlock() { RestoreHeap(); + WT_LOG(_L("Releasing lock from thread %d"), TUint(RThread().Id())); iLock.Signal(); } @@ -154,12 +202,18 @@ 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("Creating new worker thread %d"), TUint(foundThread->GetThreadId())); - iThreads.AppendL(foundThread); - CleanupStack::Pop(foundThread); - iPendingThreadLogons.AppendL(foundThread); + 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(); } @@ -179,14 +233,19 @@ // This is now always called in the main thread ASSERT(RThread().Id() == iMainThread.Id()); - // Find it and remove it - the next request will create a new worker if needed - for (TInt i = 0; i < iThreads.Count(); i++) + for (TInt i = 0; i < iThreadDeathWatchers.Count(); i++) { - CWorkerThread* worker = iThreads[i]; - if (worker == aWorker) + if (iThreadDeathWatchers[i]->WorkerThread() == aWorker) { - delete worker; + // 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; } } @@ -234,8 +293,7 @@ { ASSERT(!worker->Busy()); worker->Shutdown(); - delete worker; - iThreads.Remove(i); + // We don't delete the worker here, let CThreadDeathWatcher handle that } } Unlock(); @@ -271,6 +329,8 @@ else { // Everything else (that isn't busy) gets cleaned up + delete iThreadDeathWatchers[i]; + iThreadDeathWatchers.Remove(i); worker->Shutdown(); delete worker; iThreads.Remove(i); @@ -302,7 +362,7 @@ { for (TInt i = 0; i < iPendingThreadLogons.Count(); i++) { - iPendingThreadLogons[i]->RegisterThreadDeathWatcherOnCurrentThread(); + iPendingThreadLogons[i]->StartWatching(); } SwitchToThreadPoolHeap(); iPendingThreadLogons.Reset(); @@ -328,44 +388,11 @@ return 0; } - //// -class CThreadDeathWatcher : public CActive - { -public: - CThreadDeathWatcher(CWorkerThread* aWorker, RThread& aUnderlyingThread) - : CActive(CActive::EPriorityHigh), iWorker(aWorker), iThread(aUnderlyingThread) - { - } - ~CThreadDeathWatcher() - { - Cancel(); - } - void StartWatching() - { - CActiveScheduler::Add(this); - iThread.Logon(iStatus); - SetActive(); - } -private: - void DoCancel() - { - iThread.LogonCancel(iStatus); - } - void RunL() - { - Deque(); // Our work is done. Might as well extract ourselves from whatever scheduler we're in while we can - iWorker->ThreadDied(); - } +const TInt KMaxHeapSize = 1024 * 1024; -private: - CWorkerThread* iWorker; - RThread& iThread; - }; - -const TInt KMaxHeapSize = KMinHeapSize * 1024; - +// CWorkerThreadDispatchers run in the context of the worker thread they're owned by class CWorkerThreadDispatcher : public CActive { public: @@ -428,8 +455,6 @@ } User::LeaveIfError(err); - iThreadDeathWatcher = new(ELeave) CThreadDeathWatcher(this, iWorkerThread); - TRequestStatus stat; iWorkerThread.Rendezvous(stat); @@ -450,9 +475,8 @@ CWorkerThread::~CWorkerThread() { + WT_LOG(_L("Deleting worker thread %d"), TUint(GetThreadId())); ASSERT(iWorkerThread.Handle() == 0 || iWorkerThread.ExitType() != EExitPending); - //Cancel(); - delete iThreadDeathWatcher; iParentThread.Close(); iWorkerThread.Close(); } @@ -601,7 +625,7 @@ return iSharedAllocator; } -void CWorkerThread::ThreadDied() +void CWorkerThread::SignalClientThatThreadHasDied() { WT_LOG(_L("Task %d died with exittype %d reason %d"), iTaskId, iWorkerThread.ExitType(), iWorkerThread.ExitReason()); TInt err = iWorkerThread.ExitReason(); @@ -610,7 +634,6 @@ { iParentThread.RequestComplete(iCompletionStatus, err); } - iParentPool->WorkerDied(this); } TInt CWorkerThread::ThreadFn(TAny* aSelf) @@ -680,7 +703,3 @@ } } -void CWorkerThread::RegisterThreadDeathWatcherOnCurrentThread() - { - iThreadDeathWatcher->StartWatching(); - } diff -r 264162c6ed91 -r 3c3961c1ae26 core/src/worker_thread.h --- a/core/src/worker_thread.h Wed Sep 15 00:45:50 2010 +0100 +++ b/core/src/worker_thread.h Fri Sep 17 20:24:30 2010 +0100 @@ -31,6 +31,7 @@ }; class CWorkerThread; +class CThreadDeathWatcher; class CThreadPool : public CActive, public MTaskRunner { @@ -70,12 +71,10 @@ TInt iPendingCallbacks; CPeriodic* iIdleTimer; TInt iCountThreadsCreated; // This is for statistics gathering, not involved in the logic - RArray iPendingThreadLogons; // Not owned + RArray iPendingThreadLogons; // Not owned + RPointerArray iThreadDeathWatchers; }; - -class CThreadDeathWatcher; - class CWorkerThread : public CBase, public MThreadedTask { public: @@ -89,7 +88,6 @@ TInt Setup(TInt aTaskId, const TDesC& aThreadName, MTaskRunner::TThreadFunctionL aThreadFunction, TAny* aThreadContext); void Shutdown(); ~CWorkerThread(); - void RegisterThreadDeathWatcherOnCurrentThread(); TBool Running() const { return iWorkerThread.Handle() && iWorkerThread.ExitType() == EExitPending; } @@ -99,7 +97,7 @@ void AbortTask(); public: // For CThreadDeathWatcher to use - void ThreadDied(); + void SignalClientThatThreadHasDied(); private: CWorkerThread(CThreadPool* aParentPool, RAllocator* aSharedAllocator); @@ -126,6 +124,7 @@ TRequestStatus* iCompletionStatus; friend class CWorkerThreadDispatcher; + friend class CThreadDeathWatcher; }; #endif diff -r 264162c6ed91 -r 3c3961c1ae26 core/tsrc/fshell-basic-test.script --- a/core/tsrc/fshell-basic-test.script Wed Sep 15 00:45:50 2010 +0100 +++ b/core/tsrc/fshell-basic-test.script Fri Sep 17 20:24:30 2010 +0100 @@ -107,7 +107,9 @@ export FILE c:\fshell-basic-test.txt rm $FILE 2>/dev/null &| echo -n "" # I don't like using "&| echo" syntax to indicate don't care if it fails. Probably rm -f should be quiet like unix version +exists $FILE && $Error echo -n "Testing file redirection" > c:\fshell-basic-test.txt +exists $FILE || $Error # The redirect stdin operation doesn't get used much export -s FILECONTENTS < $FILE