1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kerneltest/e32test/nkernsa/fastmutex.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1281 @@
1.4 +// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32test\nkernsa\fastmutex.cpp
1.18 +//
1.19 +//
1.20 +
1.21 +#include <nktest/nkutils.h>
1.22 +
1.23 +const TInt KReadCount = 100000;
1.24 +//const TInt KReadCount = 2000000;
1.25 +#ifdef __CPU_ARM
1.26 +const TUint32 KTickLimit = (KReadCount>100000) ? (((TUint32)KReadCount)/10*18) : 180000u;
1.27 +#else
1.28 +const TUint32 KTickLimit = (KReadCount>100000) ? (((TUint32)KReadCount)/10*6) : 60000u;
1.29 +#endif
1.30 +
1.31 +class NFastMutexX
1.32 + {
1.33 +public:
1.34 + TInt iRefCount;
1.35 + NFastMutex* iMutex;
1.36 +public:
1.37 + NFastMutexX();
1.38 + ~NFastMutexX();
1.39 + void Create();
1.40 + TBool Open();
1.41 + TBool Close();
1.42 + TBool Wait();
1.43 + TBool Signal();
1.44 + TBool WaitFull();
1.45 + TBool SignalFull();
1.46 + };
1.47 +
1.48 +NFastMutexX::NFastMutexX()
1.49 + : iRefCount(0), iMutex(0)
1.50 + {}
1.51 +
1.52 +void NFastMutexX::Create()
1.53 + {
1.54 + iMutex = new NFastMutex;
1.55 + TEST_OOM(iMutex);
1.56 + __e32_atomic_store_rel32(&iRefCount, 1);
1.57 + }
1.58 +
1.59 +NFastMutexX::~NFastMutexX()
1.60 + {
1.61 + TEST_RESULT2(iRefCount==0, "Bad mutex ref count %d %08x", iRefCount, this);
1.62 + memset(this, 0xbf, sizeof(*this));
1.63 + }
1.64 +
1.65 +TBool NFastMutexX::Open()
1.66 + {
1.67 + return __e32_atomic_tas_ord32(&iRefCount, 1, 1, 0) > 0;
1.68 + }
1.69 +
1.70 +TBool NFastMutexX::Close()
1.71 + {
1.72 + TInt r = __e32_atomic_tas_ord32(&iRefCount, 1, -1, 0);
1.73 + if (r==1)
1.74 + {
1.75 + memset(iMutex, 0xbf, sizeof(NFastMutex));
1.76 + delete iMutex;
1.77 + iMutex = 0;
1.78 + }
1.79 + return r==1;
1.80 + }
1.81 +
1.82 +TBool NFastMutexX::Wait()
1.83 + {
1.84 + if (Open())
1.85 + {
1.86 + NKern::FMWait(iMutex);
1.87 + return TRUE;
1.88 + }
1.89 + return FALSE;
1.90 + }
1.91 +
1.92 +TBool NFastMutexX::Signal()
1.93 + {
1.94 + NKern::FMSignal(iMutex);
1.95 + return Close();
1.96 + }
1.97 +
1.98 +TBool NFastMutexX::WaitFull()
1.99 + {
1.100 + if (Open())
1.101 + {
1.102 + FMWaitFull(iMutex);
1.103 + return TRUE;
1.104 + }
1.105 + return FALSE;
1.106 + }
1.107 +
1.108 +TBool NFastMutexX::SignalFull()
1.109 + {
1.110 + FMSignalFull(iMutex);
1.111 + return Close();
1.112 + }
1.113 +
1.114 +void FMTest0()
1.115 + {
1.116 + TEST_PRINT("Testing non-contention case");
1.117 +
1.118 + NFastMutex m;
1.119 +
1.120 + TEST_RESULT(!m.HeldByCurrentThread(), "Mutex held by current thread");
1.121 + TEST_RESULT(!NKern::HeldFastMutex(), "Current thread holds a fast mutex");
1.122 +
1.123 + NKern::FMWait(&m);
1.124 +
1.125 + TEST_RESULT(m.HeldByCurrentThread(), "Mutex not held by current thread");
1.126 + TEST_RESULT(NKern::HeldFastMutex()==&m, "HeldFastMutex() incorrect");
1.127 +
1.128 + NKern::FMSignal(&m);
1.129 +
1.130 + TEST_RESULT(!m.HeldByCurrentThread(), "Mutex held by current thread");
1.131 + TEST_RESULT(!NKern::HeldFastMutex(), "Current thread holds a fast mutex");
1.132 + }
1.133 +
1.134 +struct SFMTest1Info
1.135 + {
1.136 + NFastMutex iMutex;
1.137 + volatile TUint32* iBlock;
1.138 + TInt iBlockSize; // words
1.139 + TInt iPriorityThreshold;
1.140 + volatile TBool iStop;
1.141 + NThread* iThreads[3*KMaxCpus];
1.142 + };
1.143 +
1.144 +void FMTest1Thread(TAny* a)
1.145 + {
1.146 + SFMTest1Info& info = *(SFMTest1Info*)a;
1.147 + NThread* pC = NKern::CurrentThread();
1.148 + TUint32 seed[2] = {(TUint32)pC, 0};
1.149 + TBool wait = (pC->iPriority > info.iPriorityThreshold);
1.150 + TBool thread0 = (pC==info.iThreads[0]);
1.151 + TInt n = 0;
1.152 + while (!info.iStop)
1.153 + {
1.154 + if (thread0)
1.155 + NKern::ThreadSetPriority(pC, 11);
1.156 + NKern::FMWait(&info.iMutex);
1.157 + TBool ok = verify_block((TUint32*)info.iBlock, info.iBlockSize);
1.158 + TEST_RESULT(ok, "Block corrupt");
1.159 + ++info.iBlock[0];
1.160 + setup_block((TUint32*)info.iBlock, info.iBlockSize);
1.161 + ++n;
1.162 + NKern::FMSignal(&info.iMutex);
1.163 + if (wait)
1.164 + {
1.165 + TUint32 x = random(seed) & 1;
1.166 + NKern::Sleep(x+1);
1.167 + }
1.168 + }
1.169 + TEST_PRINT2("Thread %T ran %d times", pC, n);
1.170 + }
1.171 +
1.172 +void FMTest1PInterfererThread(TAny* a)
1.173 + {
1.174 + SFMTest1Info& info = *(SFMTest1Info*)a;
1.175 + NThread* pC = NKern::CurrentThread();
1.176 + TEST_PRINT1("Thread %T start", pC);
1.177 + TUint32 seed[2] = {(TUint32)pC, 0};
1.178 + NThread* t0 = info.iThreads[0];
1.179 + TInt n = 0;
1.180 + while (!__e32_atomic_load_acq32(&info.iStop))
1.181 + {
1.182 + while (!__e32_atomic_load_acq32(&info.iStop) && t0->iPriority != 11)
1.183 + __chill();
1.184 + TUint32 x = random(seed) & 2047;
1.185 + while(x)
1.186 + {
1.187 + __e32_atomic_add_ord32(&x, TUint32(-1));
1.188 + }
1.189 + if (__e32_atomic_load_acq32(&info.iStop))
1.190 + break;
1.191 + NKern::ThreadSetPriority(t0, 9);
1.192 + ++n;
1.193 + }
1.194 + TEST_PRINT2("Thread %T ran %d times", pC, n);
1.195 + }
1.196 +
1.197 +void FMTest1()
1.198 + {
1.199 + TEST_PRINT("Testing mutual exclusion");
1.200 +
1.201 + NFastSemaphore exitSem(0);
1.202 + SFMTest1Info* pI = new SFMTest1Info;
1.203 + TEST_OOM(pI);
1.204 + memclr(pI, sizeof(SFMTest1Info));
1.205 + pI->iBlockSize = 256;
1.206 + pI->iBlock = (TUint32*)malloc(pI->iBlockSize*sizeof(TUint32));
1.207 + TEST_OOM(pI->iBlock);
1.208 + pI->iPriorityThreshold = 10;
1.209 + pI->iBlock[0] = 0;
1.210 + setup_block((TUint32*)pI->iBlock, pI->iBlockSize);
1.211 + pI->iStop = FALSE;
1.212 + TInt cpu;
1.213 + TInt threads = 0;
1.214 + for_each_cpu(cpu)
1.215 + {
1.216 + CreateThreadSignalOnExit("FMTest1H", &FMTest1Thread, 11, pI, 0, KSmallTimeslice, &exitSem, cpu);
1.217 + CreateThreadSignalOnExit("FMTest1L0", &FMTest1Thread, 10, pI, 0, KSmallTimeslice, &exitSem, cpu);
1.218 + CreateThreadSignalOnExit("FMTest1L1", &FMTest1Thread, 10, pI, 0, KSmallTimeslice, &exitSem, cpu);
1.219 + threads += 3;
1.220 + }
1.221 + FOREVER
1.222 + {
1.223 + NKern::Sleep(1000);
1.224 + TEST_PRINT1("%d", pI->iBlock[0]);
1.225 + if (pI->iBlock[0] > 65536)
1.226 + {
1.227 + pI->iStop = TRUE;
1.228 + break;
1.229 + }
1.230 + }
1.231 + while (threads--)
1.232 + NKern::FSWait(&exitSem);
1.233 + TEST_PRINT1("Total iterations %d", pI->iBlock[0]);
1.234 + free((TAny*)pI->iBlock);
1.235 + free(pI);
1.236 + }
1.237 +
1.238 +void FMTest1P()
1.239 + {
1.240 + TEST_PRINT("Testing priority change");
1.241 + if (NKern::NumberOfCpus()==1)
1.242 + return;
1.243 +
1.244 + NFastSemaphore exitSem(0);
1.245 + SFMTest1Info* pI = new SFMTest1Info;
1.246 + TEST_OOM(pI);
1.247 + memclr(pI, sizeof(SFMTest1Info));
1.248 + TEST_PRINT1("Info@0x%08x", pI);
1.249 + pI->iBlockSize = 256;
1.250 + pI->iBlock = (TUint32*)malloc(pI->iBlockSize*sizeof(TUint32));
1.251 + TEST_OOM(pI->iBlock);
1.252 + pI->iPriorityThreshold = 9;
1.253 + pI->iBlock[0] = 0;
1.254 + setup_block((TUint32*)pI->iBlock, pI->iBlockSize);
1.255 + pI->iStop = FALSE;
1.256 + TInt cpu;
1.257 + TInt threadCount = 0;
1.258 + TInt pri = 9;
1.259 + char name[16] = "FMTest1P.0";
1.260 + for_each_cpu(cpu)
1.261 + {
1.262 + name[9] = (char)(threadCount + '0');
1.263 + if (cpu==1)
1.264 + pI->iThreads[threadCount] = CreateThreadSignalOnExit("FMTest1PInterferer", &FMTest1PInterfererThread, 12, pI, 0, KSmallTimeslice, &exitSem, 1);
1.265 + else
1.266 + pI->iThreads[threadCount] = CreateThreadSignalOnExit(name, &FMTest1Thread, pri, pI, 0, KSmallTimeslice, &exitSem, cpu);
1.267 + pri = 10;
1.268 + threadCount++;
1.269 + }
1.270 + TUint32 b0 = 0xffffffffu;
1.271 + FOREVER
1.272 + {
1.273 + NKern::Sleep(1000);
1.274 + TUint32 b = pI->iBlock[0];
1.275 + TEST_PRINT1("%d", b);
1.276 + if (b > 1048576)
1.277 + {
1.278 + pI->iStop = TRUE;
1.279 + break;
1.280 + }
1.281 + if (b == b0)
1.282 + {
1.283 + __crash();
1.284 + }
1.285 + b0 = b;
1.286 + }
1.287 + while (threadCount--)
1.288 + NKern::FSWait(&exitSem);
1.289 + TEST_PRINT1("Total iterations %d", pI->iBlock[0]);
1.290 + free((TAny*)pI->iBlock);
1.291 + free(pI);
1.292 + }
1.293 +
1.294 +struct SFMTest2InfoC
1.295 + {
1.296 + NFastMutex iMutex;
1.297 + TInt iMax;
1.298 + TBool iStop;
1.299 + };
1.300 +
1.301 +struct SFMTest2InfoT
1.302 + {
1.303 + SFMTest2InfoC* iCommon;
1.304 + TUint32 iMaxDelay;
1.305 + TInt iIterations;
1.306 + TUint32 iSpinTime;
1.307 + TUint32 iBlockTimeMask;
1.308 + TUint32 iBlockTimeOffset;
1.309 + NThread* iThread;
1.310 + union {
1.311 + TUint8 iSpoiler;
1.312 + TUint32 iDelayThreshold;
1.313 + };
1.314 + };
1.315 +
1.316 +TBool StopTest = FALSE;
1.317 +
1.318 +void FMTest2Thread(TAny* a)
1.319 + {
1.320 + SFMTest2InfoT& t = *(SFMTest2InfoT*)a;
1.321 + SFMTest2InfoC& c = *t.iCommon;
1.322 + NThreadBase* pC = NKern::CurrentThread();
1.323 + TUint32 seed[2] = {(TUint32)pC, 0};
1.324 + while (!c.iStop)
1.325 + {
1.326 + ++t.iIterations;
1.327 + if (t.iSpoiler)
1.328 + {
1.329 + nfcfspin(t.iSpinTime);
1.330 + }
1.331 + else
1.332 + {
1.333 + TUint32 initial = norm_fast_counter();
1.334 + NKern::FMWait(&c.iMutex);
1.335 + TUint32 final = norm_fast_counter();
1.336 + TUint32 delay = final - initial;
1.337 + if (delay > t.iMaxDelay)
1.338 + {
1.339 + t.iMaxDelay = delay;
1.340 + __e32_atomic_add_ord32(&c.iMax, 1);
1.341 + if (delay > t.iDelayThreshold)
1.342 + __crash();
1.343 + }
1.344 + nfcfspin(t.iSpinTime);
1.345 + NKern::FMSignal(&c.iMutex);
1.346 + }
1.347 + if (t.iBlockTimeMask)
1.348 + {
1.349 + TUint32 sleep = (random(seed) & t.iBlockTimeMask) + t.iBlockTimeOffset;
1.350 + NKern::Sleep(sleep);
1.351 + }
1.352 + }
1.353 + TEST_PRINT3("Thread %T %d iterations, max delay %d", pC, t.iIterations, t.iMaxDelay);
1.354 + }
1.355 +
1.356 +SFMTest2InfoT* CreateFMTest2Thread( const char* aName,
1.357 + SFMTest2InfoC& aCommon,
1.358 + TUint32 aSpinTime,
1.359 + TUint32 aBlockTimeMask,
1.360 + TUint32 aBlockTimeOffset,
1.361 + TBool aSpoiler,
1.362 + TInt aPri,
1.363 + TInt aTimeslice,
1.364 + NFastSemaphore& aExitSem,
1.365 + TUint32 aCpu
1.366 + )
1.367 + {
1.368 + SFMTest2InfoT* ti = new SFMTest2InfoT;
1.369 + TEST_OOM(ti);
1.370 + ti->iCommon = &aCommon;
1.371 + ti->iMaxDelay = 0;
1.372 + ti->iDelayThreshold = 0xffffffffu;
1.373 + ti->iIterations = 0;
1.374 + ti->iSpinTime = aSpinTime;
1.375 + ti->iBlockTimeMask = aBlockTimeMask;
1.376 + ti->iBlockTimeOffset = aBlockTimeOffset;
1.377 + ti->iSpoiler = (TUint8)aSpoiler;
1.378 + ti->iThread = 0;
1.379 +
1.380 + NThread* t = CreateUnresumedThreadSignalOnExit(aName, &FMTest2Thread, aPri, ti, 0, aTimeslice, &aExitSem, aCpu);
1.381 + ti->iThread = t;
1.382 + DEBUGPRINT("Thread at %08x, Info at %08x", t, ti);
1.383 +
1.384 + return ti;
1.385 + }
1.386 +
1.387 +extern void DebugPrint(const char*, int);
1.388 +void FMTest2()
1.389 + {
1.390 + TEST_PRINT("Testing priority inheritance");
1.391 +
1.392 + NFastSemaphore exitSem(0);
1.393 + SFMTest2InfoC common;
1.394 + common.iMax = 0;
1.395 + common.iStop = FALSE;
1.396 + TInt cpu;
1.397 + TInt threads = 0;
1.398 + SFMTest2InfoT* tinfo[32];
1.399 + memset(tinfo, 0, sizeof(tinfo));
1.400 + DEBUGPRINT("Common info at %08x", &common);
1.401 + for_each_cpu(cpu)
1.402 + {
1.403 + tinfo[threads++] = CreateFMTest2Thread("FMTest2H", common, 500, 7, 7, FALSE, 60-cpu, KSmallTimeslice, exitSem, cpu);
1.404 + tinfo[threads++] = CreateFMTest2Thread("FMTest2L", common, 500, 0, 0, FALSE, 11, KSmallTimeslice, exitSem, cpu);
1.405 + tinfo[threads++] = CreateFMTest2Thread("FMTest2S", common, 10000, 15, 31, TRUE, 32, -1, exitSem, cpu);
1.406 + }
1.407 + tinfo[0]->iDelayThreshold = 0x300;
1.408 + TInt max = 0;
1.409 + TInt i;
1.410 + TInt iter = 0;
1.411 + for (i=0; i<threads; ++i)
1.412 + {
1.413 + NKern::ThreadResume(tinfo[i]->iThread);
1.414 + }
1.415 + FOREVER
1.416 + {
1.417 + NKern::Sleep(5000);
1.418 + DebugPrint(".",1); // only print one char since interrupts are disabled for entire time
1.419 +
1.420 + TInt max_now = common.iMax;
1.421 + if (max_now==max)
1.422 + {
1.423 + if (++iter==20)
1.424 + break;
1.425 + }
1.426 + else
1.427 + {
1.428 + iter = 0;
1.429 + max = max_now;
1.430 + }
1.431 + }
1.432 + common.iStop = TRUE;
1.433 + for (i=0; i<threads; ++i)
1.434 + NKern::FSWait(&exitSem);
1.435 + DebugPrint("\r\n",2);
1.436 + for (i=0; i<threads; ++i)
1.437 + {
1.438 + TEST_PRINT3("%d: Iter %10d Max %10d", i, tinfo[i]->iIterations, tinfo[i]->iMaxDelay);
1.439 + if (i==0)
1.440 + {
1.441 + TEST_RESULT(tinfo[0]->iMaxDelay < 700, "Thread 0 MaxDelay too high");
1.442 + }
1.443 + else if (i==3)
1.444 + {
1.445 + TEST_RESULT(tinfo[3]->iMaxDelay < 1200, "Thread 1 MaxDelay too high");
1.446 + }
1.447 + }
1.448 + for (i=0; i<threads; ++i)
1.449 + delete tinfo[i];
1.450 + }
1.451 +
1.452 +struct SWriterInfo
1.453 + {
1.454 + void DoInOp(TUint aWhich);
1.455 + void DoOutOp(TUint aWhich);
1.456 +
1.457 + TUint32* iBuf[6];
1.458 + TInt iWords;
1.459 + volatile TUint32 iWrites;
1.460 + volatile TUint32 iIn;
1.461 + volatile TBool iStop;
1.462 + NFastMutex* iM;
1.463 + NFastMutexX* iMX;
1.464 + TUint32 iInSeq; // do nibble 0 followed by nibble 1 followed by nibble 2
1.465 + TUint32 iOutSeq; // 0=nothing, 1=mutex, 2=freeze, 3=CS, 4=mutex the long way
1.466 + // 5 = mutexX, 6 = mutexX the long way, 7=join frozen group
1.467 + // 8 = join mutex-holding group, 9=join idle group
1.468 + TInt iFrz;
1.469 + TInt iPriority;
1.470 + TInt iTimeslice;
1.471 + TInt iCpu;
1.472 + NFastSemaphore iHandshake;
1.473 + TUint64 iInitFastCounter;
1.474 + TUint32 iFastCounterDelta;
1.475 + NThread* volatile iIvThrd;
1.476 +
1.477 +#ifdef __SMP__
1.478 + NThreadGroup* iGroup;
1.479 +#endif
1.480 + };
1.481 +
1.482 +void SWriterInfo::DoInOp(TUint aWhich)
1.483 + {
1.484 + switch ((iInSeq>>(aWhich*4))&0xf)
1.485 + {
1.486 + case 0: break;
1.487 + case 1: NKern::FMWait(iM); break;
1.488 + case 2: iFrz=NKern::FreezeCpu(); break;
1.489 + case 3: NKern::ThreadEnterCS(); break;
1.490 + case 4: FMWaitFull(iM); break;
1.491 + case 5: iMX->Wait(); break;
1.492 + case 6: iMX->WaitFull(); break;
1.493 +#ifdef __SMP__
1.494 + case 7:
1.495 + case 8:
1.496 + case 9: NKern::JoinGroup(iGroup); break;
1.497 +#endif
1.498 + }
1.499 + }
1.500 +
1.501 +void SWriterInfo::DoOutOp(TUint aWhich)
1.502 + {
1.503 + switch ((iOutSeq>>(aWhich*4))&0xf)
1.504 + {
1.505 + case 0: break;
1.506 + case 1: NKern::FMSignal(iM); break;
1.507 + case 2: NKern::EndFreezeCpu(iFrz); break;
1.508 + case 3: NKern::ThreadLeaveCS(); break;
1.509 + case 4: FMSignalFull(iM); break;
1.510 + case 5: iMX->Signal(); break;
1.511 + case 6: iMX->SignalFull(); break;
1.512 +#ifdef __SMP__
1.513 + case 7:
1.514 + case 8:
1.515 + case 9: NKern::LeaveGroup(); break;
1.516 +#endif
1.517 + }
1.518 + }
1.519 +
1.520 +struct SReaderInfo
1.521 + {
1.522 + enum TTestType
1.523 + {
1.524 + ETimeslice,
1.525 + ESuspend,
1.526 + EKill,
1.527 + EMigrate,
1.528 + EInterlockedSuspend,
1.529 + EInterlockedKill,
1.530 + EInterlockedMigrate,
1.531 + EMutexLifetime,
1.532 + };
1.533 +
1.534 + TUint32* iBuf[6];
1.535 + TInt iWords;
1.536 + volatile TUint32 iReads;
1.537 + volatile TUint32 iFails[7];
1.538 + volatile TBool iStop;
1.539 + TUint32 iReadLimit;
1.540 + NThread* volatile iWriter;
1.541 + NThread* volatile iReader;
1.542 + NThread* volatile iIvThrd;
1.543 + NThread* iGroupThrd;
1.544 + SWriterInfo* iWriterInfo;
1.545 + TInt iTestType;
1.546 + NFastSemaphore iExitSem;
1.547 + volatile TUint32 iCapturedIn;
1.548 + volatile TBool iSuspendResult;
1.549 + };
1.550 +
1.551 +void WriterThread(TAny* a)
1.552 + {
1.553 + SWriterInfo& info = *(SWriterInfo*)a;
1.554 +// TEST_PRINT(">WR");
1.555 +
1.556 + while (!info.iStop)
1.557 + {
1.558 + NThread* t = (NThread*)__e32_atomic_swp_ord_ptr(&info.iIvThrd, 0);
1.559 + if (t)
1.560 + NKern::ThreadRequestSignal(t);
1.561 + if (!info.iFastCounterDelta)
1.562 + info.iInitFastCounter = fast_counter();
1.563 + TInt n = ++info.iWrites;
1.564 +
1.565 + info.DoInOp(0);
1.566 +
1.567 + info.iBuf[0][0] = n;
1.568 + setup_block_cpu(info.iBuf[0], info.iWords);
1.569 +
1.570 + info.DoInOp(1);
1.571 +
1.572 + info.iBuf[1][0] = n;
1.573 + setup_block_cpu(info.iBuf[1], info.iWords);
1.574 +
1.575 + info.DoInOp(2);
1.576 +
1.577 + if (NKern::CurrentCpu() == info.iCpu)
1.578 + ++info.iIn;
1.579 + info.iBuf[2][0] = n;
1.580 + setup_block_cpu(info.iBuf[2], info.iWords);
1.581 +
1.582 + info.DoOutOp(0);
1.583 +
1.584 + info.iBuf[3][0] = n;
1.585 + setup_block_cpu(info.iBuf[3], info.iWords);
1.586 +
1.587 + info.DoOutOp(1);
1.588 +
1.589 + info.iBuf[4][0] = n;
1.590 + setup_block_cpu(info.iBuf[4], info.iWords);
1.591 +
1.592 + info.DoOutOp(2);
1.593 +
1.594 + info.iBuf[5][0] = n;
1.595 + setup_block_cpu(info.iBuf[5], info.iWords);
1.596 +
1.597 + if (!info.iFastCounterDelta)
1.598 + info.iFastCounterDelta = (TUint32)(fast_counter() - info.iInitFastCounter);
1.599 + if (NKern::CurrentCpu() != info.iCpu)
1.600 + {
1.601 + NKern::FSSignal(&info.iHandshake);
1.602 + NKern::WaitForAnyRequest();
1.603 + }
1.604 + }
1.605 +// TEST_PRINT("<WR");
1.606 + }
1.607 +
1.608 +void ReaderThread(TAny* a)
1.609 + {
1.610 + SReaderInfo& info = *(SReaderInfo*)a;
1.611 + SWriterInfo& winfo = *info.iWriterInfo;
1.612 + TInt this_cpu = NKern::CurrentCpu();
1.613 + NThread* pC = NKern::CurrentThread();
1.614 + info.iReader = pC;
1.615 +// TInt my_pri = pC->i_NThread_BasePri;
1.616 + TBool create_writer = TRUE;
1.617 + NKern::FSSetOwner(&winfo.iHandshake, 0);
1.618 + NFastSemaphore exitSem(0);
1.619 + TUint32 seed[2] = {0,7};
1.620 + TUint32 modulus = 0;
1.621 + TUint32 offset = 0;
1.622 +// TEST_PRINT1(">RD%d",info.iTestType);
1.623 +
1.624 + while (!info.iStop)
1.625 + {
1.626 + TInt i;
1.627 + if (create_writer)
1.628 + goto do_create_writer;
1.629 + if (info.iTestType==SReaderInfo::EMigrate || info.iTestType==SReaderInfo::EInterlockedMigrate)
1.630 + {
1.631 + NKern::FSWait(&winfo.iHandshake);
1.632 + }
1.633 + for (i=0; i<6; ++i)
1.634 + {
1.635 + TInt cpu = verify_block_cpu_no_trace(info.iBuf[i], info.iWords);
1.636 + if (cpu<0)
1.637 + ++info.iFails[i];
1.638 + }
1.639 + ++info.iReads;
1.640 + switch (info.iTestType)
1.641 + {
1.642 + case SReaderInfo::ETimeslice:
1.643 + NKern::ThreadSetTimeslice(info.iWriter, (random(seed) % modulus + offset) );
1.644 + NKern::YieldTimeslice();
1.645 + break;
1.646 + case SReaderInfo::ESuspend:
1.647 + winfo.iIvThrd = info.iIvThrd;
1.648 + NKern::ThreadResume(info.iWriter);
1.649 + break;
1.650 + case SReaderInfo::EKill:
1.651 + NKern::FSWait(&exitSem);
1.652 + create_writer = TRUE;
1.653 + break;
1.654 + case SReaderInfo::EMigrate:
1.655 + NKern::ThreadSetCpuAffinity(info.iWriter, this_cpu);
1.656 + if (info.iGroupThrd)
1.657 + NKern::ThreadSetCpuAffinity(info.iGroupThrd, this_cpu);
1.658 + NKern::ThreadRequestSignal(info.iIvThrd);
1.659 + NKern::ThreadRequestSignal(info.iWriter);
1.660 + break;
1.661 + case SReaderInfo::EInterlockedSuspend:
1.662 + NKern::WaitForAnyRequest();
1.663 + NKern::FMWait(winfo.iM);
1.664 + if (winfo.iIn != info.iCapturedIn && info.iSuspendResult)
1.665 + ++info.iFails[6];
1.666 + winfo.iIvThrd = info.iIvThrd;
1.667 + NKern::ThreadResume(info.iWriter, winfo.iM);
1.668 + break;
1.669 + case SReaderInfo::EInterlockedKill:
1.670 + NKern::WaitForAnyRequest();
1.671 + NKern::FSWait(&exitSem);
1.672 + if (winfo.iIn != info.iCapturedIn)
1.673 + ++info.iFails[6];
1.674 + create_writer = TRUE;
1.675 + break;
1.676 + case SReaderInfo::EInterlockedMigrate:
1.677 + NKern::WaitForAnyRequest();
1.678 + if (winfo.iIn != info.iCapturedIn)
1.679 + ++info.iFails[6];
1.680 + NKern::ThreadSetCpuAffinity(info.iWriter, this_cpu);
1.681 + if (info.iGroupThrd)
1.682 + NKern::ThreadSetCpuAffinity(info.iGroupThrd, this_cpu);
1.683 + NKern::ThreadRequestSignal(info.iIvThrd);
1.684 + NKern::ThreadRequestSignal(info.iWriter);
1.685 + break;
1.686 + }
1.687 +do_create_writer:
1.688 + if (create_writer)
1.689 + {
1.690 + create_writer = FALSE;
1.691 + winfo.iCpu = this_cpu;
1.692 + info.iWriter = CreateUnresumedThreadSignalOnExit("Writer", &WriterThread, winfo.iPriority, &winfo, 0, winfo.iTimeslice, &exitSem, this_cpu);
1.693 + TEST_OOM(info.iWriter);
1.694 + winfo.iIvThrd = info.iIvThrd;
1.695 + NKern::ThreadResume(info.iWriter);
1.696 + while (!winfo.iFastCounterDelta)
1.697 + NKern::Sleep(1);
1.698 + modulus = __fast_counter_to_timeslice_ticks(3*winfo.iFastCounterDelta);
1.699 +// offset = __microseconds_to_timeslice_ticks(64);
1.700 + offset = 1;
1.701 + }
1.702 + }
1.703 + winfo.iStop = TRUE;
1.704 + NKern::FSWait(&exitSem);
1.705 +// TEST_PRINT1("<RD%d",info.iTestType);
1.706 + }
1.707 +
1.708 +void InterventionThread(TAny* a)
1.709 + {
1.710 + SReaderInfo& info = *(SReaderInfo*)a;
1.711 + SWriterInfo& winfo = *info.iWriterInfo;
1.712 + TInt this_cpu = NKern::CurrentCpu();
1.713 + TUint32 seed[2] = {1,0};
1.714 + while (!winfo.iFastCounterDelta)
1.715 + NKern::Sleep(1);
1.716 + TUint32 modulus = 3*winfo.iFastCounterDelta;
1.717 + TUint32 offset = TUint32(fast_counter_freq() / TUint64(100000));
1.718 + NThread* w = info.iWriter;
1.719 + TUint32 lw = 0;
1.720 + TUint32 tc = NKern::TickCount();
1.721 + NKern::FSSetOwner(&info.iExitSem, 0);
1.722 +
1.723 + TEST_PRINT3(">IV%d %d %d", info.iTestType, modulus, offset);
1.724 + FOREVER
1.725 + {
1.726 + if (this_cpu == winfo.iCpu)
1.727 + {
1.728 + NKern::Sleep(1);
1.729 + }
1.730 + else
1.731 + {
1.732 + TUint32 count = random(seed) % modulus;
1.733 + count += offset;
1.734 + fcfspin(count);
1.735 + }
1.736 + if (info.iReads >= info.iReadLimit)
1.737 + {
1.738 + info.iStop = TRUE;
1.739 + winfo.iStop = TRUE;
1.740 + NKern::FSWait(&info.iExitSem);
1.741 + break;
1.742 + }
1.743 + if (winfo.iWrites >= lw + 3*info.iReadLimit)
1.744 + {
1.745 + lw += 3*info.iReadLimit;
1.746 + TEST_PRINT1("#W=%d",winfo.iWrites);
1.747 + }
1.748 + TUint32 tc2 = NKern::TickCount();
1.749 + if ( (tc2 - (tc+KTickLimit)) < 0x80000000 )
1.750 + {
1.751 + tc = tc2;
1.752 + TEST_PRINT1("##W=%d",winfo.iWrites);
1.753 + DumpMemory("WriterThread", w, 0x400);
1.754 + }
1.755 + switch (info.iTestType)
1.756 + {
1.757 + case SReaderInfo::ETimeslice:
1.758 + break;
1.759 + case SReaderInfo::ESuspend:
1.760 + NKern::ThreadSuspend(info.iWriter, 1);
1.761 + NKern::WaitForAnyRequest();
1.762 + break;
1.763 + case SReaderInfo::EKill:
1.764 + {
1.765 + w = info.iWriter;
1.766 + info.iWriter = 0;
1.767 + NKern::ThreadKill(w);
1.768 + NKern::WaitForAnyRequest();
1.769 + break;
1.770 + }
1.771 + case SReaderInfo::EMigrate:
1.772 + NKern::ThreadSetCpuAffinity(info.iWriter, this_cpu);
1.773 + if (info.iGroupThrd)
1.774 + NKern::ThreadSetCpuAffinity(info.iGroupThrd, this_cpu);
1.775 + NKern::WaitForAnyRequest();
1.776 + break;
1.777 + case SReaderInfo::EInterlockedSuspend:
1.778 + {
1.779 +#if 0
1.780 +extern TLinAddr __LastIrqRet;
1.781 +extern TLinAddr __LastSSP;
1.782 +extern TLinAddr __SSTop;
1.783 +extern TUint32 __CaptureStack[1024];
1.784 +extern TLinAddr __InterruptedThread;
1.785 +extern TUint32 __CaptureThread[1024];
1.786 +#endif
1.787 + NKern::FMWait(winfo.iM);
1.788 + info.iCapturedIn = winfo.iIn;
1.789 + info.iSuspendResult = NKern::ThreadSuspend(info.iWriter, 1);
1.790 + NKern::FMSignal(winfo.iM);
1.791 + NKern::ThreadRequestSignal(info.iReader);
1.792 +#if 0
1.793 + NThread* pC = NKern::CurrentThread();
1.794 + TUint32 tc0 = NKern::TickCount();
1.795 + tc0+=1000;
1.796 + FOREVER
1.797 + {
1.798 + TUint32 tc1 = NKern::TickCount();
1.799 + if ((tc1-tc0)<0x80000000u)
1.800 + {
1.801 + DEBUGPRINT("__LastIrqRet = %08x", __LastIrqRet);
1.802 + DEBUGPRINT("__LastSSP = %08x", __LastSSP);
1.803 + DEBUGPRINT("__SSTop = %08x", __SSTop);
1.804 +
1.805 + DumpMemory("WriterStack", __CaptureStack, __SSTop - __LastSSP);
1.806 +
1.807 + DumpMemory("CaptureThread", __CaptureThread, sizeof(NThread));
1.808 +
1.809 + DumpMemory("Writer", info.iWriter, sizeof(NThread));
1.810 +
1.811 + DumpMemory("Reader", info.iReader, sizeof(NThread));
1.812 +
1.813 + DumpMemory("SubSched0", &TheSubSchedulers[0], sizeof(TSubScheduler));
1.814 + }
1.815 + if (pC->iRequestSemaphore.iCount>0)
1.816 + break;
1.817 + }
1.818 +#endif
1.819 + NKern::WaitForAnyRequest();
1.820 + break;
1.821 + }
1.822 + case SReaderInfo::EInterlockedKill:
1.823 + {
1.824 + NKern::FMWait(winfo.iM);
1.825 + info.iCapturedIn = winfo.iIn;
1.826 + w = info.iWriter;
1.827 + info.iWriter = 0;
1.828 + NKern::ThreadKill(w, winfo.iM);
1.829 + NKern::ThreadRequestSignal(info.iReader);
1.830 + NKern::WaitForAnyRequest();
1.831 + break;
1.832 + }
1.833 + case SReaderInfo::EInterlockedMigrate:
1.834 + NKern::FMWait(winfo.iM);
1.835 + info.iCapturedIn = winfo.iIn;
1.836 + NKern::ThreadSetCpuAffinity(info.iWriter, this_cpu);
1.837 + if (info.iGroupThrd)
1.838 + NKern::ThreadSetCpuAffinity(info.iGroupThrd, this_cpu);
1.839 + NKern::FMSignal(winfo.iM);
1.840 + NKern::ThreadRequestSignal(info.iReader);
1.841 + NKern::WaitForAnyRequest();
1.842 + break;
1.843 + }
1.844 + }
1.845 + TEST_PRINT1("<IV%d",info.iTestType);
1.846 + }
1.847 +
1.848 +// State bits 0-7 show how many times timeslices are blocked
1.849 +// State bits 8-15 show how many times suspend/kill are blocked
1.850 +// State bits 16-23 show how many times migration is blocked
1.851 +// State bit 24 set if in CS when fast mutex held
1.852 +// State bit 25 set if CPU frozen when fast mutex held
1.853 +TUint32 UpdateState(TUint32 aS, TUint32 aOp, TBool aOut)
1.854 + {
1.855 + TUint32 x = 0;
1.856 + if (aS & 0xff00)
1.857 + x |= 0x01000000;
1.858 + if (aS & 0xff0000)
1.859 + x |= 0x02000000;
1.860 + if (aOut)
1.861 + {
1.862 + switch (aOp)
1.863 + {
1.864 + case 0:
1.865 + case 9:
1.866 + return aS;
1.867 + case 2:
1.868 + case 7:
1.869 + case 8:
1.870 + return aS-0x010000;
1.871 + case 3:
1.872 + return aS-0x000100;
1.873 + case 1:
1.874 + case 4:
1.875 + return aS-0x010101;
1.876 + }
1.877 + }
1.878 + else
1.879 + {
1.880 + switch (aOp)
1.881 + {
1.882 + case 0:
1.883 + case 9:
1.884 + return aS;
1.885 + case 2:
1.886 + case 7:
1.887 + case 8:
1.888 + return aS+0x010000;
1.889 + case 3:
1.890 + return aS+0x000100;
1.891 + case 1:
1.892 + case 4:
1.893 + return (aS+0x010101)|x;
1.894 + }
1.895 + }
1.896 + return aS;
1.897 + }
1.898 +
1.899 +void CheckResults(SReaderInfo& info)
1.900 + {
1.901 + SWriterInfo& winfo = *info.iWriterInfo;
1.902 + TUint32 state[7];
1.903 + char c[72];
1.904 + memset(c, 32, sizeof(c)), c[71]=0;
1.905 + state[0] = UpdateState(0, (winfo.iInSeq)&0xf, FALSE);
1.906 + state[1] = UpdateState(state[0], (winfo.iInSeq>>4)&0xf, FALSE);
1.907 + state[2] = UpdateState(state[1], (winfo.iInSeq>>8)&0xf, FALSE);
1.908 + state[3] = UpdateState(state[2], (winfo.iOutSeq)&0xf, TRUE);
1.909 + state[4] = UpdateState(state[3], (winfo.iOutSeq>>4)&0xf, TRUE);
1.910 + state[5] = UpdateState(state[4], (winfo.iOutSeq>>8)&0xf, TRUE);
1.911 + state[6] = (state[5] & 0xff000000) ^ 0x07000000;
1.912 +
1.913 + TInt i;
1.914 + for (i=0; i<6; ++i)
1.915 + state[i] &= 0x00ffffff;
1.916 +
1.917 + TEST_PRINT2("Reads %d Writes %d", info.iReads, winfo.iWrites);
1.918 + for(i=0; i<6; ++i)
1.919 + {
1.920 + if (state[i] & 0xff00)
1.921 + c[i*10] = 'S';
1.922 + if (state[i] & 0xff0000)
1.923 + c[i*10+1] = 'M';
1.924 + if (state[i] & 0xff)
1.925 + c[i*10+2] = 'T';
1.926 + }
1.927 + TEST_PRINT1("%s",c);
1.928 + 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]);
1.929 + memset(c, 32, sizeof(c)), c[71]=0;
1.930 + TUint32 mask=0;
1.931 + switch(info.iTestType)
1.932 + {
1.933 + case SReaderInfo::ETimeslice: mask = 0x040000ff; break;
1.934 + case SReaderInfo::ESuspend: mask = 0x0400ff00; break;
1.935 + case SReaderInfo::EKill: mask = 0x0400ff00; break;
1.936 + case SReaderInfo::EMigrate: mask = 0x04ff0000; break;
1.937 + case SReaderInfo::EInterlockedSuspend: mask = 0x0400ff00; break;
1.938 + case SReaderInfo::EInterlockedKill: mask = 0x0100ff00; break;
1.939 + case SReaderInfo::EInterlockedMigrate: mask = 0x02ff0000; break;
1.940 + }
1.941 + TUint32 limit = info.iReads/10;
1.942 + TInt fail=0;
1.943 + for(i=0; i<7; ++i)
1.944 + {
1.945 + TBool bad = FALSE;
1.946 + if (state[i] & mask)
1.947 + bad = (info.iFails[i] > 0);
1.948 + else
1.949 + bad = (info.iFails[i] < limit);
1.950 + if (bad)
1.951 + {
1.952 + ++fail;
1.953 + char* p = c+i*10+3;
1.954 + *p++ = '-';
1.955 + *p++ = '-';
1.956 + *p++ = '-';
1.957 + *p++ = '-';
1.958 + *p++ = '-';
1.959 + *p++ = '-';
1.960 + }
1.961 + }
1.962 + if (fail)
1.963 + {
1.964 + c[0] = 'E';
1.965 + c[1] = 'R';
1.966 + c[2] = 'R';
1.967 + TEST_PRINT1("%s",c);
1.968 + TEST_RESULT(0,"FAILED");
1.969 + }
1.970 + }
1.971 +
1.972 +struct SGroupThreadInfo
1.973 + {
1.974 + TUint32 iInSeq;
1.975 + TUint32 iRun;
1.976 + };
1.977 +
1.978 +void GroupThread(TAny* a)
1.979 + {
1.980 + SGroupThreadInfo& info = *(SGroupThreadInfo*)a;
1.981 + TInt i, frz;
1.982 + NFastMutex mutex;
1.983 + for (i = 0; i<3; ++i)
1.984 + {
1.985 + // Find the first nibble that asks for a group option
1.986 + // and do what it asks for.
1.987 + switch ((info.iInSeq>>(i*4))&0xf)
1.988 + {
1.989 + case 7:
1.990 + frz = NKern::FreezeCpu();
1.991 + NKern::WaitForAnyRequest();
1.992 + NKern::EndFreezeCpu(frz);
1.993 + return;
1.994 + case 8:
1.995 + NKern::FMWait(&mutex);
1.996 + while (__e32_atomic_load_acq32(&info.iRun))
1.997 + nfcfspin(10);
1.998 + NKern::FMSignal(&mutex);
1.999 + return;
1.1000 + }
1.1001 + }
1.1002 + // We weren't needed, but we have to wait to die anyway to avoid lifetime issues
1.1003 + NKern::WaitForAnyRequest();
1.1004 + }
1.1005 +
1.1006 +void DoRWTest(TInt aTestType, TUint32 aReadLimit, TUint32 aInSeq, TUint32 aOutSeq, TInt aRWCpu, TInt aICpu)
1.1007 + {
1.1008 + NFastMutex mutex;
1.1009 + SWriterInfo* winfo = new SWriterInfo;
1.1010 + TEST_OOM(winfo);
1.1011 + memclr(winfo, sizeof(SWriterInfo));
1.1012 + SReaderInfo* info = new SReaderInfo;
1.1013 + TEST_OOM(info);
1.1014 + memclr(info, sizeof(SReaderInfo));
1.1015 + SGroupThreadInfo* gtinfo = new SGroupThreadInfo;
1.1016 + TEST_OOM(gtinfo);
1.1017 + memclr(gtinfo, sizeof(SGroupThreadInfo));
1.1018 + TUint32 bufwords = 256;
1.1019 + TUint32* buf = (TUint32*)malloc(6 * bufwords * sizeof(TUint32));
1.1020 + TEST_OOM(buf);
1.1021 + memclr(buf, 6 * bufwords * sizeof(TUint32));
1.1022 + TInt i;
1.1023 + for (i=0; i<6; ++i)
1.1024 + {
1.1025 + info->iBuf[i] = buf + i * bufwords;
1.1026 + winfo->iBuf[i] = buf + i * bufwords;
1.1027 + }
1.1028 + winfo->iWords = bufwords;
1.1029 + winfo->iM = &mutex;
1.1030 + winfo->iInSeq = aInSeq;
1.1031 + winfo->iOutSeq = aOutSeq;
1.1032 + winfo->iPriority = 11;
1.1033 + winfo->iTimeslice = __microseconds_to_timeslice_ticks(10000);
1.1034 + winfo->iCpu = aRWCpu;
1.1035 +
1.1036 + NFastSemaphore localExit(0);
1.1037 +
1.1038 +#ifdef __SMP__
1.1039 + NThreadGroup group;
1.1040 + SNThreadGroupCreateInfo ginfo;
1.1041 + ginfo.iCpuAffinity = aRWCpu;
1.1042 + TInt r = NKern::GroupCreate(&group, ginfo);
1.1043 + TEST_RESULT(r==KErrNone, "");
1.1044 + winfo->iGroup = &group;
1.1045 + gtinfo->iRun = 1;
1.1046 + gtinfo->iInSeq = aInSeq;
1.1047 + NThread* groupThrd = CreateThreadSignalOnExit("GroupThrd", &GroupThread, 1, gtinfo, 0, KSmallTimeslice, &localExit, aRWCpu, &group);
1.1048 + TEST_OOM(groupThrd);
1.1049 + info->iGroupThrd = groupThrd;
1.1050 + NKern::Sleep(100);
1.1051 +#endif
1.1052 +
1.1053 + info->iWords = bufwords;
1.1054 + info->iReadLimit = aReadLimit;
1.1055 + info->iWriterInfo = winfo;
1.1056 + info->iTestType = aTestType;
1.1057 +
1.1058 + TInt rpri = (aTestType == SReaderInfo::ETimeslice) ? 11 : 10;
1.1059 + NThread* reader = CreateThreadSignalOnExit("Reader", &ReaderThread, rpri, info, 0, -1, &info->iExitSem, aRWCpu);
1.1060 + TEST_OOM(reader);
1.1061 + info->iReader = reader;
1.1062 + NKern::Sleep(10);
1.1063 + NThread* ivt = CreateThreadSignalOnExit("Intervention", &InterventionThread, 12, info, 0, KSmallTimeslice, &localExit, aICpu);
1.1064 + TEST_OOM(ivt);
1.1065 + info->iIvThrd = ivt;
1.1066 +
1.1067 + NKern::FSWait(&localExit);
1.1068 +#ifdef __SMP__
1.1069 + NKern::ThreadRequestSignal(groupThrd);
1.1070 +#endif
1.1071 + __e32_atomic_store_rel32(>info->iRun, 0);
1.1072 + NKern::FSWait(&localExit);
1.1073 +
1.1074 +#ifdef __SMP__
1.1075 + NKern::GroupDestroy(&group);
1.1076 +#endif
1.1077 +
1.1078 + free(buf);
1.1079 +
1.1080 + TEST_PRINT6("Type %d RL %d ISEQ %03x OSEQ %03x RWCPU %d ICPU %d", aTestType, aReadLimit, aInSeq, aOutSeq, aRWCpu, aICpu);
1.1081 + CheckResults(*info);
1.1082 +
1.1083 + free(info);
1.1084 + free(winfo);
1.1085 + free(gtinfo);
1.1086 + }
1.1087 +
1.1088 +
1.1089 +void TestFastMutex()
1.1090 + {
1.1091 + TEST_PRINT("Testing Fast Mutexes...");
1.1092 +
1.1093 + FMTest0();
1.1094 + FMTest1();
1.1095 + FMTest1P();
1.1096 + FMTest2();
1.1097 + }
1.1098 +
1.1099 +void TestSuspendKillMigrate()
1.1100 + {
1.1101 + TEST_PRINT("Testing Suspend/Kill/Migrate...");
1.1102 +
1.1103 + DoRWTest(SReaderInfo::ETimeslice, KReadCount, 0x000, 0x000, 0, 1);
1.1104 + DoRWTest(SReaderInfo::ETimeslice, KReadCount, 0x010, 0x100, 0, 1);
1.1105 + DoRWTest(SReaderInfo::ETimeslice, KReadCount, 0x040, 0x400, 0, 1);
1.1106 + DoRWTest(SReaderInfo::ETimeslice, KReadCount, 0x132, 0x231, 0, 1);
1.1107 + DoRWTest(SReaderInfo::ETimeslice, KReadCount, 0x432, 0x234, 0, 1);
1.1108 + DoRWTest(SReaderInfo::ETimeslice, KReadCount, 0x310, 0x310, 0, 1);
1.1109 + DoRWTest(SReaderInfo::ETimeslice, KReadCount, 0x340, 0x340, 0, 1);
1.1110 +
1.1111 + DoRWTest(SReaderInfo::ESuspend, KReadCount, 0x000, 0x000, 0, 1);
1.1112 + DoRWTest(SReaderInfo::ESuspend, KReadCount, 0x010, 0x100, 0, 1);
1.1113 + DoRWTest(SReaderInfo::ESuspend, KReadCount, 0x040, 0x400, 0, 1);
1.1114 + DoRWTest(SReaderInfo::ESuspend, KReadCount, 0x132, 0x231, 0, 1);
1.1115 + DoRWTest(SReaderInfo::ESuspend, KReadCount, 0x432, 0x234, 0, 1);
1.1116 + DoRWTest(SReaderInfo::ESuspend, KReadCount, 0x310, 0x310, 0, 1);
1.1117 + DoRWTest(SReaderInfo::ESuspend, KReadCount, 0x340, 0x340, 0, 1);
1.1118 +
1.1119 + DoRWTest(SReaderInfo::EKill, KReadCount, 0x000, 0x000, 0, 1);
1.1120 + DoRWTest(SReaderInfo::EKill, KReadCount, 0x010, 0x100, 0, 1);
1.1121 + DoRWTest(SReaderInfo::EKill, KReadCount, 0x040, 0x400, 0, 1);
1.1122 + DoRWTest(SReaderInfo::EKill, KReadCount, 0x132, 0x231, 0, 1);
1.1123 + DoRWTest(SReaderInfo::EKill, KReadCount, 0x432, 0x234, 0, 1);
1.1124 + DoRWTest(SReaderInfo::EKill, KReadCount, 0x310, 0x310, 0, 1);
1.1125 + DoRWTest(SReaderInfo::EKill, KReadCount, 0x340, 0x340, 0, 1);
1.1126 +
1.1127 + DoRWTest(SReaderInfo::EMigrate, KReadCount, 0x000, 0x000, 0, 1);
1.1128 + DoRWTest(SReaderInfo::EMigrate, KReadCount, 0x132, 0x231, 0, 1);
1.1129 + DoRWTest(SReaderInfo::EMigrate, KReadCount, 0x432, 0x234, 0, 1);
1.1130 + DoRWTest(SReaderInfo::EMigrate, KReadCount, 0x020, 0x200, 0, 1);
1.1131 + DoRWTest(SReaderInfo::EMigrate, KReadCount, 0x010, 0x100, 0, 1);
1.1132 + DoRWTest(SReaderInfo::EMigrate, KReadCount, 0x040, 0x400, 0, 1);
1.1133 + DoRWTest(SReaderInfo::EMigrate, KReadCount, 0x030, 0x300, 0, 1);
1.1134 +
1.1135 + DoRWTest(SReaderInfo::EInterlockedSuspend, KReadCount, 0x432, 0x234, 0, 1);
1.1136 + DoRWTest(SReaderInfo::EInterlockedSuspend, KReadCount, 0x040, 0x400, 0, 1);
1.1137 + DoRWTest(SReaderInfo::EInterlockedSuspend, KReadCount, 0x010, 0x100, 0, 1);
1.1138 + DoRWTest(SReaderInfo::EInterlockedSuspend, KReadCount, 0x340, 0x340, 0, 1);
1.1139 + DoRWTest(SReaderInfo::EInterlockedSuspend, KReadCount, 0x310, 0x310, 0, 1);
1.1140 + DoRWTest(SReaderInfo::EInterlockedSuspend, KReadCount, 0x132, 0x231, 0, 1);
1.1141 +
1.1142 + DoRWTest(SReaderInfo::EInterlockedKill, KReadCount, 0x040, 0x400, 0, 1);
1.1143 + DoRWTest(SReaderInfo::EInterlockedKill, KReadCount, 0x010, 0x100, 0, 1);
1.1144 + DoRWTest(SReaderInfo::EInterlockedKill, KReadCount, 0x432, 0x234, 0, 1);
1.1145 + DoRWTest(SReaderInfo::EInterlockedKill, KReadCount, 0x340, 0x340, 0, 1);
1.1146 + DoRWTest(SReaderInfo::EInterlockedKill, KReadCount, 0x132, 0x231, 0, 1);
1.1147 + DoRWTest(SReaderInfo::EInterlockedKill, KReadCount, 0x310, 0x310, 0, 1);
1.1148 +
1.1149 + DoRWTest(SReaderInfo::EInterlockedMigrate, KReadCount, 0x040, 0x400, 0, 1);
1.1150 + DoRWTest(SReaderInfo::EInterlockedMigrate, KReadCount, 0x010, 0x100, 0, 1);
1.1151 + DoRWTest(SReaderInfo::EInterlockedMigrate, KReadCount, 0x310, 0x310, 0, 1);
1.1152 + DoRWTest(SReaderInfo::EInterlockedMigrate, KReadCount, 0x340, 0x340, 0, 1);
1.1153 + DoRWTest(SReaderInfo::EInterlockedMigrate, KReadCount, 0x132, 0x231, 0, 1);
1.1154 + DoRWTest(SReaderInfo::EInterlockedMigrate, KReadCount, 0x432, 0x234, 0, 1);
1.1155 + DoRWTest(SReaderInfo::EInterlockedMigrate, KReadCount, 0x120, 0x210, 0, 1);
1.1156 + DoRWTest(SReaderInfo::EInterlockedMigrate, KReadCount, 0x420, 0x240, 0, 1);
1.1157 +
1.1158 +#ifdef __SMP__
1.1159 + // Tests from above that involve freezing, except by joining a frozen group instead
1.1160 + DoRWTest(SReaderInfo::ETimeslice, KReadCount, 0x137, 0x731, 0, 1);
1.1161 + DoRWTest(SReaderInfo::ETimeslice, KReadCount, 0x437, 0x734, 0, 1);
1.1162 +
1.1163 + DoRWTest(SReaderInfo::ESuspend, KReadCount, 0x137, 0x731, 0, 1);
1.1164 + DoRWTest(SReaderInfo::ESuspend, KReadCount, 0x437, 0x734, 0, 1);
1.1165 +
1.1166 + DoRWTest(SReaderInfo::EKill, KReadCount, 0x137, 0x731, 0, 1);
1.1167 + DoRWTest(SReaderInfo::EKill, KReadCount, 0x437, 0x734, 0, 1);
1.1168 +
1.1169 + DoRWTest(SReaderInfo::EMigrate, KReadCount, 0x137, 0x731, 0, 1);
1.1170 + DoRWTest(SReaderInfo::EMigrate, KReadCount, 0x437, 0x734, 0, 1);
1.1171 + DoRWTest(SReaderInfo::EMigrate, KReadCount, 0x070, 0x700, 0, 1);
1.1172 +
1.1173 + DoRWTest(SReaderInfo::EInterlockedSuspend, KReadCount, 0x437, 0x734, 0, 1);
1.1174 + DoRWTest(SReaderInfo::EInterlockedSuspend, KReadCount, 0x137, 0x731, 0, 1);
1.1175 +
1.1176 + DoRWTest(SReaderInfo::EInterlockedKill, KReadCount, 0x437, 0x734, 0, 1);
1.1177 + DoRWTest(SReaderInfo::EInterlockedKill, KReadCount, 0x137, 0x731, 0, 1);
1.1178 +
1.1179 + DoRWTest(SReaderInfo::EInterlockedMigrate, KReadCount, 0x137, 0x731, 0, 1);
1.1180 + DoRWTest(SReaderInfo::EInterlockedMigrate, KReadCount, 0x437, 0x734, 0, 1);
1.1181 + DoRWTest(SReaderInfo::EInterlockedMigrate, KReadCount, 0x170, 0x710, 0, 1);
1.1182 + DoRWTest(SReaderInfo::EInterlockedMigrate, KReadCount, 0x470, 0x740, 0, 1);
1.1183 +
1.1184 + // Tests from above that involve freezing, except by joining a group with a mutex-holder instead
1.1185 + DoRWTest(SReaderInfo::ETimeslice, KReadCount, 0x138, 0x831, 0, 1);
1.1186 + DoRWTest(SReaderInfo::ETimeslice, KReadCount, 0x438, 0x834, 0, 1);
1.1187 +
1.1188 + DoRWTest(SReaderInfo::ESuspend, KReadCount, 0x138, 0x831, 0, 1);
1.1189 + DoRWTest(SReaderInfo::ESuspend, KReadCount, 0x438, 0x834, 0, 1);
1.1190 +
1.1191 + DoRWTest(SReaderInfo::EKill, KReadCount, 0x138, 0x831, 0, 1);
1.1192 + DoRWTest(SReaderInfo::EKill, KReadCount, 0x438, 0x834, 0, 1);
1.1193 +
1.1194 + DoRWTest(SReaderInfo::EMigrate, KReadCount, 0x138, 0x831, 0, 1);
1.1195 + DoRWTest(SReaderInfo::EMigrate, KReadCount, 0x438, 0x834, 0, 1);
1.1196 + DoRWTest(SReaderInfo::EMigrate, KReadCount, 0x080, 0x800, 0, 1);
1.1197 +
1.1198 + DoRWTest(SReaderInfo::EInterlockedSuspend, KReadCount, 0x438, 0x834, 0, 1);
1.1199 + DoRWTest(SReaderInfo::EInterlockedSuspend, KReadCount, 0x138, 0x831, 0, 1);
1.1200 +
1.1201 + DoRWTest(SReaderInfo::EInterlockedKill, KReadCount, 0x438, 0x834, 0, 1);
1.1202 + DoRWTest(SReaderInfo::EInterlockedKill, KReadCount, 0x138, 0x831, 0, 1);
1.1203 +
1.1204 + DoRWTest(SReaderInfo::EInterlockedMigrate, KReadCount, 0x138, 0x831, 0, 1);
1.1205 + DoRWTest(SReaderInfo::EInterlockedMigrate, KReadCount, 0x438, 0x834, 0, 1);
1.1206 + DoRWTest(SReaderInfo::EInterlockedMigrate, KReadCount, 0x180, 0x810, 0, 1);
1.1207 + DoRWTest(SReaderInfo::EInterlockedMigrate, KReadCount, 0x480, 0x840, 0, 1);
1.1208 +
1.1209 + // Tests from above that have a noop, except join a group that's doing nothing instead
1.1210 + // Most of these do "join group, other op, leave group, undo other op" - this is
1.1211 + // supposed to work, even though you can't *join* a group while frozen or holding a mutex
1.1212 + DoRWTest(SReaderInfo::ETimeslice, KReadCount, 0x090, 0x900, 0, 1);
1.1213 + DoRWTest(SReaderInfo::ETimeslice, KReadCount, 0x019, 0x190, 0, 1);
1.1214 + DoRWTest(SReaderInfo::ETimeslice, KReadCount, 0x049, 0x490, 0, 1);
1.1215 + DoRWTest(SReaderInfo::ETimeslice, KReadCount, 0x319, 0x319, 0, 1);
1.1216 + DoRWTest(SReaderInfo::ETimeslice, KReadCount, 0x349, 0x349, 0, 1);
1.1217 +
1.1218 + DoRWTest(SReaderInfo::ESuspend, KReadCount, 0x090, 0x900, 0, 1);
1.1219 + DoRWTest(SReaderInfo::ESuspend, KReadCount, 0x019, 0x190, 0, 1);
1.1220 + DoRWTest(SReaderInfo::ESuspend, KReadCount, 0x049, 0x490, 0, 1);
1.1221 + DoRWTest(SReaderInfo::ESuspend, KReadCount, 0x319, 0x319, 0, 1);
1.1222 + DoRWTest(SReaderInfo::ESuspend, KReadCount, 0x349, 0x349, 0, 1);
1.1223 +
1.1224 + DoRWTest(SReaderInfo::EKill, KReadCount, 0x090, 0x900, 0, 1);
1.1225 + DoRWTest(SReaderInfo::EKill, KReadCount, 0x019, 0x190, 0, 1);
1.1226 + DoRWTest(SReaderInfo::EKill, KReadCount, 0x049, 0x490, 0, 1);
1.1227 + DoRWTest(SReaderInfo::EKill, KReadCount, 0x319, 0x319, 0, 1);
1.1228 + DoRWTest(SReaderInfo::EKill, KReadCount, 0x349, 0x349, 0, 1);
1.1229 +
1.1230 + DoRWTest(SReaderInfo::EMigrate, KReadCount, 0x090, 0x900, 0, 1);
1.1231 + DoRWTest(SReaderInfo::EMigrate, KReadCount, 0x029, 0x290, 0, 1);
1.1232 + DoRWTest(SReaderInfo::EMigrate, KReadCount, 0x019, 0x190, 0, 1);
1.1233 + DoRWTest(SReaderInfo::EMigrate, KReadCount, 0x049, 0x490, 0, 1);
1.1234 + DoRWTest(SReaderInfo::EMigrate, KReadCount, 0x039, 0x390, 0, 1);
1.1235 +
1.1236 + DoRWTest(SReaderInfo::EInterlockedSuspend, KReadCount, 0x049, 0x490, 0, 1);
1.1237 + DoRWTest(SReaderInfo::EInterlockedSuspend, KReadCount, 0x019, 0x190, 0, 1);
1.1238 + DoRWTest(SReaderInfo::EInterlockedSuspend, KReadCount, 0x349, 0x349, 0, 1);
1.1239 + DoRWTest(SReaderInfo::EInterlockedSuspend, KReadCount, 0x319, 0x319, 0, 1);
1.1240 +
1.1241 + DoRWTest(SReaderInfo::EInterlockedKill, KReadCount, 0x049, 0x490, 0, 1);
1.1242 + DoRWTest(SReaderInfo::EInterlockedKill, KReadCount, 0x019, 0x190, 0, 1);
1.1243 + DoRWTest(SReaderInfo::EInterlockedKill, KReadCount, 0x349, 0x349, 0, 1);
1.1244 + DoRWTest(SReaderInfo::EInterlockedKill, KReadCount, 0x319, 0x319, 0, 1);
1.1245 +
1.1246 + DoRWTest(SReaderInfo::EInterlockedMigrate, KReadCount, 0x049, 0x490, 0, 1);
1.1247 + DoRWTest(SReaderInfo::EInterlockedMigrate, KReadCount, 0x019, 0x190, 0, 1);
1.1248 + DoRWTest(SReaderInfo::EInterlockedMigrate, KReadCount, 0x319, 0x319, 0, 1);
1.1249 + DoRWTest(SReaderInfo::EInterlockedMigrate, KReadCount, 0x349, 0x349, 0, 1);
1.1250 + DoRWTest(SReaderInfo::EInterlockedMigrate, KReadCount, 0x129, 0x219, 0, 1);
1.1251 + DoRWTest(SReaderInfo::EInterlockedMigrate, KReadCount, 0x429, 0x249, 0, 1);
1.1252 +
1.1253 + // Test freezing or acquiring a mutex while in a group that also does one of those things
1.1254 + // and then leave the group.
1.1255 + DoRWTest(SReaderInfo::ETimeslice, KReadCount, 0x017, 0x170, 0, 1);
1.1256 + DoRWTest(SReaderInfo::ETimeslice, KReadCount, 0x018, 0x180, 0, 1);
1.1257 + DoRWTest(SReaderInfo::ETimeslice, KReadCount, 0x027, 0x270, 0, 1);
1.1258 + DoRWTest(SReaderInfo::ETimeslice, KReadCount, 0x028, 0x280, 0, 1);
1.1259 +
1.1260 + DoRWTest(SReaderInfo::ESuspend, KReadCount, 0x017, 0x170, 0, 1);
1.1261 + DoRWTest(SReaderInfo::ESuspend, KReadCount, 0x018, 0x180, 0, 1);
1.1262 + DoRWTest(SReaderInfo::ESuspend, KReadCount, 0x027, 0x270, 0, 1);
1.1263 + DoRWTest(SReaderInfo::ESuspend, KReadCount, 0x028, 0x280, 0, 1);
1.1264 +
1.1265 + DoRWTest(SReaderInfo::EKill, KReadCount, 0x017, 0x170, 0, 1);
1.1266 + DoRWTest(SReaderInfo::EKill, KReadCount, 0x018, 0x180, 0, 1);
1.1267 + DoRWTest(SReaderInfo::EKill, KReadCount, 0x027, 0x270, 0, 1);
1.1268 + DoRWTest(SReaderInfo::EKill, KReadCount, 0x028, 0x280, 0, 1);
1.1269 +
1.1270 + DoRWTest(SReaderInfo::EMigrate, KReadCount, 0x017, 0x170, 0, 1);
1.1271 + DoRWTest(SReaderInfo::EMigrate, KReadCount, 0x018, 0x180, 0, 1);
1.1272 + DoRWTest(SReaderInfo::EMigrate, KReadCount, 0x027, 0x270, 0, 1);
1.1273 + DoRWTest(SReaderInfo::EMigrate, KReadCount, 0x028, 0x280, 0, 1);
1.1274 +
1.1275 + DoRWTest(SReaderInfo::EInterlockedSuspend, KReadCount, 0x017, 0x170, 0, 1);
1.1276 + DoRWTest(SReaderInfo::EInterlockedSuspend, KReadCount, 0x018, 0x180, 0, 1);
1.1277 +
1.1278 + DoRWTest(SReaderInfo::EInterlockedKill, KReadCount, 0x017, 0x170, 0, 1);
1.1279 + DoRWTest(SReaderInfo::EInterlockedKill, KReadCount, 0x018, 0x180, 0, 1);
1.1280 +
1.1281 + DoRWTest(SReaderInfo::EInterlockedMigrate, KReadCount, 0x017, 0x170, 0, 1);
1.1282 + DoRWTest(SReaderInfo::EInterlockedMigrate, KReadCount, 0x018, 0x180, 0, 1);
1.1283 +#endif
1.1284 +}