sl@0: // Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // f32test\fsstress\t_soak1.cpp sl@0: // Suggestions for future improvements: The createVerifyFileX method uses local sl@0: // RBufs for writing and reading. By making these buffers global (at least the sl@0: // write buffers), the overhead of allocating and filling memory can be avoided. sl@0: // sl@0: // sl@0: sl@0: #include sl@0: #include sl@0: #include "t_chlffs.h" sl@0: #include "t_server.h" sl@0: #define __TESTING_LFFS__ sl@0: sl@0: LOCAL_D TInt gDriveNumber; sl@0: sl@0: const TInt KMaxNumberThreads = 4; sl@0: const TInt KHeapSize = 0x600000; sl@0: const TInt KDiskUnitThreshold = 0x1000000; // if disk metrics are above threshold, display in MB rather than KB sl@0: const TInt KNotificationInterval = 10 * 1000000; sl@0: sl@0: const TInt KMaxSizeArray = 3; sl@0: const TInt KMaxFilesPerDirectory = 100; sl@0: sl@0: struct TTestMetrics sl@0: { sl@0: TInt SizeArray[KMaxSizeArray][5]; sl@0: TInt KSpaceRequiredForMakeAndDelete; sl@0: TInt KFillDiskFileSize; sl@0: }; sl@0: sl@0: sl@0: sl@0: sl@0: ///#define SINGLE__THREAD sl@0: sl@0: // 256 sectors, 17 sectors+1, 3 bytes, 254 sectors+4, 100 sectors sl@0: // 50 sectors, 113 sectors+25, 10 sectors, 103 bytes, 199 sectors+44 sl@0: // 24 sectors+166, 189 bytes, 225 sectors, 4 sectors+221, 117 sectors+40 sl@0: LOCAL_D const TTestMetrics DefMetrics = sl@0: { sl@0: {{65536,4353,3,65028,25600}, // Sizearray[0] sl@0: {12800,28953,2560,103,50988}, // Sizearray[1] sl@0: {6310,189,57600,1245,29992}}, // Sizearray[2] sl@0: 655360, // KSpaceRequiredForMakeAndDelete sl@0: 65536 // KFillDiskFileSize sl@0: }; sl@0: sl@0: // 16 sectors, 1 sectors+1, 3 bytes, 15 sectors+4, 6 sectors sl@0: // 3 sectors, 7 sectors+25, 1 sector, 103 bytes, 12 sectors+44 sl@0: // 2 sectors+166, 189 bytes, 15 sectors, 4 sectors+221, 7 sectors+40 sl@0: LOCAL_D const TTestMetrics LffsMetrics = sl@0: { sl@0: {{4096,257,3,3844,1536}, // Sizearray[0] sl@0: {768,1817,256,103,3116}, // Sizearray[1] sl@0: {678,189,3840,1245,1832}}, // Sizearray[2] sl@0: 36864, // KSpaceRequiredForMakeAndDelete sl@0: 4096 // KFillDiskFileSize sl@0: }; sl@0: sl@0: // 1600 sectors, 100 sectors+100, 1 sector+44, 1501 sectors+144, 600 sectors sl@0: // 300 sectors, 709 sectors+196, 100 sectors, 40 sectors+60, 1217 sectors+48 sl@0: // 264 sectors+216, 73 sectors+212, 486 sectors+84, 715 sectors+160 sl@0: LOCAL_D const TTestMetrics FAT32Metrics = sl@0: { sl@0: {{409600,25700,300,384400,153600}, // Sizearray[0] sl@0: {76800,181700,25600,10300,311600}, // Sizearray[1] sl@0: {67800,18900,384000,124500,183200}}, // Sizearray[2] sl@0: 3686400, // KSpaceRequiredForMakeAndDelete sl@0: 409600 // KFillDiskFileSize sl@0: }; sl@0: sl@0: // 8 sectors, 1 sectors+1, 3 bytes, 7 sectors+4, 3 sectors sl@0: // 1 sectors, 3 sectors+25, 1 sector, 103 bytes, 6 sectors+44 sl@0: // 1 sector+166 bytes, 189 bytes, 7 sectors, 2 sectors+221, 3 sectors+40 sl@0: sl@0: LOCAL_D const TTestMetrics NandMetrics = sl@0: { sl@0: {{2048,257,3,1796,768}, // Sizearray[0] sl@0: {256,793,256,103,1580}, // Sizearray[1] sl@0: {422,189,1792,833,808}}, // Sizearray[2] sl@0: 20480, // KSpaceRequiredForMakeAndDelete sl@0: 2048 // KFillDiskFileSize sl@0: }; sl@0: sl@0: sl@0: sl@0: LOCAL_D const TTestMetrics* TheMetrics = 0; sl@0: sl@0: sl@0: #if defined(__WINS__) sl@0: #define WIN32_LEAN_AND_MEAN sl@0: #pragma warning (disable:4201) // warning C4201: nonstandard extension used : nameless struct/union sl@0: #pragma warning (default:4201) // warning C4201: nonstandard extension used : nameless struct/union sl@0: #endif sl@0: sl@0: #if defined(_UNICODE) sl@0: #if !defined(UNICODE) sl@0: #define UNICODE sl@0: #endif sl@0: #endif sl@0: sl@0: #ifndef SINGLE__THREAD sl@0: #define REUSE_THREAD sl@0: #endif sl@0: sl@0: #ifdef REUSE_THREAD sl@0: LOCAL_D TBool gRequestEnd; sl@0: #endif sl@0: sl@0: class TThreadTestInfo sl@0: { sl@0: public: sl@0: TInt iCycles; sl@0: TInt iErrors; sl@0: TInt iSizeArrayPos; sl@0: TInt iErrorInfo; sl@0: }; sl@0: sl@0: GLDEF_D RTest test(_L("T_SOAK1")); sl@0: LOCAL_D TThreadTestInfo ThreadTestInfo[KMaxNumberThreads]; sl@0: LOCAL_D TBool CurrentlyFillingDisk; sl@0: LOCAL_D TInt FillDiskCount; sl@0: LOCAL_D TInt FillDiskCycle; sl@0: sl@0: LOCAL_C TInt MakeAndDeleteFilesThread(TAny* anId); sl@0: LOCAL_C TInt FillAndEmptyDiskThread(TAny* anId); sl@0: LOCAL_C TInt CreateVerifyFileX(const TDesC& aBaseName,TInt aSize,RFs &aFs,TInt aPattern); sl@0: LOCAL_C TInt MakeFileName(TInt aThreadId, TInt aFileNumber, RFs & aFs, TFileName& aName, TBool aMakeDir = ETrue); sl@0: LOCAL_C TInt AppendPath(TFileName& aPath, TInt aNumber, TInt aLevel); sl@0: sl@0: _LIT( KConnect, "Connect" ); sl@0: _LIT( KDelete, "Delete" ); sl@0: _LIT( KDriveToChar, "DriveToChar" ); sl@0: _LIT( KAppendPath, "AppendPath" ); sl@0: _LIT( KSetSessPath, "SetSessPath" ); sl@0: _LIT( KMdAll, "MkdirAll" ); sl@0: _LIT( KVolInfo, "VolInfo" ); sl@0: _LIT( KReplace, "Replace" ); sl@0: _LIT( KRead, "Read" ); sl@0: _LIT( KWrite, "Write" ); sl@0: _LIT( KFlush, "Flush" ); sl@0: _LIT( KDataCompare, "DataCompare" ); sl@0: _LIT( KMemory, "Memory" ); sl@0: _LIT( KFilePrefix, "FILE_" ); sl@0: sl@0: _LIT(KPath, "?:\\SOAK_TEST\\SESSION%d\\"); sl@0: sl@0: LOCAL_C void LogError( TInt aError, const TDesC& aAction, const TDesC& aFileName, TUint a1, TUint a2, TInt line = -1 ) sl@0: { sl@0: if(line >= 0) sl@0: { sl@0: _LIT(KFmt, "TSOAK1 ERROR (line %d): %d, file [%S], %S, (0x%x, 0x%x)"); sl@0: RDebug::Print(KFmt, line, aError, &aFileName, &aAction, a1, a2); sl@0: } sl@0: else sl@0: { sl@0: _LIT(KFmt, "TSOAK1 ERROR: %d, file [%S], %S, (0x%x, 0x%x)"); sl@0: RDebug::Print(KFmt, aError, &aFileName, &aAction, a1, a2); sl@0: } sl@0: } sl@0: sl@0: LOCAL_C TInt MakeFileName(TInt aThreadId, TInt aFileNumber, RFs & aFs, TFileName& aName, TBool aMakeDir) sl@0: // sl@0: // creates a file name and makes all the directory components, if required sl@0: // sl@0: { sl@0: sl@0: TFileName path; sl@0: path.Format(KPath, aThreadId); sl@0: sl@0: TChar driveLetter; sl@0: TInt r; sl@0: r = aFs.DriveToChar(gDriveNumber, driveLetter); sl@0: if (r != KErrNone) sl@0: { sl@0: LogError(r, KDriveToChar, KNullDesC, driveLetter, 0); sl@0: aFs.Close(); sl@0: return(r); sl@0: } sl@0: sl@0: path[0] = (TText) driveLetter; sl@0: r = aFs.SetSessionPath(path); sl@0: if (r != KErrNone) sl@0: { sl@0: LogError(r, KSetSessPath, path, 0, 0); sl@0: aFs.Close(); sl@0: return(r); sl@0: } sl@0: sl@0: // add additional directories sl@0: TInt fileNumber; sl@0: fileNumber = aFileNumber; sl@0: r = AppendPath(path, fileNumber, 0); sl@0: if(r != KErrNone) sl@0: { sl@0: LogError(r, KAppendPath, path, fileNumber, 0); sl@0: aFs.Close(); sl@0: return(r); sl@0: } sl@0: sl@0: if(aMakeDir) sl@0: { sl@0: r = aFs.MkDirAll(path); sl@0: if (r != KErrNone && r != KErrAlreadyExists) sl@0: { sl@0: LogError(r, KMdAll, path, 0, 0); sl@0: aFs.Close(); sl@0: return(r); sl@0: } sl@0: } sl@0: sl@0: // and finally add file name sl@0: path.Append(KFilePrefix); sl@0: path.AppendNum(aFileNumber); sl@0: sl@0: aName = path; sl@0: return(KErrNone); sl@0: } sl@0: sl@0: sl@0: LOCAL_C TInt AppendPath(TFileName& aPath, TInt aNumber, TInt aLevel) sl@0: // sl@0: // helper function for MakeFileName() sl@0: // sl@0: { sl@0: sl@0: if(aNumber > KMaxFilesPerDirectory) sl@0: { sl@0: aNumber /= KMaxFilesPerDirectory; sl@0: AppendPath(aPath, aNumber, aLevel + 1); sl@0: } sl@0: sl@0: if(aLevel) sl@0: { sl@0: aPath.AppendNum(aNumber % KMaxFilesPerDirectory); sl@0: aPath.Append('\\'); sl@0: } sl@0: sl@0: return(KErrNone); sl@0: } sl@0: sl@0: LOCAL_C TInt MakeAndDeleteFilesThread(TAny* anId) sl@0: // sl@0: // The entry point for the 'MakeAndDeleteFiles' thread. sl@0: // sl@0: { sl@0: sl@0: TInt thrdId=(TInt)anId; sl@0: TInt pattern=(ThreadTestInfo[thrdId].iCycles)%2; sl@0: TInt r; sl@0: RFs f; sl@0: r=f.Connect(); sl@0: if (r!=KErrNone) sl@0: { sl@0: LogError( r, KConnect, KNullDesC, 0, 0 ); sl@0: ThreadTestInfo[thrdId].iErrorInfo=1; sl@0: return(r); sl@0: } sl@0: sl@0: TFileName fileName; sl@0: TInt sizeArrayPos = ThreadTestInfo[thrdId].iSizeArrayPos; sl@0: #ifdef REUSE_THREAD sl@0: while(!gRequestEnd) sl@0: { sl@0: #endif sl@0: for(TInt i = 0; i < 5; i++) sl@0: { sl@0: // create files sl@0: r = MakeFileName(thrdId, i, f, fileName); sl@0: if(r != KErrNone) sl@0: { sl@0: ThreadTestInfo[thrdId].iErrorInfo=2; sl@0: f.Close(); sl@0: return(r); sl@0: } sl@0: sl@0: r = CreateVerifyFileX(fileName, TheMetrics->SizeArray[sizeArrayPos][0], f, pattern); sl@0: if (r!=KErrNone) sl@0: { sl@0: ThreadTestInfo[thrdId].iErrorInfo=3; sl@0: f.Close(); sl@0: return(r); sl@0: } sl@0: sl@0: // delete selected files at certain points in the cycle sl@0: TInt deleteFile = EFalse; sl@0: switch(i) sl@0: { sl@0: default: sl@0: // nothing to be done sl@0: break; sl@0: case 2: sl@0: // delete file 0 sl@0: deleteFile = ETrue; sl@0: r = MakeFileName(thrdId, 0, f, fileName, EFalse); sl@0: break; sl@0: case 3: sl@0: // delete file 1 sl@0: deleteFile = ETrue; sl@0: r = MakeFileName(thrdId, 1, f, fileName, EFalse); sl@0: break; sl@0: } sl@0: sl@0: if(deleteFile) sl@0: { sl@0: // check MakeFileName() error code sl@0: if(r != KErrNone) sl@0: { sl@0: ThreadTestInfo[thrdId].iErrorInfo = 4; sl@0: f.Close(); sl@0: return(r); sl@0: } sl@0: sl@0: // and delete file sl@0: r = f.Delete(fileName); sl@0: if(r != KErrNone) sl@0: { sl@0: ThreadTestInfo[thrdId].iErrorInfo = 5; sl@0: f.Close(); sl@0: return(r); sl@0: } sl@0: } sl@0: } sl@0: sl@0: sizeArrayPos++; sl@0: if(sizeArrayPos >= KMaxSizeArray) sl@0: { sl@0: sizeArrayPos = 0; sl@0: } sl@0: sl@0: ThreadTestInfo[thrdId].iSizeArrayPos=sizeArrayPos; sl@0: #ifdef REUSE_THREAD sl@0: ThreadTestInfo[thrdId].iCycles++; sl@0: pattern = (ThreadTestInfo[thrdId].iCycles) % 2; sl@0: } sl@0: #endif sl@0: sl@0: f.Close(); sl@0: return(KErrNone); sl@0: } sl@0: sl@0: LOCAL_C TInt FillAndEmptyDiskThread(TAny* anId) sl@0: // sl@0: // The entry point for the 'FillAndEmptyDisk' thread. sl@0: // sl@0: { sl@0: sl@0: TInt thrdId=(TInt)anId; sl@0: TInt pattern=(ThreadTestInfo[thrdId].iCycles)%2; sl@0: TInt r; sl@0: RFs f; sl@0: r=f.Connect(); sl@0: if (r!=KErrNone) sl@0: { sl@0: LogError( r, KConnect, KNullDesC, 0, 0 ); sl@0: ThreadTestInfo[thrdId].iErrorInfo=6; sl@0: return(r); sl@0: } sl@0: sl@0: TInt i; sl@0: #ifdef REUSE_THREAD sl@0: while(!gRequestEnd) sl@0: { sl@0: #endif sl@0: for (i=0;i<5;i++) // Create/Delete 5 files each time sl@0: { sl@0: if (CurrentlyFillingDisk) sl@0: { sl@0: TVolumeInfo v; sl@0: r=f.Volume(v,gDriveNumber); sl@0: if (r!=KErrNone) sl@0: { sl@0: ThreadTestInfo[thrdId].iErrorInfo=7; sl@0: LogError( r, KVolInfo, KNullDesC, gDriveNumber, 0); sl@0: f.Close(); sl@0: return(r); sl@0: } sl@0: if (v.iFree<=(TheMetrics->KSpaceRequiredForMakeAndDelete+TheMetrics->KFillDiskFileSize)) sl@0: CurrentlyFillingDisk=EFalse; sl@0: else sl@0: { sl@0: TFileName fileName; sl@0: r = MakeFileName(thrdId, FillDiskCount, f, fileName); sl@0: if(r != KErrNone) sl@0: { sl@0: ThreadTestInfo[thrdId].iErrorInfo = 8; sl@0: f.Close(); sl@0: return(r); sl@0: } sl@0: sl@0: r = CreateVerifyFileX(fileName, TheMetrics->KFillDiskFileSize, f, pattern); sl@0: if (r!=KErrNone) sl@0: { sl@0: ThreadTestInfo[thrdId].iErrorInfo=9; sl@0: f.Close(); sl@0: return(r); sl@0: } sl@0: FillDiskCount++; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: if (FillDiskCount<=0) sl@0: { sl@0: CurrentlyFillingDisk=ETrue; sl@0: FillDiskCount=0; sl@0: FillDiskCycle++; sl@0: } sl@0: else sl@0: { sl@0: FillDiskCount--; sl@0: TFileName fileName; sl@0: r = MakeFileName(thrdId, FillDiskCount, f, fileName, EFalse); sl@0: if(r != KErrNone) sl@0: { sl@0: ThreadTestInfo[thrdId].iErrorInfo = 10; sl@0: f.Close(); sl@0: return(r); sl@0: } sl@0: sl@0: r = f.Delete(fileName); sl@0: if (r!=KErrNone) sl@0: { sl@0: ThreadTestInfo[thrdId].iErrorInfo=11; sl@0: LogError(r, KDelete, fileName,FillDiskCount, 0); sl@0: f.Close(); sl@0: return(r); sl@0: } sl@0: } sl@0: } sl@0: } sl@0: #ifdef REUSE_THREAD sl@0: ThreadTestInfo[thrdId].iCycles++; sl@0: pattern = (ThreadTestInfo[thrdId].iCycles) % 2; sl@0: } sl@0: #endif sl@0: sl@0: f.Close(); sl@0: return(KErrNone); sl@0: } sl@0: sl@0: const TInt KCreateFileBufSize = 0x80000; sl@0: LOCAL_C TInt CreateVerifyFileX(const TDesC& aFileName, TInt aSize, RFs& aFs, TInt aPattern) sl@0: // sl@0: // Create and verify a file. sl@0: // sl@0: { sl@0: // Note, the directory structure is provided by MakeFileName(). Hence it sl@0: // is assumed at this point that the path to the file exists already. sl@0: RFile file; sl@0: TInt r; sl@0: r = file.Replace(aFs, aFileName, EFileWrite); sl@0: if (r!=KErrNone) sl@0: { sl@0: LogError( r, KReplace, aFileName, EFileWrite, 0 ); sl@0: return(r); sl@0: } sl@0: sl@0: // Grow it to the specified size by writing a pattern buffer to it sl@0: // Alternate the pattern buffer each time sl@0: RBuf8 wBuf; sl@0: r = wBuf.CreateMax(KCreateFileBufSize); sl@0: if(r != KErrNone) sl@0: { sl@0: LogError(r, KMemory, aFileName, 0, 0, __LINE__); sl@0: wBuf.Close(); sl@0: file.Close(); sl@0: return(r); sl@0: } sl@0: sl@0: TInt i; sl@0: sl@0: if (aPattern) sl@0: { sl@0: // ascending pattern sl@0: for (i = 0; i < KCreateFileBufSize; i++) sl@0: { sl@0: wBuf[i] = (TUint8) i; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: // descending pattern sl@0: for (i = 0; i < KCreateFileBufSize; i++) sl@0: { sl@0: wBuf[i] = (TUint8) ((KCreateFileBufSize - 1) - i); sl@0: } sl@0: } sl@0: sl@0: sl@0: TInt pos; sl@0: TInt chunkSize; sl@0: TInt sectorCount = 0; sl@0: sl@0: for (pos = 0; pos < aSize; pos += chunkSize) sl@0: { sl@0: wBuf[0]=(TUint8)i; // Insert sector count sl@0: chunkSize = Min((aSize-pos), KCreateFileBufSize); sl@0: r = file.Write(pos, wBuf, chunkSize); sl@0: if (r != KErrNone) sl@0: { sl@0: LogError(r, KWrite, aFileName, pos, chunkSize, __LINE__); sl@0: file.Close(); sl@0: wBuf.Close(); sl@0: return(r); sl@0: } sl@0: sl@0: sectorCount++; sl@0: } sl@0: sl@0: // Flush it sl@0: r=file.Flush(); sl@0: if (r!=KErrNone) sl@0: { sl@0: LogError( r, KFlush, aFileName, 0, 0, __LINE__); sl@0: file.Close(); sl@0: wBuf.Close(); sl@0: return(r); sl@0: } sl@0: sl@0: // Test still works if this is commented out just doesn't verify sl@0: // Read back and verify it sl@0: RBuf8 rBuf; sl@0: r = rBuf.CreateMax(KCreateFileBufSize); sl@0: if(r != KErrNone) sl@0: { sl@0: LogError( r, KMemory, aFileName, 0, 0, __LINE__); sl@0: file.Close(); sl@0: wBuf.Close(); sl@0: rBuf.Close(); sl@0: return(KErrGeneral); sl@0: } sl@0: sl@0: sl@0: for (pos = 0;pos < aSize; pos += chunkSize) sl@0: { sl@0: chunkSize = Min((aSize-pos), KCreateFileBufSize); sl@0: r = file.Read(pos, rBuf, chunkSize); sl@0: if (r != KErrNone) sl@0: { sl@0: LogError(r, KRead, aFileName, pos, 0, __LINE__); sl@0: file.Close(); sl@0: wBuf.Close(); sl@0: rBuf.Close(); sl@0: return(r); sl@0: } sl@0: sl@0: wBuf[0] = (TUint8) i; // Insert sector count sl@0: wBuf.SetLength(chunkSize); sl@0: r = rBuf.Compare(wBuf); sl@0: if (r != 0) sl@0: { sl@0: LogError(r, KDataCompare, aFileName, 0, 0, __LINE__); sl@0: file.Close(); sl@0: wBuf.Close(); sl@0: rBuf.Close(); sl@0: return(KErrGeneral); sl@0: } sl@0: } sl@0: // sl@0: sl@0: file.Close(); sl@0: wBuf.Close(); sl@0: rBuf.Close(); sl@0: return(KErrNone); sl@0: } sl@0: sl@0: sl@0: #ifdef SINGLE__THREAD sl@0: LOCAL_C void DoTests() sl@0: // sl@0: // single thread sl@0: // sl@0: { sl@0: sl@0: TInt r=KErrNone; sl@0: test.Next(_L("Start continuous file Write/Read/Verify operation")); sl@0: RThread t[KMaxNumberThreads]; sl@0: TRequestStatus tStat[KMaxNumberThreads]; sl@0: sl@0: TInt i=0; sl@0: sl@0: TName threadName; sl@0: TRequestStatus kStat=KRequestPending; sl@0: test.Console()->Read(kStat); sl@0: ThreadTestInfo[i].iCycles=0; sl@0: ThreadTestInfo[i].iErrors=0; sl@0: ThreadTestInfo[i].iSizeArrayPos=(i%KMaxSizeArray); sl@0: ThreadTestInfo[i].iErrorInfo=0; sl@0: if (i<(KMaxNumberThreads-1)) sl@0: { sl@0: threadName.Format(_L("MakeAndDeleteFiles%d"),i); sl@0: r=t[i].Create(threadName,MakeAndDeleteFilesThread,KDefaultStackSize,KHeapSize,KHeapSize,(TAny*)i); sl@0: } sl@0: else sl@0: { sl@0: // Last thread fills/empties disk sl@0: threadName.Format(_L("FillAndEmptyDisk%d"),i); sl@0: r=t[i].Create(threadName,FillAndEmptyDiskThread,KDefaultStackSize,KHeapSize,KHeapSize,(TAny*)i); sl@0: } sl@0: if (r!=KErrNone) sl@0: test.Printf(_L("Error(%d) creating thread(%d)\r\n"),r,i); sl@0: test(r==KErrNone); sl@0: t[i].Logon(tStat[i]); sl@0: t[i].Resume(); sl@0: CurrentlyFillingDisk=ETrue; sl@0: FillDiskCount=0; sl@0: sl@0: TInt totalTime=0; sl@0: TTime startTime; sl@0: TTime time; sl@0: startTime.UniversalTime(); sl@0: sl@0: TInt ypos=test.Console()->WhereY(); sl@0: FOREVER sl@0: { sl@0: User::WaitForAnyRequest(); sl@0: if (kStat!=KRequestPending) sl@0: { sl@0: t[i].LogonCancel(tStat[i]); sl@0: User::WaitForRequest(tStat[i]); sl@0: break; sl@0: } sl@0: else sl@0: { sl@0: TBool threadFinished=EFalse; sl@0: if (tStat[i]!=KRequestPending && !threadFinished) sl@0: { sl@0: t[i].Close(); sl@0: (ThreadTestInfo[i].iCycles)++; sl@0: if (tStat[i]!=KErrNone) sl@0: (ThreadTestInfo[i].iErrors)++; sl@0: threadFinished=ETrue; sl@0: sl@0: // Launch another thread sl@0: TInt threadNameId=((ThreadTestInfo[i].iCycles)%2)?(i+KMaxNumberThreads):i; // Alternate thread name sl@0: threadName.Format(_L("FillAndEmptyDisk%d"),threadNameId); sl@0: r=t[i].Create(threadName,FillAndEmptyDiskThread,KDefaultStackSize,KHeapSize,KHeapSize,(TAny*)i); sl@0: if (r!=KErrNone) sl@0: test.Printf(_L("Error(%d) creating thread(%d)\r\n"),r,i); sl@0: test(r==KErrNone); sl@0: t[i].Logon(tStat[i]); sl@0: t[i].Resume(); sl@0: } sl@0: sl@0: test.Console()->SetPos(0,(ypos+i)); sl@0: test.Printf(_L("Thread(%d): % 4d errors in % 4d cycles (%d)\r\n"),i,ThreadTestInfo[i].iErrors,ThreadTestInfo[i].iCycles,ThreadTestInfo[i].iErrorInfo); sl@0: if (!threadFinished) sl@0: { sl@0: test.Printf(_L("Semaphore death")); sl@0: break; sl@0: } sl@0: TVolumeInfo v; sl@0: r=TheFs.Volume(v,gDriveNumber); sl@0: test(r==KErrNone); sl@0: test.Console()->SetPos(0,(ypos+KMaxNumberThreads)); sl@0: test.Printf(_L("Free space on disk: %u K(of %u K)\r\n"),(v.iFree/1024).Low(),(v.iSize/1024).Low()); sl@0: sl@0: TTimeIntervalSeconds timeTaken; sl@0: time.UniversalTime(); sl@0: r=time.SecondsFrom(startTime,timeTaken); sl@0: test(r==KErrNone); sl@0: totalTime=timeTaken.Int(); sl@0: sl@0: TInt seconds = totalTime % 60; sl@0: TInt minutes = (totalTime / 60) % 60; sl@0: TInt hours = (totalTime / 3600) % 24; sl@0: TInt days = totalTime / (60 * 60 * 24); sl@0: test.Printf(_L("Elapsed Time: %d d %02d:%02d:%02d\r\n"), days, hours, minutes, seconds); sl@0: } sl@0: } sl@0: } sl@0: sl@0: #else sl@0: sl@0: LOCAL_C void DoTests() sl@0: // sl@0: // multiple threads sl@0: // sl@0: { sl@0: sl@0: TInt r=KErrNone; sl@0: test.Next(_L("Start continuous file Write/Read/Verify operation")); sl@0: RThread t[KMaxNumberThreads]; sl@0: TRequestStatus tStat[KMaxNumberThreads]; sl@0: sl@0: TInt i=0; sl@0: sl@0: TName threadName; sl@0: TRequestStatus kStat=KRequestPending; sl@0: test.Console()->Read(kStat); sl@0: for (i=0;iWhereY(); sl@0: FOREVER sl@0: { sl@0: User::WaitForAnyRequest(); sl@0: if (kStat!=KRequestPending) sl@0: { sl@0: // user requested to end - let threads die sl@0: #ifdef REUSE_THREAD sl@0: gRequestEnd = ETrue; sl@0: #endif sl@0: for (i=0;iSetPos(0,(ypos+i)); sl@0: test.Printf(_L("Thread(%d): % 4d errors in % 4d cycles (%d)\r\n"),i,ThreadTestInfo[i].iErrors,ThreadTestInfo[i].iCycles,ThreadTestInfo[i].iErrorInfo); sl@0: } sl@0: sl@0: #ifdef REUSE_THREAD sl@0: if(displayStat != KRequestPending) sl@0: { sl@0: // re-request notification sl@0: displayTimer.After(displayStat, KNotificationInterval); sl@0: } sl@0: else if (!threadFinished) sl@0: { sl@0: test.Printf(_L("Semaphore death")); sl@0: break; sl@0: } sl@0: #else sl@0: if (!threadFinished) sl@0: { sl@0: test.Printf(_L("Semaphore death")); sl@0: break; sl@0: } sl@0: #endif sl@0: sl@0: r=TheFs.Volume(v,gDriveNumber); sl@0: test(r==KErrNone); sl@0: test.Console()->SetPos(0,(ypos+KMaxNumberThreads)); sl@0: sl@0: TInt freeSpace; sl@0: TInt8 freeSpaceUnit; sl@0: TInt totalSpace; sl@0: TInt8 totalSpaceUnit; sl@0: sl@0: // switch t sl@0: if(v.iFree > KDiskUnitThreshold) sl@0: { sl@0: // display in MB sl@0: freeSpace = I64LOW(v.iFree / (1024 * 1024)); sl@0: freeSpaceUnit = 'M'; sl@0: } sl@0: else sl@0: { sl@0: // display in KB sl@0: freeSpace = I64LOW(v.iFree/1024); sl@0: freeSpaceUnit = 'K'; sl@0: } sl@0: sl@0: if(v.iSize > KDiskUnitThreshold) sl@0: { sl@0: // display in MB sl@0: totalSpace = I64LOW(v.iSize / (1024 * 1024)); sl@0: totalSpaceUnit = 'M'; sl@0: } sl@0: else sl@0: { sl@0: // display in KB sl@0: totalSpace = I64LOW(v.iSize/1024); sl@0: totalSpaceUnit = 'K'; sl@0: } sl@0: sl@0: test.Printf(_L("Free space on disk: %u %cB (of %u %cB)\r\n"), sl@0: freeSpace, freeSpaceUnit, totalSpace, totalSpaceUnit); sl@0: sl@0: TTimeIntervalSeconds timeTaken; sl@0: time.UniversalTime(); sl@0: r=time.SecondsFrom(startTime,timeTaken); sl@0: test(r==KErrNone); sl@0: totalTime=timeTaken.Int(); sl@0: sl@0: TInt seconds = totalTime % 60; sl@0: TInt minutes = (totalTime / 60) % 60; sl@0: TInt hours = (totalTime / 3600) % 24; sl@0: TInt days = totalTime / (60 * 60 * 24); sl@0: test.Printf(_L("Elapsed Time (%d): %d d %02d:%02d:%02d\r\n"), FillDiskCycle, days, hours, minutes, seconds); sl@0: sl@0: if(CurrentlyFillingDisk) sl@0: { sl@0: // work out ETA to full disk sl@0: r = time.SecondsFrom(cycleTime, timeTaken); sl@0: if((r == KErrNone) && (v.iSize > v.iFree)) sl@0: { sl@0: totalTime = (TInt) ((v.iFree/1024 * (TInt64) timeTaken.Int()) / (v.iSize/1024 - v.iFree/1024)); sl@0: seconds = totalTime % 60; sl@0: minutes = (totalTime / 60) % 60; sl@0: hours = (totalTime / 3600) % 24; sl@0: days = totalTime / (60 * 60 * 24); sl@0: sl@0: test.Printf(_L("ETA to full disk: %d d %02d:%02d:%02d\r\n"), days, hours, minutes, seconds); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: // currently emptying disk, update time metrics sl@0: cycleTime.UniversalTime(); sl@0: } sl@0: sl@0: } sl@0: sl@0: test.Printf(_L("\n")); sl@0: } sl@0: } sl@0: #endif sl@0: sl@0: sl@0: GLDEF_C void CallTestsL() sl@0: // sl@0: // Call all tests sl@0: // sl@0: { sl@0: TInt r = TheFs.CharToDrive( gSessionPath[0], gDriveNumber ); sl@0: test( KErrNone == r ); sl@0: sl@0: // select appropriate metrics table sl@0: if(IsFileSystemFAT32(TheFs, gDriveNumber)) sl@0: { sl@0: TheMetrics = &FAT32Metrics; sl@0: RDebug::Printf("Using FAT32 metrics\r\n"); sl@0: } sl@0: else if(IsTestingLFFS()) sl@0: { sl@0: TheMetrics = &LffsMetrics; sl@0: RDebug::Printf("Using LFFS metrics\r\n"); sl@0: } sl@0: else sl@0: { sl@0: TDriveInfo driveInfo; sl@0: r=TheFs.Drive(driveInfo, gDriveNumber); sl@0: test(r==KErrNone); sl@0: sl@0: if((driveInfo.iType==EMediaNANDFlash) && !(driveInfo.iMediaAtt & KMediaAttWriteProtected)) sl@0: { sl@0: TheMetrics = &NandMetrics; sl@0: RDebug::Printf("Using NAND metrics\r\n"); sl@0: } sl@0: else sl@0: { sl@0: TheMetrics = &DefMetrics; sl@0: RDebug::Printf("Using default metrics\r\n"); sl@0: } sl@0: } sl@0: sl@0: FillDiskCycle = 1; sl@0: #ifdef REUSE_THREAD sl@0: gRequestEnd = EFalse; sl@0: #endif sl@0: DoTests(); sl@0: sl@0: } sl@0: