kerneltest/e32test/nkernsa/fastmutex.cpp
changeset 0 a41df078684a
child 90 947f0dc9f7a8
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 2006-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".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // e32test\nkernsa\fastmutex.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 #include <nktest/nkutils.h>
       
    19 
       
    20 const TInt KReadCount = 100000;
       
    21 //const TInt KReadCount = 2000000;
       
    22 #ifdef __CPU_ARM
       
    23 const TUint32 KTickLimit = (KReadCount>100000) ? (((TUint32)KReadCount)/10*18) : 180000u;
       
    24 #else
       
    25 const TUint32 KTickLimit = (KReadCount>100000) ? (((TUint32)KReadCount)/10*6) : 60000u;
       
    26 #endif
       
    27 
       
    28 class NFastMutexX
       
    29 	{
       
    30 public:
       
    31 	TInt iRefCount;
       
    32 	NFastMutex* iMutex;
       
    33 public:
       
    34 	NFastMutexX();
       
    35 	~NFastMutexX();
       
    36 	void Create();
       
    37 	TBool Open();
       
    38 	TBool Close();
       
    39 	TBool Wait();
       
    40 	TBool Signal();
       
    41 	TBool WaitFull();
       
    42 	TBool SignalFull();
       
    43 	};
       
    44 
       
    45 NFastMutexX::NFastMutexX()
       
    46 	:	iRefCount(0), iMutex(0)
       
    47 	{}
       
    48 
       
    49 void NFastMutexX::Create()
       
    50 	{
       
    51 	iMutex = new NFastMutex;
       
    52 	TEST_OOM(iMutex);
       
    53 	__e32_atomic_store_rel32(&iRefCount, 1);
       
    54 	}
       
    55 
       
    56 NFastMutexX::~NFastMutexX()
       
    57 	{
       
    58 	TEST_RESULT2(iRefCount==0, "Bad mutex ref count %d %08x", iRefCount, this);
       
    59 	memset(this, 0xbf, sizeof(*this));
       
    60 	}
       
    61 
       
    62 TBool NFastMutexX::Open()
       
    63 	{
       
    64 	return __e32_atomic_tas_ord32(&iRefCount, 1, 1, 0) >  0;
       
    65 	}
       
    66 
       
    67 TBool NFastMutexX::Close()
       
    68 	{
       
    69 	TInt r = __e32_atomic_tas_ord32(&iRefCount, 1, -1, 0);
       
    70 	if (r==1)
       
    71 		{
       
    72 		memset(iMutex, 0xbf, sizeof(NFastMutex));
       
    73 		delete iMutex;
       
    74 		iMutex = 0;
       
    75 		}
       
    76 	return r==1;
       
    77 	}
       
    78 
       
    79 TBool NFastMutexX::Wait()
       
    80 	{
       
    81 	if (Open())
       
    82 		{
       
    83 		NKern::FMWait(iMutex);
       
    84 		return TRUE;
       
    85 		}
       
    86 	return FALSE;
       
    87 	}
       
    88 
       
    89 TBool NFastMutexX::Signal()
       
    90 	{
       
    91 	NKern::FMSignal(iMutex);
       
    92 	return Close();
       
    93 	}
       
    94 
       
    95 TBool NFastMutexX::WaitFull()
       
    96 	{
       
    97 	if (Open())
       
    98 		{
       
    99 		FMWaitFull(iMutex);
       
   100 		return TRUE;
       
   101 		}
       
   102 	return FALSE;
       
   103 	}
       
   104 
       
   105 TBool NFastMutexX::SignalFull()
       
   106 	{
       
   107 	FMSignalFull(iMutex);
       
   108 	return Close();
       
   109 	}
       
   110 
       
   111 void FMTest0()
       
   112 	{
       
   113 	TEST_PRINT("Testing non-contention case");
       
   114 
       
   115 	NFastMutex m;
       
   116 
       
   117 	TEST_RESULT(!m.HeldByCurrentThread(), "Mutex held by current thread");
       
   118 	TEST_RESULT(!NKern::HeldFastMutex(), "Current thread holds a fast mutex");
       
   119 
       
   120 	NKern::FMWait(&m);
       
   121 
       
   122 	TEST_RESULT(m.HeldByCurrentThread(), "Mutex not held by current thread");
       
   123 	TEST_RESULT(NKern::HeldFastMutex()==&m, "HeldFastMutex() incorrect");
       
   124 
       
   125 	NKern::FMSignal(&m);
       
   126 
       
   127 	TEST_RESULT(!m.HeldByCurrentThread(), "Mutex held by current thread");
       
   128 	TEST_RESULT(!NKern::HeldFastMutex(), "Current thread holds a fast mutex");
       
   129 	}
       
   130 
       
   131 struct SFMTest1Info
       
   132 	{
       
   133 	NFastMutex iMutex;
       
   134 	volatile TUint32* iBlock;
       
   135 	TInt iBlockSize;	// words
       
   136 	TInt iPriorityThreshold;
       
   137 	volatile TBool iStop;
       
   138 	NThread* iThreads[3*KMaxCpus];
       
   139 	};
       
   140 
       
   141 void FMTest1Thread(TAny* a)
       
   142 	{
       
   143 	SFMTest1Info& info = *(SFMTest1Info*)a;
       
   144 	NThread* pC = NKern::CurrentThread();
       
   145 	TUint32 seed[2] = {(TUint32)pC, 0};
       
   146 	TBool wait = (pC->iPriority > info.iPriorityThreshold);
       
   147 	TBool thread0 = (pC==info.iThreads[0]);
       
   148 	TInt n = 0;
       
   149 	while (!info.iStop)
       
   150 		{
       
   151 		if (thread0)
       
   152 			NKern::ThreadSetPriority(pC, 11);
       
   153 		NKern::FMWait(&info.iMutex);
       
   154 		TBool ok = verify_block((TUint32*)info.iBlock, info.iBlockSize);
       
   155 		TEST_RESULT(ok, "Block corrupt");
       
   156 		++info.iBlock[0];
       
   157 		setup_block((TUint32*)info.iBlock, info.iBlockSize);
       
   158 		++n;
       
   159 		NKern::FMSignal(&info.iMutex);
       
   160 		if (wait)
       
   161 			{
       
   162 			TUint32 x = random(seed) & 1;
       
   163 			NKern::Sleep(x+1);
       
   164 			}
       
   165 		}
       
   166 	TEST_PRINT2("Thread %T ran %d times", pC, n);
       
   167 	}
       
   168 
       
   169 void FMTest1PInterfererThread(TAny* a)
       
   170 	{
       
   171 	SFMTest1Info& info = *(SFMTest1Info*)a;
       
   172 	NThread* pC = NKern::CurrentThread();
       
   173 	TEST_PRINT1("Thread %T start", pC);
       
   174 	TUint32 seed[2] = {(TUint32)pC, 0};
       
   175 	NThread* t0 = info.iThreads[0];
       
   176 	TInt n = 0;
       
   177 	while (!__e32_atomic_load_acq32(&info.iStop))
       
   178 		{
       
   179 		while (!__e32_atomic_load_acq32(&info.iStop) && t0->iPriority != 11)
       
   180 			__chill();
       
   181 		TUint32 x = random(seed) & 2047;
       
   182 		while(x)
       
   183 			{
       
   184 			__e32_atomic_add_ord32(&x, TUint32(-1));
       
   185 			}
       
   186 		if (__e32_atomic_load_acq32(&info.iStop))
       
   187 			break;
       
   188 		NKern::ThreadSetPriority(t0, 9);
       
   189 		++n;
       
   190 		}
       
   191 	TEST_PRINT2("Thread %T ran %d times", pC, n);
       
   192 	}
       
   193 
       
   194 void FMTest1()
       
   195 	{
       
   196 	TEST_PRINT("Testing mutual exclusion");
       
   197 
       
   198 	NFastSemaphore exitSem(0);
       
   199 	SFMTest1Info* pI = new SFMTest1Info;
       
   200 	TEST_OOM(pI);
       
   201 	memclr(pI, sizeof(SFMTest1Info));
       
   202 	pI->iBlockSize = 256;
       
   203 	pI->iBlock = (TUint32*)malloc(pI->iBlockSize*sizeof(TUint32));
       
   204 	TEST_OOM(pI->iBlock);
       
   205 	pI->iPriorityThreshold = 10;
       
   206 	pI->iBlock[0] = 0;
       
   207 	setup_block((TUint32*)pI->iBlock, pI->iBlockSize);
       
   208 	pI->iStop = FALSE;
       
   209 	TInt cpu;
       
   210 	TInt threads = 0;
       
   211 	for_each_cpu(cpu)
       
   212 		{
       
   213 		CreateThreadSignalOnExit("FMTest1H", &FMTest1Thread, 11, pI, 0, KSmallTimeslice, &exitSem, cpu);
       
   214 		CreateThreadSignalOnExit("FMTest1L0", &FMTest1Thread, 10, pI, 0, KSmallTimeslice, &exitSem, cpu);
       
   215 		CreateThreadSignalOnExit("FMTest1L1", &FMTest1Thread, 10, pI, 0, KSmallTimeslice, &exitSem, cpu);
       
   216 		threads += 3;
       
   217 		}
       
   218 	FOREVER
       
   219 		{
       
   220 		NKern::Sleep(1000);
       
   221 		TEST_PRINT1("%d", pI->iBlock[0]);
       
   222 		if (pI->iBlock[0] > 65536)
       
   223 			{
       
   224 			pI->iStop = TRUE;
       
   225 			break;
       
   226 			}
       
   227 		}
       
   228 	while (threads--)
       
   229 		NKern::FSWait(&exitSem);
       
   230 	TEST_PRINT1("Total iterations %d", pI->iBlock[0]);
       
   231 	free((TAny*)pI->iBlock);
       
   232 	free(pI);
       
   233 	}
       
   234 
       
   235 void FMTest1P()
       
   236 	{
       
   237 	TEST_PRINT("Testing priority change");
       
   238 	if (NKern::NumberOfCpus()==1)
       
   239 		return;
       
   240 
       
   241 	NFastSemaphore exitSem(0);
       
   242 	SFMTest1Info* pI = new SFMTest1Info;
       
   243 	TEST_OOM(pI);
       
   244 	memclr(pI, sizeof(SFMTest1Info));
       
   245 	TEST_PRINT1("Info@0x%08x", pI);
       
   246 	pI->iBlockSize = 256;
       
   247 	pI->iBlock = (TUint32*)malloc(pI->iBlockSize*sizeof(TUint32));
       
   248 	TEST_OOM(pI->iBlock);
       
   249 	pI->iPriorityThreshold = 9;
       
   250 	pI->iBlock[0] = 0;
       
   251 	setup_block((TUint32*)pI->iBlock, pI->iBlockSize);
       
   252 	pI->iStop = FALSE;
       
   253 	TInt cpu;
       
   254 	TInt threadCount = 0;
       
   255 	TInt pri = 9;
       
   256 	char name[16] = "FMTest1P.0";
       
   257 	for_each_cpu(cpu)
       
   258 		{
       
   259 		name[9] = (char)(threadCount + '0');
       
   260 		if (cpu==1)
       
   261 			pI->iThreads[threadCount] = CreateThreadSignalOnExit("FMTest1PInterferer", &FMTest1PInterfererThread, 12, pI, 0, KSmallTimeslice, &exitSem, 1);
       
   262 		else
       
   263 			pI->iThreads[threadCount] = CreateThreadSignalOnExit(name, &FMTest1Thread, pri, pI, 0, KSmallTimeslice, &exitSem, cpu);
       
   264 		pri = 10;
       
   265 		threadCount++;
       
   266 		}
       
   267 	TUint32 b0 = 0xffffffffu;
       
   268 	FOREVER
       
   269 		{
       
   270 		NKern::Sleep(1000);
       
   271 		TUint32 b = pI->iBlock[0];
       
   272 		TEST_PRINT1("%d", b);
       
   273 		if (b > 1048576)
       
   274 			{
       
   275 			pI->iStop = TRUE;
       
   276 			break;
       
   277 			}
       
   278 		if (b == b0)
       
   279 			{
       
   280 			__crash();
       
   281 			}
       
   282 		b0 = b;
       
   283 		}
       
   284 	while (threadCount--)
       
   285 		NKern::FSWait(&exitSem);
       
   286 	TEST_PRINT1("Total iterations %d", pI->iBlock[0]);
       
   287 	free((TAny*)pI->iBlock);
       
   288 	free(pI);
       
   289 	}
       
   290 
       
   291 struct SFMTest2InfoC
       
   292 	{
       
   293 	NFastMutex iMutex;
       
   294 	TInt iMax;
       
   295 	TBool iStop;
       
   296 	};
       
   297 
       
   298 struct SFMTest2InfoT
       
   299 	{
       
   300 	SFMTest2InfoC* iCommon;
       
   301 	TUint32 iMaxDelay;
       
   302 	TInt iIterations;
       
   303 	TUint32 iSpinTime;
       
   304 	TUint32 iBlockTimeMask;
       
   305 	TUint32 iBlockTimeOffset;
       
   306 	NThread* iThread;
       
   307 	union {
       
   308 		TUint8 iSpoiler;
       
   309 		TUint32 iDelayThreshold;
       
   310 		};
       
   311 	};
       
   312 
       
   313 TBool StopTest = FALSE;
       
   314 
       
   315 void FMTest2Thread(TAny* a)
       
   316 	{
       
   317 	SFMTest2InfoT& t = *(SFMTest2InfoT*)a;
       
   318 	SFMTest2InfoC& c = *t.iCommon;
       
   319 	NThreadBase* pC = NKern::CurrentThread();
       
   320 	TUint32 seed[2] = {(TUint32)pC, 0};
       
   321 	while (!c.iStop)
       
   322 		{
       
   323 		++t.iIterations;
       
   324 		if (t.iSpoiler)
       
   325 			{
       
   326 			nfcfspin(t.iSpinTime);
       
   327 			}
       
   328 		else
       
   329 			{
       
   330 			TUint32 initial = norm_fast_counter();
       
   331 			NKern::FMWait(&c.iMutex);
       
   332 			TUint32 final = norm_fast_counter();
       
   333 			TUint32 delay = final - initial;
       
   334 			if (delay > t.iMaxDelay)
       
   335 				{
       
   336 				t.iMaxDelay = delay;
       
   337 				__e32_atomic_add_ord32(&c.iMax, 1);
       
   338 				if (delay > t.iDelayThreshold)
       
   339 					__crash();
       
   340 				}
       
   341 			nfcfspin(t.iSpinTime);
       
   342 			NKern::FMSignal(&c.iMutex);
       
   343 			}
       
   344 		if (t.iBlockTimeMask)
       
   345 			{
       
   346 			TUint32 sleep = (random(seed) & t.iBlockTimeMask) + t.iBlockTimeOffset;
       
   347 			NKern::Sleep(sleep);
       
   348 			}
       
   349 		}
       
   350 	TEST_PRINT3("Thread %T %d iterations, max delay %d", pC, t.iIterations, t.iMaxDelay);
       
   351 	}
       
   352 
       
   353 SFMTest2InfoT* CreateFMTest2Thread(	const char* aName,
       
   354 									SFMTest2InfoC& aCommon,
       
   355 									TUint32 aSpinTime,
       
   356 									TUint32 aBlockTimeMask,
       
   357 									TUint32 aBlockTimeOffset,
       
   358 									TBool aSpoiler,
       
   359 									TInt aPri,
       
   360 									TInt aTimeslice,
       
   361 									NFastSemaphore& aExitSem,
       
   362 									TUint32 aCpu
       
   363 								  )
       
   364 	{
       
   365 	SFMTest2InfoT* ti = new SFMTest2InfoT;
       
   366 	TEST_OOM(ti);
       
   367 	ti->iCommon = &aCommon;
       
   368 	ti->iMaxDelay = 0;
       
   369 	ti->iDelayThreshold = 0xffffffffu;
       
   370 	ti->iIterations = 0;
       
   371 	ti->iSpinTime = aSpinTime;
       
   372 	ti->iBlockTimeMask = aBlockTimeMask;
       
   373 	ti->iBlockTimeOffset = aBlockTimeOffset;
       
   374 	ti->iSpoiler = (TUint8)aSpoiler;
       
   375 	ti->iThread = 0;
       
   376 
       
   377 	NThread* t = CreateUnresumedThreadSignalOnExit(aName, &FMTest2Thread, aPri, ti, 0, aTimeslice, &aExitSem, aCpu);
       
   378 	ti->iThread = t;
       
   379 	DEBUGPRINT("Thread at %08x, Info at %08x", t, ti);
       
   380 
       
   381 	return ti;
       
   382 	}
       
   383 
       
   384 extern void DebugPrint(const char*, int);
       
   385 void FMTest2()
       
   386 	{
       
   387 	TEST_PRINT("Testing priority inheritance");
       
   388 
       
   389 	NFastSemaphore exitSem(0);
       
   390 	SFMTest2InfoC common;
       
   391 	common.iMax = 0;
       
   392 	common.iStop = FALSE;
       
   393 	TInt cpu;
       
   394 	TInt threads = 0;
       
   395 	SFMTest2InfoT* tinfo[32];
       
   396 	memset(tinfo, 0, sizeof(tinfo));
       
   397 	DEBUGPRINT("Common info at %08x", &common);
       
   398 	for_each_cpu(cpu)
       
   399 		{
       
   400 		tinfo[threads++] = CreateFMTest2Thread("FMTest2H", common, 500, 7, 7, FALSE, 60-cpu, KSmallTimeslice, exitSem, cpu);
       
   401 		tinfo[threads++] = CreateFMTest2Thread("FMTest2L", common, 500, 0, 0, FALSE, 11, KSmallTimeslice, exitSem, cpu);
       
   402 		tinfo[threads++] = CreateFMTest2Thread("FMTest2S", common, 10000, 15, 31, TRUE, 32, -1, exitSem, cpu);
       
   403 		}
       
   404 	tinfo[0]->iDelayThreshold = 0x300;
       
   405 	TInt max = 0;
       
   406 	TInt i;
       
   407 	TInt iter = 0;
       
   408 	for (i=0; i<threads; ++i)
       
   409 		{
       
   410 		NKern::ThreadResume(tinfo[i]->iThread);
       
   411 		}
       
   412 	FOREVER
       
   413 		{
       
   414 		NKern::Sleep(5000);
       
   415 		DebugPrint(".",1);	// only print one char since interrupts are disabled for entire time
       
   416 
       
   417 		TInt max_now = common.iMax;
       
   418 		if (max_now==max)
       
   419 			{
       
   420 			if (++iter==20)
       
   421 				break;
       
   422 			}
       
   423 		else
       
   424 			{
       
   425 			iter = 0;
       
   426 			max = max_now;
       
   427 			}
       
   428 		}
       
   429 	common.iStop = TRUE;
       
   430 	for (i=0; i<threads; ++i)
       
   431 		NKern::FSWait(&exitSem);
       
   432 	DebugPrint("\r\n",2);
       
   433 	for (i=0; i<threads; ++i)
       
   434 		{
       
   435 		TEST_PRINT3("%d: Iter %10d Max %10d", i, tinfo[i]->iIterations, tinfo[i]->iMaxDelay);
       
   436 		if (i==0)
       
   437 			{
       
   438 			TEST_RESULT(tinfo[0]->iMaxDelay < 700, "Thread 0 MaxDelay too high");
       
   439 			}
       
   440 		else if (i==3)
       
   441 			{
       
   442 			TEST_RESULT(tinfo[3]->iMaxDelay < 1200, "Thread 1 MaxDelay too high");
       
   443 			}
       
   444 		}
       
   445 	for (i=0; i<threads; ++i)
       
   446 		delete tinfo[i];
       
   447 	}
       
   448 
       
   449 struct SWriterInfo
       
   450 	{
       
   451 	void DoInOp(TUint aWhich);
       
   452 	void DoOutOp(TUint aWhich);
       
   453 
       
   454 	TUint32* iBuf[6];
       
   455 	TInt iWords;
       
   456 	volatile TUint32 iWrites;
       
   457 	volatile TUint32 iIn;
       
   458 	volatile TBool iStop;
       
   459 	NFastMutex* iM;
       
   460 	NFastMutexX* iMX;
       
   461 	TUint32 iInSeq;		// do nibble 0 followed by nibble 1 followed by nibble 2
       
   462 	TUint32 iOutSeq;	// 0=nothing, 1=mutex, 2=freeze, 3=CS, 4=mutex the long way
       
   463 						// 5 = mutexX, 6 = mutexX the long way, 7=join frozen group
       
   464 						// 8 = join mutex-holding group, 9=join idle group
       
   465 	TInt iFrz;
       
   466 	TInt iPriority;
       
   467 	TInt iTimeslice;
       
   468 	TInt iCpu;
       
   469 	NFastSemaphore iHandshake;
       
   470 	TUint64 iInitFastCounter;
       
   471 	TUint32 iFastCounterDelta;
       
   472 	NThread* volatile iIvThrd;
       
   473 
       
   474 #ifdef __SMP__
       
   475 	NThreadGroup* iGroup;
       
   476 #endif
       
   477 	};
       
   478 
       
   479 void SWriterInfo::DoInOp(TUint aWhich)
       
   480 	{
       
   481 	switch ((iInSeq>>(aWhich*4))&0xf)
       
   482 		{
       
   483 		case 0:	break;
       
   484 		case 1:	NKern::FMWait(iM); break;
       
   485 		case 2: iFrz=NKern::FreezeCpu(); break;
       
   486 		case 3: NKern::ThreadEnterCS(); break;
       
   487 		case 4: FMWaitFull(iM); break;
       
   488 		case 5: iMX->Wait(); break;
       
   489 		case 6: iMX->WaitFull(); break;
       
   490 #ifdef __SMP__
       
   491 		case 7:
       
   492 		case 8:
       
   493 		case 9:	NKern::JoinGroup(iGroup); break;
       
   494 #endif
       
   495 		}
       
   496 	}
       
   497 
       
   498 void SWriterInfo::DoOutOp(TUint aWhich)
       
   499 	{
       
   500 	switch ((iOutSeq>>(aWhich*4))&0xf)
       
   501 		{
       
   502 		case 0:	break;
       
   503 		case 1:	NKern::FMSignal(iM); break;
       
   504 		case 2: NKern::EndFreezeCpu(iFrz); break;
       
   505 		case 3: NKern::ThreadLeaveCS(); break;
       
   506 		case 4: FMSignalFull(iM); break;
       
   507 		case 5: iMX->Signal(); break;
       
   508 		case 6: iMX->SignalFull(); break;
       
   509 #ifdef __SMP__
       
   510 		case 7:
       
   511 		case 8:
       
   512 		case 9:	NKern::LeaveGroup(); break;
       
   513 #endif
       
   514 		}
       
   515 	}
       
   516 
       
   517 struct SReaderInfo
       
   518 	{
       
   519 	enum TTestType
       
   520 		{
       
   521 		ETimeslice,
       
   522 		ESuspend,
       
   523 		EKill,
       
   524 		EMigrate,
       
   525 		EInterlockedSuspend,
       
   526 		EInterlockedKill,
       
   527 		EInterlockedMigrate,
       
   528 		EMutexLifetime,
       
   529 		};
       
   530 
       
   531 	TUint32* iBuf[6];
       
   532 	TInt iWords;
       
   533 	volatile TUint32 iReads;
       
   534 	volatile TUint32 iFails[7];
       
   535 	volatile TBool iStop;
       
   536 	TUint32 iReadLimit;
       
   537 	NThread* volatile iWriter;
       
   538 	NThread* volatile iReader;
       
   539 	NThread* volatile iIvThrd;
       
   540 	NThread* iGroupThrd;
       
   541 	SWriterInfo* iWriterInfo;
       
   542 	TInt iTestType;
       
   543 	NFastSemaphore iExitSem;
       
   544 	volatile TUint32 iCapturedIn;
       
   545 	volatile TBool iSuspendResult;
       
   546 	};
       
   547 
       
   548 void WriterThread(TAny* a)
       
   549 	{
       
   550 	SWriterInfo& info = *(SWriterInfo*)a;
       
   551 //	TEST_PRINT(">WR");
       
   552 
       
   553 	while (!info.iStop)
       
   554 		{
       
   555 		NThread* t = (NThread*)__e32_atomic_swp_ord_ptr(&info.iIvThrd, 0);
       
   556 		if (t)
       
   557 			NKern::ThreadRequestSignal(t);
       
   558 		if (!info.iFastCounterDelta)
       
   559 			info.iInitFastCounter = fast_counter();
       
   560 		TInt n = ++info.iWrites;
       
   561 
       
   562 		info.DoInOp(0);
       
   563 
       
   564 		info.iBuf[0][0] = n;
       
   565 		setup_block_cpu(info.iBuf[0], info.iWords);
       
   566 
       
   567 		info.DoInOp(1);
       
   568 
       
   569 		info.iBuf[1][0] = n;
       
   570 		setup_block_cpu(info.iBuf[1], info.iWords);
       
   571 
       
   572 		info.DoInOp(2);
       
   573 
       
   574 		if (NKern::CurrentCpu() == info.iCpu)
       
   575 			++info.iIn;
       
   576 		info.iBuf[2][0] = n;
       
   577 		setup_block_cpu(info.iBuf[2], info.iWords);
       
   578 
       
   579 		info.DoOutOp(0);
       
   580 
       
   581 		info.iBuf[3][0] = n;
       
   582 		setup_block_cpu(info.iBuf[3], info.iWords);
       
   583 
       
   584 		info.DoOutOp(1);
       
   585 
       
   586 		info.iBuf[4][0] = n;
       
   587 		setup_block_cpu(info.iBuf[4], info.iWords);
       
   588 
       
   589 		info.DoOutOp(2);
       
   590 
       
   591 		info.iBuf[5][0] = n;
       
   592 		setup_block_cpu(info.iBuf[5], info.iWords);
       
   593 
       
   594 		if (!info.iFastCounterDelta)
       
   595 			info.iFastCounterDelta = (TUint32)(fast_counter() - info.iInitFastCounter);
       
   596 		if (NKern::CurrentCpu() != info.iCpu)
       
   597 			{
       
   598 			NKern::FSSignal(&info.iHandshake);
       
   599 			NKern::WaitForAnyRequest();
       
   600 			}
       
   601 		}
       
   602 //	TEST_PRINT("<WR");
       
   603 	}
       
   604 
       
   605 void ReaderThread(TAny* a)
       
   606 	{
       
   607 	SReaderInfo& info = *(SReaderInfo*)a;
       
   608 	SWriterInfo& winfo = *info.iWriterInfo;
       
   609 	TInt this_cpu = NKern::CurrentCpu();
       
   610 	NThread* pC = NKern::CurrentThread();
       
   611 	info.iReader = pC;
       
   612 //	TInt my_pri = pC->i_NThread_BasePri;
       
   613 	TBool create_writer = TRUE;
       
   614 	NKern::FSSetOwner(&winfo.iHandshake, 0);
       
   615 	NFastSemaphore exitSem(0);
       
   616 	TUint32 seed[2] = {0,7};
       
   617 	TUint32 modulus = 0;
       
   618 	TUint32 offset = 0;
       
   619 //	TEST_PRINT1(">RD%d",info.iTestType);
       
   620 
       
   621 	while (!info.iStop)
       
   622 		{
       
   623 		TInt i;
       
   624 		if (create_writer)
       
   625 			goto do_create_writer;
       
   626 		if (info.iTestType==SReaderInfo::EMigrate || info.iTestType==SReaderInfo::EInterlockedMigrate)
       
   627 			{
       
   628 			NKern::FSWait(&winfo.iHandshake);
       
   629 			}
       
   630 		for (i=0; i<6; ++i)
       
   631 			{
       
   632 			TInt cpu = verify_block_cpu_no_trace(info.iBuf[i], info.iWords);
       
   633 			if (cpu<0)
       
   634 				++info.iFails[i];
       
   635 			}
       
   636 		++info.iReads;
       
   637 		switch (info.iTestType)
       
   638 			{
       
   639 			case SReaderInfo::ETimeslice:
       
   640 				NKern::ThreadSetTimeslice(info.iWriter, (random(seed) % modulus + offset) );
       
   641 				NKern::YieldTimeslice();
       
   642 				break;
       
   643 			case SReaderInfo::ESuspend:
       
   644 				winfo.iIvThrd = info.iIvThrd;
       
   645 				NKern::ThreadResume(info.iWriter);
       
   646 				break;
       
   647 			case SReaderInfo::EKill:
       
   648 				NKern::FSWait(&exitSem);
       
   649 				create_writer = TRUE;
       
   650 				break;
       
   651 			case SReaderInfo::EMigrate:
       
   652 				NKern::ThreadSetCpuAffinity(info.iWriter, this_cpu);
       
   653 				if (info.iGroupThrd)
       
   654 					NKern::ThreadSetCpuAffinity(info.iGroupThrd, this_cpu);
       
   655 				NKern::ThreadRequestSignal(info.iIvThrd);
       
   656 				NKern::ThreadRequestSignal(info.iWriter);
       
   657 				break;
       
   658 			case SReaderInfo::EInterlockedSuspend:
       
   659 				NKern::WaitForAnyRequest();
       
   660 				NKern::FMWait(winfo.iM);
       
   661 				if (winfo.iIn != info.iCapturedIn && info.iSuspendResult)
       
   662 					++info.iFails[6];
       
   663 				winfo.iIvThrd = info.iIvThrd;
       
   664 				NKern::ThreadResume(info.iWriter, winfo.iM);
       
   665 				break;
       
   666 			case SReaderInfo::EInterlockedKill:
       
   667 				NKern::WaitForAnyRequest();
       
   668 				NKern::FSWait(&exitSem);
       
   669 				if (winfo.iIn != info.iCapturedIn)
       
   670 					++info.iFails[6];
       
   671 				create_writer = TRUE;
       
   672 				break;
       
   673 			case SReaderInfo::EInterlockedMigrate:
       
   674 				NKern::WaitForAnyRequest();
       
   675 				if (winfo.iIn != info.iCapturedIn)
       
   676 					++info.iFails[6];
       
   677 				NKern::ThreadSetCpuAffinity(info.iWriter, this_cpu);
       
   678 				if (info.iGroupThrd)
       
   679 					NKern::ThreadSetCpuAffinity(info.iGroupThrd, this_cpu);
       
   680 				NKern::ThreadRequestSignal(info.iIvThrd);
       
   681 				NKern::ThreadRequestSignal(info.iWriter);
       
   682 				break;
       
   683 			}
       
   684 do_create_writer:
       
   685 		if (create_writer)
       
   686 			{
       
   687 			create_writer = FALSE;
       
   688 			winfo.iCpu = this_cpu;
       
   689 			info.iWriter = CreateUnresumedThreadSignalOnExit("Writer", &WriterThread, winfo.iPriority, &winfo, 0, winfo.iTimeslice, &exitSem, this_cpu);
       
   690 			TEST_OOM(info.iWriter);
       
   691 			winfo.iIvThrd = info.iIvThrd;
       
   692 			NKern::ThreadResume(info.iWriter);
       
   693 			while (!winfo.iFastCounterDelta)
       
   694 				NKern::Sleep(1);
       
   695 			modulus = __fast_counter_to_timeslice_ticks(3*winfo.iFastCounterDelta);
       
   696 //			offset = __microseconds_to_timeslice_ticks(64);
       
   697 			offset = 1;
       
   698 			}
       
   699 		}
       
   700 	winfo.iStop = TRUE;
       
   701 	NKern::FSWait(&exitSem);
       
   702 //	TEST_PRINT1("<RD%d",info.iTestType);
       
   703 	}
       
   704 
       
   705 void InterventionThread(TAny* a)
       
   706 	{
       
   707 	SReaderInfo& info = *(SReaderInfo*)a;
       
   708 	SWriterInfo& winfo = *info.iWriterInfo;
       
   709 	TInt this_cpu = NKern::CurrentCpu();
       
   710 	TUint32 seed[2] = {1,0};
       
   711 	while (!winfo.iFastCounterDelta)
       
   712 		NKern::Sleep(1);
       
   713 	TUint32 modulus = 3*winfo.iFastCounterDelta;
       
   714 	TUint32 offset = TUint32(fast_counter_freq() / TUint64(100000));
       
   715 	NThread* w = info.iWriter;
       
   716 	TUint32 lw = 0;
       
   717 	TUint32 tc = NKern::TickCount();
       
   718 	NKern::FSSetOwner(&info.iExitSem, 0);
       
   719 
       
   720 	TEST_PRINT3(">IV%d %d %d", info.iTestType, modulus, offset);
       
   721 	FOREVER
       
   722 		{
       
   723 		if (this_cpu == winfo.iCpu)
       
   724 			{
       
   725  			NKern::Sleep(1);
       
   726 			}
       
   727 		else
       
   728 			{
       
   729 			TUint32 count = random(seed) % modulus;
       
   730 			count += offset;
       
   731 			fcfspin(count);
       
   732 			}
       
   733 		if (info.iReads >= info.iReadLimit)
       
   734 			{
       
   735 			info.iStop = TRUE;
       
   736 			winfo.iStop = TRUE;
       
   737 			NKern::FSWait(&info.iExitSem);
       
   738 			break;
       
   739 			}
       
   740 		if (winfo.iWrites >= lw + 3*info.iReadLimit)
       
   741 			{
       
   742 			lw += 3*info.iReadLimit;
       
   743 			TEST_PRINT1("#W=%d",winfo.iWrites);
       
   744 			}
       
   745 		TUint32 tc2 = NKern::TickCount();
       
   746 		if ( (tc2 - (tc+KTickLimit)) < 0x80000000 )
       
   747 			{
       
   748 			tc = tc2;
       
   749 			TEST_PRINT1("##W=%d",winfo.iWrites);
       
   750 			DumpMemory("WriterThread", w, 0x400);
       
   751 			}
       
   752 		switch (info.iTestType)
       
   753 			{
       
   754 			case SReaderInfo::ETimeslice:
       
   755 				break;
       
   756 			case SReaderInfo::ESuspend:
       
   757 				NKern::ThreadSuspend(info.iWriter, 1);
       
   758 	 			NKern::WaitForAnyRequest();
       
   759 				break;
       
   760 			case SReaderInfo::EKill:
       
   761 				{
       
   762 				w = info.iWriter;
       
   763 				info.iWriter = 0;
       
   764 				NKern::ThreadKill(w);
       
   765 	 			NKern::WaitForAnyRequest();
       
   766 				break;
       
   767 				}
       
   768 			case SReaderInfo::EMigrate:
       
   769 				NKern::ThreadSetCpuAffinity(info.iWriter, this_cpu);
       
   770 				if (info.iGroupThrd)
       
   771 					NKern::ThreadSetCpuAffinity(info.iGroupThrd, this_cpu);
       
   772 	 			NKern::WaitForAnyRequest();
       
   773 				break;
       
   774 			case SReaderInfo::EInterlockedSuspend:
       
   775 				{
       
   776 #if 0
       
   777 extern TLinAddr __LastIrqRet;
       
   778 extern TLinAddr __LastSSP;
       
   779 extern TLinAddr __SSTop;
       
   780 extern TUint32 __CaptureStack[1024];
       
   781 extern TLinAddr __InterruptedThread;
       
   782 extern TUint32 __CaptureThread[1024];
       
   783 #endif
       
   784 				NKern::FMWait(winfo.iM);
       
   785 				info.iCapturedIn = winfo.iIn;
       
   786 				info.iSuspendResult = NKern::ThreadSuspend(info.iWriter, 1);
       
   787 				NKern::FMSignal(winfo.iM);
       
   788 				NKern::ThreadRequestSignal(info.iReader);
       
   789 #if 0
       
   790 				NThread* pC = NKern::CurrentThread();
       
   791 				TUint32 tc0 = NKern::TickCount();
       
   792 				tc0+=1000;
       
   793 				FOREVER
       
   794 					{
       
   795 					TUint32 tc1 = NKern::TickCount();
       
   796 					if ((tc1-tc0)<0x80000000u)
       
   797 						{
       
   798 						DEBUGPRINT("__LastIrqRet = %08x", __LastIrqRet);
       
   799 						DEBUGPRINT("__LastSSP    = %08x", __LastSSP);
       
   800 						DEBUGPRINT("__SSTop      = %08x", __SSTop);
       
   801 
       
   802 						DumpMemory("WriterStack", __CaptureStack, __SSTop - __LastSSP);
       
   803 
       
   804 						DumpMemory("CaptureThread", __CaptureThread, sizeof(NThread));
       
   805 
       
   806 						DumpMemory("Writer", info.iWriter, sizeof(NThread));
       
   807 
       
   808 						DumpMemory("Reader", info.iReader, sizeof(NThread));
       
   809 
       
   810 						DumpMemory("SubSched0", &TheSubSchedulers[0], sizeof(TSubScheduler));
       
   811 						}
       
   812 					if (pC->iRequestSemaphore.iCount>0)
       
   813 						break;
       
   814 					}
       
   815 #endif
       
   816 	 			NKern::WaitForAnyRequest();
       
   817 				break;
       
   818 				}
       
   819 			case SReaderInfo::EInterlockedKill:
       
   820 				{
       
   821 				NKern::FMWait(winfo.iM);
       
   822 				info.iCapturedIn = winfo.iIn;
       
   823 				w = info.iWriter;
       
   824 				info.iWriter = 0;
       
   825 				NKern::ThreadKill(w, winfo.iM);
       
   826 				NKern::ThreadRequestSignal(info.iReader);
       
   827 	 			NKern::WaitForAnyRequest();
       
   828 				break;
       
   829 				}
       
   830 			case SReaderInfo::EInterlockedMigrate:
       
   831 				NKern::FMWait(winfo.iM);
       
   832 				info.iCapturedIn = winfo.iIn;
       
   833 				NKern::ThreadSetCpuAffinity(info.iWriter, this_cpu);
       
   834 				if (info.iGroupThrd)
       
   835 					NKern::ThreadSetCpuAffinity(info.iGroupThrd, this_cpu);
       
   836 				NKern::FMSignal(winfo.iM);
       
   837 				NKern::ThreadRequestSignal(info.iReader);
       
   838 	 			NKern::WaitForAnyRequest();
       
   839 				break;
       
   840 			}
       
   841 		}
       
   842 	TEST_PRINT1("<IV%d",info.iTestType);
       
   843 	}
       
   844 
       
   845 // State bits 0-7 show how many times timeslices are blocked
       
   846 // State bits 8-15 show how many times suspend/kill are blocked
       
   847 // State bits 16-23 show how many times migration is blocked
       
   848 // State bit 24 set if in CS when fast mutex held
       
   849 // State bit 25 set if CPU frozen when fast mutex held
       
   850 TUint32 UpdateState(TUint32 aS, TUint32 aOp, TBool aOut)
       
   851 	{
       
   852 	TUint32 x = 0;
       
   853 	if (aS & 0xff00)
       
   854 		x |= 0x01000000;
       
   855 	if (aS & 0xff0000)
       
   856 		x |= 0x02000000;
       
   857 	if (aOut)
       
   858 		{
       
   859 		switch (aOp)
       
   860 			{
       
   861 			case 0:
       
   862 			case 9:
       
   863 				return aS;
       
   864 			case 2:
       
   865 			case 7:
       
   866 			case 8:
       
   867 				return aS-0x010000;
       
   868 			case 3:
       
   869 				return aS-0x000100;
       
   870 			case 1:
       
   871 			case 4:
       
   872 				return aS-0x010101;
       
   873 			}
       
   874 		}
       
   875 	else
       
   876 		{
       
   877 		switch (aOp)
       
   878 			{
       
   879 			case 0:
       
   880 			case 9:
       
   881 				return aS;
       
   882 			case 2:
       
   883 			case 7:
       
   884 			case 8:
       
   885 				return aS+0x010000;
       
   886 			case 3:
       
   887 				return aS+0x000100;
       
   888 			case 1:
       
   889 			case 4:
       
   890 				return (aS+0x010101)|x;
       
   891 			}
       
   892 		}
       
   893 	return aS;
       
   894 	}
       
   895 
       
   896 void CheckResults(SReaderInfo& info)
       
   897 	{
       
   898 	SWriterInfo& winfo = *info.iWriterInfo;
       
   899 	TUint32 state[7];
       
   900 	char c[72];
       
   901 	memset(c, 32, sizeof(c)), c[71]=0;
       
   902 	state[0] = UpdateState(0, (winfo.iInSeq)&0xf, FALSE);
       
   903 	state[1] = UpdateState(state[0], (winfo.iInSeq>>4)&0xf, FALSE);
       
   904 	state[2] = UpdateState(state[1], (winfo.iInSeq>>8)&0xf, FALSE);
       
   905 	state[3] = UpdateState(state[2], (winfo.iOutSeq)&0xf, TRUE);
       
   906 	state[4] = UpdateState(state[3], (winfo.iOutSeq>>4)&0xf, TRUE);
       
   907 	state[5] = UpdateState(state[4], (winfo.iOutSeq>>8)&0xf, TRUE);
       
   908 	state[6] = (state[5] & 0xff000000) ^ 0x07000000;
       
   909 
       
   910 	TInt i;
       
   911 	for (i=0; i<6; ++i)
       
   912 		state[i] &= 0x00ffffff;
       
   913 
       
   914 	TEST_PRINT2("Reads %d Writes %d", info.iReads, winfo.iWrites);
       
   915 	for(i=0; i<6; ++i)
       
   916 		{
       
   917 		if (state[i] & 0xff00)
       
   918 			c[i*10] = 'S';
       
   919 		if (state[i] & 0xff0000)
       
   920 			c[i*10+1] = 'M';
       
   921 		if (state[i] & 0xff)
       
   922 			c[i*10+2] = 'T';
       
   923 		}
       
   924 	TEST_PRINT1("%s",c);
       
   925 	TEST_PRINT7("F0 %6d F1 %6d F2 %6d F3 %6d F4 %6d F5 %6d F6 %6d", info.iFails[0], info.iFails[1], info.iFails[2], info.iFails[3], info.iFails[4], info.iFails[5], info.iFails[6]);
       
   926 	memset(c, 32, sizeof(c)), c[71]=0;
       
   927 	TUint32 mask=0;
       
   928 	switch(info.iTestType)
       
   929 		{
       
   930 		case SReaderInfo::ETimeslice:			mask = 0x040000ff; break;
       
   931 		case SReaderInfo::ESuspend:				mask = 0x0400ff00; break;
       
   932 		case SReaderInfo::EKill:				mask = 0x0400ff00; break;
       
   933 		case SReaderInfo::EMigrate:				mask = 0x04ff0000; break;
       
   934 		case SReaderInfo::EInterlockedSuspend:	mask = 0x0400ff00; break;
       
   935 		case SReaderInfo::EInterlockedKill:		mask = 0x0100ff00; break;
       
   936 		case SReaderInfo::EInterlockedMigrate:	mask = 0x02ff0000; break;
       
   937 		}
       
   938 	TUint32 limit = info.iReads/10;
       
   939 	TInt fail=0;
       
   940 	for(i=0; i<7; ++i)
       
   941 		{
       
   942 		TBool bad = FALSE;
       
   943 		if (state[i] & mask)
       
   944 			bad = (info.iFails[i] > 0);
       
   945 		else
       
   946 			bad = (info.iFails[i] < limit);
       
   947 		if (bad)
       
   948 			{
       
   949 			++fail;
       
   950 			char* p = c+i*10+3;
       
   951 			*p++ = '-';
       
   952 			*p++ = '-';
       
   953 			*p++ = '-';
       
   954 			*p++ = '-';
       
   955 			*p++ = '-';
       
   956 			*p++ = '-';
       
   957 			}
       
   958 		}
       
   959 	if (fail)
       
   960 		{
       
   961 		c[0] = 'E';
       
   962 		c[1] = 'R';
       
   963 		c[2] = 'R';
       
   964 		TEST_PRINT1("%s",c);
       
   965 		TEST_RESULT(0,"FAILED");
       
   966 		}
       
   967 	}
       
   968 
       
   969 struct SGroupThreadInfo
       
   970 	{
       
   971 	TUint32 iInSeq;
       
   972 	TUint32 iRun;
       
   973 	};
       
   974 
       
   975 void GroupThread(TAny* a)
       
   976 	{
       
   977 	SGroupThreadInfo& info = *(SGroupThreadInfo*)a;
       
   978 	TInt i, frz;
       
   979 	NFastMutex mutex;
       
   980 	for (i = 0; i<3; ++i)
       
   981 		{
       
   982 		// Find the first nibble that asks for a group option
       
   983 		// and do what it asks for.
       
   984 		switch ((info.iInSeq>>(i*4))&0xf)
       
   985 			{
       
   986 			case 7:
       
   987 				frz = NKern::FreezeCpu();
       
   988 				NKern::WaitForAnyRequest();
       
   989 				NKern::EndFreezeCpu(frz);
       
   990 				return;
       
   991 			case 8:
       
   992 				NKern::FMWait(&mutex);
       
   993 				while (__e32_atomic_load_acq32(&info.iRun))
       
   994 					nfcfspin(10);
       
   995 				NKern::FMSignal(&mutex);
       
   996 				return;
       
   997 			}
       
   998 		}
       
   999 	// We weren't needed, but we have to wait to die anyway to avoid lifetime issues
       
  1000 	NKern::WaitForAnyRequest();
       
  1001 	}
       
  1002 
       
  1003 void DoRWTest(TInt aTestType, TUint32 aReadLimit, TUint32 aInSeq, TUint32 aOutSeq, TInt aRWCpu, TInt aICpu)
       
  1004 	{
       
  1005 	NFastMutex mutex;
       
  1006 	SWriterInfo* winfo = new SWriterInfo;
       
  1007 	TEST_OOM(winfo);
       
  1008 	memclr(winfo, sizeof(SWriterInfo));
       
  1009 	SReaderInfo* info = new SReaderInfo;
       
  1010 	TEST_OOM(info);
       
  1011 	memclr(info, sizeof(SReaderInfo));
       
  1012 	SGroupThreadInfo* gtinfo = new SGroupThreadInfo;
       
  1013 	TEST_OOM(gtinfo);
       
  1014 	memclr(gtinfo, sizeof(SGroupThreadInfo));
       
  1015 	TUint32 bufwords = 256;
       
  1016 	TUint32* buf = (TUint32*)malloc(6 * bufwords * sizeof(TUint32));
       
  1017 	TEST_OOM(buf);
       
  1018 	memclr(buf, 6 * bufwords * sizeof(TUint32));
       
  1019 	TInt i;
       
  1020 	for (i=0; i<6; ++i)
       
  1021 		{
       
  1022 		info->iBuf[i] = buf + i * bufwords;
       
  1023 		winfo->iBuf[i] = buf + i * bufwords;
       
  1024 		}
       
  1025 	winfo->iWords = bufwords;
       
  1026 	winfo->iM = &mutex;
       
  1027 	winfo->iInSeq = aInSeq;
       
  1028 	winfo->iOutSeq = aOutSeq;
       
  1029 	winfo->iPriority = 11;
       
  1030 	winfo->iTimeslice = __microseconds_to_timeslice_ticks(10000);
       
  1031 	winfo->iCpu = aRWCpu;
       
  1032 
       
  1033 	NFastSemaphore localExit(0);
       
  1034 
       
  1035 #ifdef __SMP__
       
  1036 	NThreadGroup group;
       
  1037 	SNThreadGroupCreateInfo ginfo;
       
  1038 	ginfo.iCpuAffinity = aRWCpu;
       
  1039 	TInt r = NKern::GroupCreate(&group, ginfo);
       
  1040 	TEST_RESULT(r==KErrNone, "");
       
  1041 	winfo->iGroup = &group;
       
  1042 	gtinfo->iRun = 1;
       
  1043 	gtinfo->iInSeq = aInSeq;
       
  1044 	NThread* groupThrd = CreateThreadSignalOnExit("GroupThrd", &GroupThread, 1, gtinfo, 0, KSmallTimeslice, &localExit, aRWCpu, &group);
       
  1045 	TEST_OOM(groupThrd);
       
  1046 	info->iGroupThrd = groupThrd;
       
  1047 	NKern::Sleep(100);
       
  1048 #endif
       
  1049 
       
  1050 	info->iWords = bufwords;
       
  1051 	info->iReadLimit = aReadLimit;
       
  1052 	info->iWriterInfo = winfo;
       
  1053 	info->iTestType = aTestType;
       
  1054 
       
  1055 	TInt rpri = (aTestType == SReaderInfo::ETimeslice) ? 11 : 10;
       
  1056 	NThread* reader = CreateThreadSignalOnExit("Reader", &ReaderThread, rpri, info, 0, -1, &info->iExitSem, aRWCpu);
       
  1057 	TEST_OOM(reader);
       
  1058 	info->iReader = reader;
       
  1059 	NKern::Sleep(10);
       
  1060 	NThread* ivt = CreateThreadSignalOnExit("Intervention", &InterventionThread, 12, info, 0, KSmallTimeslice, &localExit, aICpu);
       
  1061 	TEST_OOM(ivt);
       
  1062 	info->iIvThrd = ivt;
       
  1063 
       
  1064 	NKern::FSWait(&localExit);
       
  1065 #ifdef __SMP__
       
  1066 	NKern::ThreadRequestSignal(groupThrd);
       
  1067 #endif
       
  1068 	__e32_atomic_store_rel32(&gtinfo->iRun, 0);
       
  1069 	NKern::FSWait(&localExit);
       
  1070 
       
  1071 #ifdef __SMP__
       
  1072 	NKern::GroupDestroy(&group);
       
  1073 #endif
       
  1074 
       
  1075 	free(buf);
       
  1076 
       
  1077 	TEST_PRINT6("Type %d RL %d ISEQ %03x OSEQ %03x RWCPU %d ICPU %d", aTestType, aReadLimit, aInSeq, aOutSeq, aRWCpu, aICpu);
       
  1078 	CheckResults(*info);
       
  1079 
       
  1080 	free(info);
       
  1081 	free(winfo);
       
  1082 	free(gtinfo);
       
  1083 	}
       
  1084 
       
  1085 
       
  1086 void TestFastMutex()
       
  1087 	{
       
  1088 	TEST_PRINT("Testing Fast Mutexes...");
       
  1089 
       
  1090 	FMTest0();
       
  1091 	FMTest1();
       
  1092 	FMTest1P();
       
  1093 	FMTest2();
       
  1094 	}
       
  1095 
       
  1096 void TestSuspendKillMigrate()
       
  1097 	{
       
  1098 	TEST_PRINT("Testing Suspend/Kill/Migrate...");
       
  1099 
       
  1100 	DoRWTest(SReaderInfo::ETimeslice,			KReadCount, 0x000, 0x000, 0, 1);
       
  1101 	DoRWTest(SReaderInfo::ETimeslice,			KReadCount, 0x010, 0x100, 0, 1);
       
  1102 	DoRWTest(SReaderInfo::ETimeslice,			KReadCount, 0x040, 0x400, 0, 1);
       
  1103 	DoRWTest(SReaderInfo::ETimeslice,			KReadCount, 0x132, 0x231, 0, 1);
       
  1104 	DoRWTest(SReaderInfo::ETimeslice,			KReadCount, 0x432, 0x234, 0, 1);
       
  1105 	DoRWTest(SReaderInfo::ETimeslice,			KReadCount, 0x310, 0x310, 0, 1);
       
  1106 	DoRWTest(SReaderInfo::ETimeslice,			KReadCount, 0x340, 0x340, 0, 1);
       
  1107 
       
  1108 	DoRWTest(SReaderInfo::ESuspend,				KReadCount, 0x000, 0x000, 0, 1);
       
  1109 	DoRWTest(SReaderInfo::ESuspend,				KReadCount, 0x010, 0x100, 0, 1);
       
  1110 	DoRWTest(SReaderInfo::ESuspend,				KReadCount, 0x040, 0x400, 0, 1);
       
  1111 	DoRWTest(SReaderInfo::ESuspend,				KReadCount, 0x132, 0x231, 0, 1);
       
  1112 	DoRWTest(SReaderInfo::ESuspend,				KReadCount, 0x432, 0x234, 0, 1);
       
  1113 	DoRWTest(SReaderInfo::ESuspend,				KReadCount, 0x310, 0x310, 0, 1);
       
  1114 	DoRWTest(SReaderInfo::ESuspend,				KReadCount, 0x340, 0x340, 0, 1);
       
  1115 
       
  1116 	DoRWTest(SReaderInfo::EKill,				KReadCount, 0x000, 0x000, 0, 1);
       
  1117 	DoRWTest(SReaderInfo::EKill,				KReadCount, 0x010, 0x100, 0, 1);
       
  1118 	DoRWTest(SReaderInfo::EKill,				KReadCount, 0x040, 0x400, 0, 1);
       
  1119 	DoRWTest(SReaderInfo::EKill,				KReadCount, 0x132, 0x231, 0, 1);
       
  1120 	DoRWTest(SReaderInfo::EKill,				KReadCount, 0x432, 0x234, 0, 1);
       
  1121 	DoRWTest(SReaderInfo::EKill,				KReadCount, 0x310, 0x310, 0, 1);
       
  1122 	DoRWTest(SReaderInfo::EKill,				KReadCount, 0x340, 0x340, 0, 1);
       
  1123 
       
  1124 	DoRWTest(SReaderInfo::EMigrate,				KReadCount, 0x000, 0x000, 0, 1);
       
  1125 	DoRWTest(SReaderInfo::EMigrate,				KReadCount, 0x132, 0x231, 0, 1);
       
  1126 	DoRWTest(SReaderInfo::EMigrate,				KReadCount, 0x432, 0x234, 0, 1);
       
  1127 	DoRWTest(SReaderInfo::EMigrate,				KReadCount, 0x020, 0x200, 0, 1);
       
  1128 	DoRWTest(SReaderInfo::EMigrate,				KReadCount, 0x010, 0x100, 0, 1);
       
  1129 	DoRWTest(SReaderInfo::EMigrate,				KReadCount, 0x040, 0x400, 0, 1);
       
  1130 	DoRWTest(SReaderInfo::EMigrate,				KReadCount, 0x030, 0x300, 0, 1);
       
  1131 
       
  1132 	DoRWTest(SReaderInfo::EInterlockedSuspend,	KReadCount, 0x432, 0x234, 0, 1);
       
  1133 	DoRWTest(SReaderInfo::EInterlockedSuspend,	KReadCount, 0x040, 0x400, 0, 1);
       
  1134 	DoRWTest(SReaderInfo::EInterlockedSuspend,	KReadCount, 0x010, 0x100, 0, 1);
       
  1135 	DoRWTest(SReaderInfo::EInterlockedSuspend,	KReadCount, 0x340, 0x340, 0, 1);
       
  1136 	DoRWTest(SReaderInfo::EInterlockedSuspend,	KReadCount, 0x310, 0x310, 0, 1);
       
  1137 	DoRWTest(SReaderInfo::EInterlockedSuspend,	KReadCount, 0x132, 0x231, 0, 1);
       
  1138 
       
  1139 	DoRWTest(SReaderInfo::EInterlockedKill,		KReadCount, 0x040, 0x400, 0, 1);
       
  1140 	DoRWTest(SReaderInfo::EInterlockedKill,		KReadCount, 0x010, 0x100, 0, 1);
       
  1141 	DoRWTest(SReaderInfo::EInterlockedKill,		KReadCount, 0x432, 0x234, 0, 1);
       
  1142 	DoRWTest(SReaderInfo::EInterlockedKill,		KReadCount, 0x340, 0x340, 0, 1);
       
  1143 	DoRWTest(SReaderInfo::EInterlockedKill,		KReadCount, 0x132, 0x231, 0, 1);
       
  1144 	DoRWTest(SReaderInfo::EInterlockedKill,		KReadCount, 0x310, 0x310, 0, 1);
       
  1145 
       
  1146 	DoRWTest(SReaderInfo::EInterlockedMigrate,	KReadCount, 0x040, 0x400, 0, 1);
       
  1147 	DoRWTest(SReaderInfo::EInterlockedMigrate,	KReadCount, 0x010, 0x100, 0, 1);
       
  1148 	DoRWTest(SReaderInfo::EInterlockedMigrate,	KReadCount, 0x310, 0x310, 0, 1);
       
  1149 	DoRWTest(SReaderInfo::EInterlockedMigrate,	KReadCount, 0x340, 0x340, 0, 1);
       
  1150 	DoRWTest(SReaderInfo::EInterlockedMigrate,	KReadCount, 0x132, 0x231, 0, 1);
       
  1151 	DoRWTest(SReaderInfo::EInterlockedMigrate,	KReadCount, 0x432, 0x234, 0, 1);
       
  1152 	DoRWTest(SReaderInfo::EInterlockedMigrate,	KReadCount, 0x120, 0x210, 0, 1);
       
  1153 	DoRWTest(SReaderInfo::EInterlockedMigrate,	KReadCount, 0x420, 0x240, 0, 1);
       
  1154 
       
  1155 #ifdef __SMP__
       
  1156 	// Tests from above that involve freezing, except by joining a frozen group instead
       
  1157 	DoRWTest(SReaderInfo::ETimeslice,			KReadCount, 0x137, 0x731, 0, 1);
       
  1158 	DoRWTest(SReaderInfo::ETimeslice,			KReadCount, 0x437, 0x734, 0, 1);
       
  1159 
       
  1160 	DoRWTest(SReaderInfo::ESuspend,				KReadCount, 0x137, 0x731, 0, 1);
       
  1161 	DoRWTest(SReaderInfo::ESuspend,				KReadCount, 0x437, 0x734, 0, 1);
       
  1162 
       
  1163 	DoRWTest(SReaderInfo::EKill,				KReadCount, 0x137, 0x731, 0, 1);
       
  1164 	DoRWTest(SReaderInfo::EKill,				KReadCount, 0x437, 0x734, 0, 1);
       
  1165 
       
  1166 	DoRWTest(SReaderInfo::EMigrate,				KReadCount, 0x137, 0x731, 0, 1);
       
  1167 	DoRWTest(SReaderInfo::EMigrate,				KReadCount, 0x437, 0x734, 0, 1);
       
  1168 	DoRWTest(SReaderInfo::EMigrate,				KReadCount, 0x070, 0x700, 0, 1);
       
  1169 
       
  1170 	DoRWTest(SReaderInfo::EInterlockedSuspend,	KReadCount, 0x437, 0x734, 0, 1);
       
  1171 	DoRWTest(SReaderInfo::EInterlockedSuspend,	KReadCount, 0x137, 0x731, 0, 1);
       
  1172 
       
  1173 	DoRWTest(SReaderInfo::EInterlockedKill,		KReadCount, 0x437, 0x734, 0, 1);
       
  1174 	DoRWTest(SReaderInfo::EInterlockedKill,		KReadCount, 0x137, 0x731, 0, 1);
       
  1175 
       
  1176 	DoRWTest(SReaderInfo::EInterlockedMigrate,	KReadCount, 0x137, 0x731, 0, 1);
       
  1177 	DoRWTest(SReaderInfo::EInterlockedMigrate,	KReadCount, 0x437, 0x734, 0, 1);
       
  1178 	DoRWTest(SReaderInfo::EInterlockedMigrate,	KReadCount, 0x170, 0x710, 0, 1);
       
  1179 	DoRWTest(SReaderInfo::EInterlockedMigrate,	KReadCount, 0x470, 0x740, 0, 1);
       
  1180 
       
  1181 	// Tests from above that involve freezing, except by joining a group with a mutex-holder instead
       
  1182 	DoRWTest(SReaderInfo::ETimeslice,			KReadCount, 0x138, 0x831, 0, 1);
       
  1183 	DoRWTest(SReaderInfo::ETimeslice,			KReadCount, 0x438, 0x834, 0, 1);
       
  1184 
       
  1185 	DoRWTest(SReaderInfo::ESuspend,				KReadCount, 0x138, 0x831, 0, 1);
       
  1186 	DoRWTest(SReaderInfo::ESuspend,				KReadCount, 0x438, 0x834, 0, 1);
       
  1187 
       
  1188 	DoRWTest(SReaderInfo::EKill,				KReadCount, 0x138, 0x831, 0, 1);
       
  1189 	DoRWTest(SReaderInfo::EKill,				KReadCount, 0x438, 0x834, 0, 1);
       
  1190 
       
  1191 	DoRWTest(SReaderInfo::EMigrate,				KReadCount, 0x138, 0x831, 0, 1);
       
  1192 	DoRWTest(SReaderInfo::EMigrate,				KReadCount, 0x438, 0x834, 0, 1);
       
  1193 	DoRWTest(SReaderInfo::EMigrate,				KReadCount, 0x080, 0x800, 0, 1);
       
  1194 
       
  1195 	DoRWTest(SReaderInfo::EInterlockedSuspend,	KReadCount, 0x438, 0x834, 0, 1);
       
  1196 	DoRWTest(SReaderInfo::EInterlockedSuspend,	KReadCount, 0x138, 0x831, 0, 1);
       
  1197 
       
  1198 	DoRWTest(SReaderInfo::EInterlockedKill,		KReadCount, 0x438, 0x834, 0, 1);
       
  1199 	DoRWTest(SReaderInfo::EInterlockedKill,		KReadCount, 0x138, 0x831, 0, 1);
       
  1200 
       
  1201 	DoRWTest(SReaderInfo::EInterlockedMigrate,	KReadCount, 0x138, 0x831, 0, 1);
       
  1202 	DoRWTest(SReaderInfo::EInterlockedMigrate,	KReadCount, 0x438, 0x834, 0, 1);
       
  1203 	DoRWTest(SReaderInfo::EInterlockedMigrate,	KReadCount, 0x180, 0x810, 0, 1);
       
  1204 	DoRWTest(SReaderInfo::EInterlockedMigrate,	KReadCount, 0x480, 0x840, 0, 1);
       
  1205 
       
  1206 	// Tests from above that have a noop, except join a group that's doing nothing instead
       
  1207 	// Most of these do "join group, other op, leave group, undo other op" - this is
       
  1208 	// supposed to work, even though you can't *join* a group while frozen or holding a mutex
       
  1209 	DoRWTest(SReaderInfo::ETimeslice,			KReadCount, 0x090, 0x900, 0, 1);
       
  1210 	DoRWTest(SReaderInfo::ETimeslice,			KReadCount, 0x019, 0x190, 0, 1);
       
  1211 	DoRWTest(SReaderInfo::ETimeslice,			KReadCount, 0x049, 0x490, 0, 1);
       
  1212 	DoRWTest(SReaderInfo::ETimeslice,			KReadCount, 0x319, 0x319, 0, 1);
       
  1213 	DoRWTest(SReaderInfo::ETimeslice,			KReadCount, 0x349, 0x349, 0, 1);
       
  1214 
       
  1215 	DoRWTest(SReaderInfo::ESuspend,				KReadCount, 0x090, 0x900, 0, 1);
       
  1216 	DoRWTest(SReaderInfo::ESuspend,				KReadCount, 0x019, 0x190, 0, 1);
       
  1217 	DoRWTest(SReaderInfo::ESuspend,				KReadCount, 0x049, 0x490, 0, 1);
       
  1218 	DoRWTest(SReaderInfo::ESuspend,				KReadCount, 0x319, 0x319, 0, 1);
       
  1219 	DoRWTest(SReaderInfo::ESuspend,				KReadCount, 0x349, 0x349, 0, 1);
       
  1220 
       
  1221 	DoRWTest(SReaderInfo::EKill,				KReadCount, 0x090, 0x900, 0, 1);
       
  1222 	DoRWTest(SReaderInfo::EKill,				KReadCount, 0x019, 0x190, 0, 1);
       
  1223 	DoRWTest(SReaderInfo::EKill,				KReadCount, 0x049, 0x490, 0, 1);
       
  1224 	DoRWTest(SReaderInfo::EKill,				KReadCount, 0x319, 0x319, 0, 1);
       
  1225 	DoRWTest(SReaderInfo::EKill,				KReadCount, 0x349, 0x349, 0, 1);
       
  1226 
       
  1227 	DoRWTest(SReaderInfo::EMigrate,				KReadCount, 0x090, 0x900, 0, 1);
       
  1228 	DoRWTest(SReaderInfo::EMigrate,				KReadCount, 0x029, 0x290, 0, 1);
       
  1229 	DoRWTest(SReaderInfo::EMigrate,				KReadCount, 0x019, 0x190, 0, 1);
       
  1230 	DoRWTest(SReaderInfo::EMigrate,				KReadCount, 0x049, 0x490, 0, 1);
       
  1231 	DoRWTest(SReaderInfo::EMigrate,				KReadCount, 0x039, 0x390, 0, 1);
       
  1232 
       
  1233 	DoRWTest(SReaderInfo::EInterlockedSuspend,	KReadCount, 0x049, 0x490, 0, 1);
       
  1234 	DoRWTest(SReaderInfo::EInterlockedSuspend,	KReadCount, 0x019, 0x190, 0, 1);
       
  1235 	DoRWTest(SReaderInfo::EInterlockedSuspend,	KReadCount, 0x349, 0x349, 0, 1);
       
  1236 	DoRWTest(SReaderInfo::EInterlockedSuspend,	KReadCount, 0x319, 0x319, 0, 1);
       
  1237 
       
  1238 	DoRWTest(SReaderInfo::EInterlockedKill,		KReadCount, 0x049, 0x490, 0, 1);
       
  1239 	DoRWTest(SReaderInfo::EInterlockedKill,		KReadCount, 0x019, 0x190, 0, 1);
       
  1240 	DoRWTest(SReaderInfo::EInterlockedKill,		KReadCount, 0x349, 0x349, 0, 1);
       
  1241 	DoRWTest(SReaderInfo::EInterlockedKill,		KReadCount, 0x319, 0x319, 0, 1);
       
  1242 
       
  1243 	DoRWTest(SReaderInfo::EInterlockedMigrate,	KReadCount, 0x049, 0x490, 0, 1);
       
  1244 	DoRWTest(SReaderInfo::EInterlockedMigrate,	KReadCount, 0x019, 0x190, 0, 1);
       
  1245 	DoRWTest(SReaderInfo::EInterlockedMigrate,	KReadCount, 0x319, 0x319, 0, 1);
       
  1246 	DoRWTest(SReaderInfo::EInterlockedMigrate,	KReadCount, 0x349, 0x349, 0, 1);
       
  1247 	DoRWTest(SReaderInfo::EInterlockedMigrate,	KReadCount, 0x129, 0x219, 0, 1);
       
  1248 	DoRWTest(SReaderInfo::EInterlockedMigrate,	KReadCount, 0x429, 0x249, 0, 1);
       
  1249 
       
  1250 	// Test freezing or acquiring a mutex while in a group that also does one of those things
       
  1251 	// and then leave the group.
       
  1252 	DoRWTest(SReaderInfo::ETimeslice,			KReadCount, 0x017, 0x170, 0, 1);
       
  1253 	DoRWTest(SReaderInfo::ETimeslice,			KReadCount, 0x018, 0x180, 0, 1);
       
  1254 	DoRWTest(SReaderInfo::ETimeslice,			KReadCount, 0x027, 0x270, 0, 1);
       
  1255 	DoRWTest(SReaderInfo::ETimeslice,			KReadCount, 0x028, 0x280, 0, 1);
       
  1256 
       
  1257 	DoRWTest(SReaderInfo::ESuspend,				KReadCount, 0x017, 0x170, 0, 1);
       
  1258 	DoRWTest(SReaderInfo::ESuspend,				KReadCount, 0x018, 0x180, 0, 1);
       
  1259 	DoRWTest(SReaderInfo::ESuspend,				KReadCount, 0x027, 0x270, 0, 1);
       
  1260 	DoRWTest(SReaderInfo::ESuspend,				KReadCount, 0x028, 0x280, 0, 1);
       
  1261 
       
  1262 	DoRWTest(SReaderInfo::EKill,				KReadCount, 0x017, 0x170, 0, 1);
       
  1263 	DoRWTest(SReaderInfo::EKill,				KReadCount, 0x018, 0x180, 0, 1);
       
  1264 	DoRWTest(SReaderInfo::EKill,				KReadCount, 0x027, 0x270, 0, 1);
       
  1265 	DoRWTest(SReaderInfo::EKill,				KReadCount, 0x028, 0x280, 0, 1);
       
  1266 
       
  1267 	DoRWTest(SReaderInfo::EMigrate,				KReadCount, 0x017, 0x170, 0, 1);
       
  1268 	DoRWTest(SReaderInfo::EMigrate,				KReadCount, 0x018, 0x180, 0, 1);
       
  1269 	DoRWTest(SReaderInfo::EMigrate,				KReadCount, 0x027, 0x270, 0, 1);
       
  1270 	DoRWTest(SReaderInfo::EMigrate,				KReadCount, 0x028, 0x280, 0, 1);
       
  1271 
       
  1272 	DoRWTest(SReaderInfo::EInterlockedSuspend,	KReadCount, 0x017, 0x170, 0, 1);
       
  1273 	DoRWTest(SReaderInfo::EInterlockedSuspend,	KReadCount, 0x018, 0x180, 0, 1);
       
  1274 
       
  1275 	DoRWTest(SReaderInfo::EInterlockedKill,		KReadCount, 0x017, 0x170, 0, 1);
       
  1276 	DoRWTest(SReaderInfo::EInterlockedKill,		KReadCount, 0x018, 0x180, 0, 1);
       
  1277 
       
  1278 	DoRWTest(SReaderInfo::EInterlockedMigrate,	KReadCount, 0x017, 0x170, 0, 1);
       
  1279 	DoRWTest(SReaderInfo::EInterlockedMigrate,	KReadCount, 0x018, 0x180, 0, 1);
       
  1280 #endif
       
  1281 }