os/kernelhwsrv/kerneltest/e32test/nkernsa/fastmutex.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     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 }