First public contribution.
1 // Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
16 //! @file f32test\concur\t_tdebug.cpp
22 #include "cfafsdlyif.h"
24 TThreadData TTest::iData[KMaxThreads];
25 TThreadData TTest::iDummy;
26 TFullName TTest::iWhere;
27 RMutex TTest::iDebugLock;
28 RMutex TTest::iPrintLock;
29 TBool TTest::iInit = EFalse;
31 LOCAL_C TFileName gErrorPos;
33 // Instance of the class to force initialisation.
36 LOCAL_C TInt KSecond = 1000000;
38 class TTestOverflowTruncate : public TDesOverflow
40 /// Used to suppress overflow when appending formatted text to a buffer.
44 virtual void Overflow(TDes &/*aDes*/) {}
49 // Constructor, forces initialisation of variables.
57 /// Initialise stuff (currently just the locks) if it hasn't been
64 r = iDebugLock.CreateLocal();
67 RDebug::Print(_L("ERROR %d creating iDebugLock\n"), r);
70 r = iPrintLock.CreateLocal();
73 RDebug::Print(_L("ERROR %d creating iPrintLock\n"), r);
81 TInt TTest::Create(TInt aNum, TThreadFunction aFunction, const TDesC& aName)
83 /// Create a thread, setting up the name and our data area.
86 if (aNum < 0 || aNum > KMaxThreads)
88 test.Printf(_L("Illegal thread %d\n"), aNum);
91 TThreadData &d = iData[aNum];
92 // test.Printf(_L("creating thread %d (%S)\n"), aNum, &aName);
93 // d.iThread.LogonCancel(d.iStat);
96 r = d.iThread.Create(aName, aFunction, KDefaultStackSize+32*1024, KMinHeapSize, 0x20000, &d);
100 test.Printf(_L("Error creating thread %d '%S' (was %d '%S'): %S\n"),
101 aNum, &aName, d.iNum, &d.iName, &TTest::ErrStr(r, buf));
104 d.iId = d.iThread.Id();
107 d.iThread.Logon(d.iStat);
111 TInt TTest::RunOnly()
113 /// Resume all of the threads we have created.
117 for (i = 0; i < KMaxThreads; i++)
119 if (iData[i].iId > 0)
121 iData[i].iThread.Resume();
127 TInt TTest::Run(TBool aExitAny, TInt aTimeout)
129 /// Run until all (or any one) threads has completed, or until a timeout.
130 /// @param aExitAny If true, exit when the first thread completes, otherwise
131 /// wait until they have all completed.
132 /// @param aTimeout if zero, no timeout, otherwise it is the timeout in microseconds.
136 TInt status = RunOnly();
138 TRequestStatus tstat;
141 timer.After(tstat, aTimeout);
145 User::WaitForAnyRequest();
146 if (aTimeout > 0 && tstat != KRequestPending)
148 TBool running = EFalse;
149 for (i = 0; i < KMaxThreads; i++)
151 if (iData[i].iId > 0)
153 if (iData[i].iStat == KRequestPending)
159 TThreadData &d = iData[i];
160 // ignore result of LogonCancel, since we know thread has finished
161 d.iThread.LogonCancel(d.iStat);
164 if (d.iStat != KErrNone)
168 test.Printf(_L("ERROR: %S in thread %S: %S\n %S"),
169 &ErrStr(d.iStat.Int(), ebuf), &d.iName, &d.iMess, &iWhere);
187 void TTest::KillAll(TInt aReason)
189 // Kill (destroy) all of the created threads, then wait for up to 10 seconds
190 // for them all to die (and just exit if any are still alive).
193 for (TInt i = 0; i < KMaxThreads; i++)
195 if (iData[i].iId > 0)
197 TThreadData &d = iData[i];
198 d.iThread.Kill(aReason);
201 Run(EFalse, 10*KSecond);
204 TThreadData& TTest::Self()
206 /// Return a reference to the current thread; if it's not one we've created
207 /// return a reference to a dummy data area indicating no thread.
212 for (i = 0; i < KMaxThreads; i++)
214 if (me.Id() == iData[i].iId)
221 iDummy.iName.Format(_L("#%d"), (TUint)me.Id());
225 TThreadData& TTest::Data(TInt aIndex)
227 /// Return a reference to the data area for the specified thread, or to a
228 /// dummy area if it's not in the right range.
230 /// @param aIndex index to the thread (ThreadData::iNum is the same number).
233 if (aIndex >= 0 && aIndex < KMaxThreads)
234 return iData[aIndex];
237 iDummy.iName = _L("");
241 void TTest::Start(const TDesC& aStr)
243 /// Output "START TEST" and the string.
246 Printf(_L("START TEST: %S\n"), &aStr);
249 void TTest::Next(const TDesC& aStr)
251 /// Output "NEXT TEST" and the string.
254 Printf(_L("NEXT TEST: %S\n"), &aStr);
257 void TTest::PrintLock()
259 /// Wait if another task is doing output.
265 void TTest::PrintUnlock()
267 /// Signal that output is complete so that other tasks can do output.
273 void TTest::Printf(TRefByValue<const TDesC> aFmt, ...)
275 /// Output the formatted text, prepending it with the thread name if it is one
276 /// we've created. Parameters as for printf(). Note that if more than one
277 /// thread tries to call it at the same time it will lock so that only one is
278 /// processed at a time, the debug output isn't thread-safe (it can mix
279 /// characters from different threads).
282 TTestOverflowTruncate overflow;
284 VA_START(list, aFmt);
287 if (Self().iNum >= 0)
289 buf.Append(Self().iName);
290 buf.Append(_L(": "));
292 buf.AppendFormatList(aFmt, list, &overflow);
293 #if defined(__WINS__)
294 if (buf.Right(1) != _L("\n"))
295 buf.Append(_L("\n"));
297 if (buf.Right(1) == _L("\n"))
298 buf.SetLength(buf.Length() - 1);
301 RDebug::Print(_L("%S"), &buf);
308 /// Output a blank line, prepended with the thread name if any.
314 void TTest::Fail(TPos aPos, TRefByValue<const TDesC> aFmt, ...)
316 /// Output an error message (formatted as for printf()), then exit the thread.
317 /// The message is placed in the buffer associated with the thread so that
318 /// the parent task can display it.
322 VA_START(list, aFmt);
323 Self().iMess.FormatList(aFmt, list);
325 TPtrC8 ptr((TUint8*)aPos.iFailFile);
327 iWhere.Format(_L(" %S line %d\n"), &gErrorPos, aPos.iFailLine);
328 RDebug::Print(_L("\n"));
329 RDebug::Print(_L("ERROR in thread %S: %S"), &Self().iName, &Self().iMess);
330 RDebug::Print(_L(" %S line %d\n"), &gErrorPos, aPos.iFailLine);
331 RDebug::Print(_L("\n"));
333 User::Exit(KErrAbort);
336 void TTest::Fail(TPos aPos, TInt aErr, TRefByValue<const TDesC> aFmt, ...)
338 /// Output an error message including the interpreted error value followed
339 /// by the specified text (formatted as for printf()), then exit the thread.
340 /// The message is placed in the buffer associated with the thread so that
341 /// the parent task can display it.
345 VA_START(list, aFmt);
348 Self().iMess.FormatList(aFmt, list);
350 TPtrC8 ptr((TUint8*)aPos.iFailFile);
352 iWhere.Format(_L(" %S line %d\n"), &gErrorPos, aPos.iFailLine);
353 RDebug::Print(_L("\n"));
354 RDebug::Print(_L("%S in thread %S: %S"), &ebuf, &Self().iName, &Self().iMess);
355 RDebug::Print(_L(" %S line %d\n"), &gErrorPos, aPos.iFailLine);
356 RDebug::Print(_L("\n"));
361 TDesC& TTest::ErrStr(TInt aErr, TDes& aDes)
363 /// Interpret an error status value as a string in the specified buffer.
364 /// If the value isn't recognised then it formats a string containing the
365 /// value itself (like "Error -65").
366 /// @param aErr The error value.
367 /// @param aDes Descriptor of the buffer to be used.
368 /// @return Descriptor of the buffer.
374 aDes = _L("KErrNone");
377 aDes = _L("KErrNotFound");
380 aDes = _L("KErrGeneral");
383 aDes = _L("KErrCancel");
386 aDes = _L("KErrNoMemory");
388 case KErrNotSupported:
389 aDes = _L("KErrNotSupported");
392 aDes = _L("KErrArgument");
394 case KErrTotalLossOfPrecision:
395 aDes = _L("KErrTotalLossOfPrecision");
398 aDes = _L("KErrBadHandle");
401 aDes = _L("KErrOverflow");
404 aDes = _L("KErrUnderflow");
406 case KErrAlreadyExists:
407 aDes = _L("KErrAlreadyExists");
409 case KErrPathNotFound:
410 aDes = _L("KErrPathNotFound");
413 aDes = _L("KErrDied");
416 aDes = _L("KErrInUse");
418 case KErrServerTerminated:
419 aDes = _L("KErrServerTerminated");
422 aDes = _L("KErrServerBusy");
425 aDes = _L("KErrCompletion");
428 aDes = _L("KErrNotReady");
431 aDes = _L("KErrUnknown");
434 aDes = _L("KErrCorrupt");
436 case KErrAccessDenied:
437 aDes = _L("KErrAccessDenied");
440 aDes = _L("KErrLocked");
443 aDes = _L("KErrWrite");
446 aDes = _L("KErrDisMounted");
449 aDes = _L("KErrEof");
452 aDes = _L("KErrDiskFull");
455 aDes = _L("KErrBadDriver");
458 aDes = _L("KErrBadName");
460 case KErrCommsLineFail:
461 aDes = _L("KErrCommsLineFail");
464 aDes = _L("KErrCommsFrame");
466 case KErrCommsOverrun:
467 aDes = _L("KErrCommsOverrun");
469 case KErrCommsParity:
470 aDes = _L("KErrCommsParity");
473 aDes = _L("KErrTimedOut");
475 case KErrCouldNotConnect:
476 aDes = _L("KErrCouldNotConnect");
478 case KErrCouldNotDisconnect:
479 aDes = _L("KErrCouldNotDisconnect");
481 case KErrDisconnected:
482 aDes = _L("KErrDisconnected");
484 case KErrBadLibraryEntryPoint:
485 aDes = _L("KErrBadLibraryEntryPoint");
487 case KErrBadDescriptor:
488 aDes = _L("KErrBadDescriptor");
491 aDes = _L("KErrAbort");
494 aDes = _L("KErrTooBig");
496 case KErrDivideByZero:
497 aDes = _L("KErrDivideByZero");
500 aDes = _L("KErrBadPower");
503 aDes = _L("KErrDirFull");
505 case KErrHardwareNotAvailable:
506 aDes = _L("KErrHardwareNotAvailable");
508 case KErrSessionClosed:
509 aDes = _L("KErrSessionClosed");
511 case KErrPermissionDenied:
512 aDes = _L("KErrPermissionDenied");
514 case KRequestPending:
515 aDes = _L("KRequestPending");
519 aDes.AppendNum(aErr);
525 TInt TTest::ParseCommandArguments(TPtrC aArgV[], TInt aArgMax)
527 /// Parse command line. Put the parameters into array aArgv for
528 /// use by the tests, strip out flags starting with / or - and interpret
529 /// them to set debug flags.
533 TInt r = fs.Connect();
536 TInt argc = ParseCommandArguments(aArgV, aArgMax, flags);
537 fs.SetDebugRegister(flags);
542 TInt TTest::ParseCommandArguments(TPtrC aArgV[], TInt aArgMax, TInt& aDebugFlags)
544 /// Parse command line. Put the parameters into array aArgv for
545 /// use by the tests, strip out flags starting with / or - and interpret
546 /// them to set debug flags.
549 LOCAL_D TBuf<0x100> cmd;
550 User::CommandLine(cmd);
552 TPtrC token=lex.NextToken();
553 TFileName thisfile=RProcess().FileName();
554 if (token.MatchF(thisfile)==0)
556 token.Set(lex.NextToken());
558 // set up parameter list (offset zero is the filename)
560 aArgV[argc++].Set(thisfile);
561 while (token.Length() != 0)
564 // strip out (and interpret) flags starting with - or /
565 if (ch == '-' || ch == '/')
567 for (TInt i = 1; i < token.Length(); i++)
569 switch (User::UpperCase(token[i]))
572 aDebugFlags |= KDLYFAST;
575 aDebugFlags |= KFSYS;
578 aDebugFlags |= KISO9660;
581 aDebugFlags |= KFLDR;
583 #ifdef __CONCURRENT_FILE_ACCESS__
585 aDebugFlags |= KTHRD;
589 aDebugFlags |= KNTFS;
592 aDebugFlags |= KFSERV;
595 aDebugFlags |= KLFFS;
598 aDebugFlags |= KDLYTRC;
603 else if (argc < aArgMax)
604 aArgV[argc++].Set(token);
605 token.Set(lex.NextToken());
610 TChar TTest::DefaultDriveChar()
615 fs.SessionPath(session);
617 TChar drvch = User::UpperCase(session[0]);
621 TTest::TPos::TPos(const char *aFile, TInt aLine)