1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kerneltest/e32test/prime/t_semutx2.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1414 @@
1.4 +// Copyright (c) 1995-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\prime\t_semutx2.cpp
1.18 +// Test RSemaphore and RMutex
1.19 +// Overview:
1.20 +// Tests the RSemaphore and RMutex
1.21 +// API Information:
1.22 +// RSemaphore, RMutex
1.23 +// Details:
1.24 +// - Test and verify that thread priorities work as expected.
1.25 +// - Test and verify that signalling an RMutex from the wrong
1.26 +// thread fails as expected.
1.27 +// - Test and verify that mutex priority inheritance works as
1.28 +// expected.
1.29 +// - Perform an exhaustive state transition test using mutexs
1.30 +// and up to ten threads. Verify priorities, order of execution,
1.31 +// mutex signalling, suspend, resume, kill and close. Verify
1.32 +// results are as expected.
1.33 +// - Test semaphore speed by counting how many Wait/Signal
1.34 +// operations can be completed in one second.
1.35 +// Platforms/Drives/Compatibility:
1.36 +// All.
1.37 +// Assumptions/Requirement/Pre-requisites:
1.38 +// Failures and causes:
1.39 +// Base Port information:
1.40 +//
1.41 +//
1.42 +
1.43 +#include <e32test.h>
1.44 +
1.45 +RMutex M1;
1.46 +RMutex M2;
1.47 +RSemaphore S;
1.48 +
1.49 +const TInt KBufferSize=4096;
1.50 +TUint ThreadId[KBufferSize];
1.51 +TInt PutIx;
1.52 +TInt GetIx;
1.53 +TInt Count;
1.54 +RThread Main;
1.55 +
1.56 +
1.57 +RTest test(_L("T_SEMUTX2"));
1.58 +
1.59 +/*****************************************************************************
1.60 + * Utility functions / macros
1.61 + *****************************************************************************/
1.62 +#define TRACE_ON User::SetDebugMask(0xffdfffff);
1.63 +#define TRACE_OFF User::SetDebugMask(0x80000000);
1.64 +
1.65 +//#define MCOUNT(m,c) test((m).Count() ==(c))
1.66 +// mutex count value is not visible for user any more
1.67 +#define MCOUNT(m,c) (void)(1)
1.68 +#define IDCHECK(x) test(GetNextId()==(x))
1.69 +#define NUMCHECK(x) test(NumIdsPending()==(x))
1.70 +
1.71 +#define id0 id[0]
1.72 +#define id1 id[1]
1.73 +#define id2 id[2]
1.74 +#define id3 id[3]
1.75 +#define id4 id[4]
1.76 +#define id5 id[5]
1.77 +#define id6 id[6]
1.78 +#define id7 id[7]
1.79 +#define id8 id[8]
1.80 +#define id9 id[9]
1.81 +#define id10 id[10]
1.82 +
1.83 +TBool Exists(const TDesC& aName)
1.84 + {
1.85 + TFullName n(RProcess().Name());
1.86 + n+=_L("::");
1.87 + n+=aName;
1.88 + TFindThread ft(n);
1.89 + TFullName fn;
1.90 + return ft.Next(fn)==KErrNone;
1.91 + }
1.92 +
1.93 +TBool Exists(TInt aNum)
1.94 + {
1.95 + TBuf<4> b;
1.96 + b.Num(aNum);
1.97 + return Exists(b);
1.98 + }
1.99 +
1.100 +void BusyWait(TInt aMicroseconds)
1.101 + {
1.102 + TTime begin;
1.103 + begin.HomeTime();
1.104 + FOREVER
1.105 + {
1.106 + TTime now;
1.107 + now.HomeTime();
1.108 + TTimeIntervalMicroSeconds iv=now.MicroSecondsFrom(begin);
1.109 + if (iv.Int64()>=TInt64(aMicroseconds))
1.110 + return;
1.111 + }
1.112 + }
1.113 +
1.114 +void Kick(RThread& t)
1.115 + {
1.116 + TRequestStatus s;
1.117 + TRequestStatus* pS=&s;
1.118 + t.RequestComplete(pS,0);
1.119 + }
1.120 +
1.121 +TUint GetNextId()
1.122 + {
1.123 + if (GetIx<PutIx)
1.124 + return ThreadId[GetIx++];
1.125 + return 0;
1.126 + }
1.127 +
1.128 +TInt NumIdsPending()
1.129 + {
1.130 + return PutIx-GetIx;
1.131 + }
1.132 +
1.133 +/*****************************************************************************
1.134 + * General tests
1.135 + *****************************************************************************/
1.136 +TInt Test0Thread(TAny* aPtr)
1.137 + {
1.138 + TInt& count=*(TInt*)aPtr;
1.139 + ++count;
1.140 + Main.SetPriority(EPriorityMuchMore);
1.141 + ++count;
1.142 + Main.SetPriority(EPriorityMuchMore);
1.143 + ++count;
1.144 + RThread().SetPriority(EPriorityNormal);
1.145 + ++count;
1.146 + return 0;
1.147 + }
1.148 +
1.149 +void Test0()
1.150 + {
1.151 + User::After(100000); // Test fails intermittently on hardware unless we pause here
1.152 +
1.153 + test.Start(_L("Test thread priorities work"));
1.154 + test.Next(_L("Create thread"));
1.155 + RThread t;
1.156 + TInt count=0;
1.157 + TRequestStatus s;
1.158 + TInt r=t.Create(_L("Test0"),Test0Thread,0x1000,NULL,&count);
1.159 + test(r==KErrNone);
1.160 + t.Logon(s);
1.161 + test(r==KErrNone);
1.162 + User::After(10000); // make sure we have a full timeslice
1.163 + t.Resume();
1.164 +
1.165 + test(count==0); // t shouldn't have run yet
1.166 + RThread().SetPriority(EPriorityMuchMore); // shouldn't reschedule (priority unchanged)
1.167 + test(count==0);
1.168 + RThread().SetPriority(EPriorityMore); // shouldn't reschedule (priority decreasing, but not enough)
1.169 + test(count==0);
1.170 + RThread().SetPriority(EPriorityMuchMore); // shouldn't reschedule (priority increasing)
1.171 + test(count==0);
1.172 + RThread().SetPriority(EPriorityNormal); // should reschedule (we go behind t)
1.173 + test(count==1);
1.174 + RThread().SetPriority(EPriorityLess); // should reschedule (priority decreasing to below t)
1.175 + test(count==2);
1.176 + t.SetPriority(EPriorityMuchMore); // shouldn't reschedule (round-robin, timeslice not expired)
1.177 + test(count==2);
1.178 + t.SetPriority(EPriorityNormal); // shouldn't reschedule (t's priority decreasing)
1.179 + test(count==2);
1.180 + t.SetPriority(EPriorityNormal); // shouldn't reschedule (t's priority unchanged)
1.181 + test(count==2);
1.182 + BusyWait(100000); // use up our timeslice
1.183 + t.SetPriority(EPriorityMuchMore); // should reschedule (round-robin, timeslice expired)
1.184 + test(count==3);
1.185 + test(s==KRequestPending);
1.186 + test(t.ExitType()==EExitPending);
1.187 + t.SetPriority(EPriorityRealTime); // should reschedule (t increases above current)
1.188 + test(count==4);
1.189 + test(s==KErrNone); // t should have exited
1.190 + test(t.ExitType()==EExitKill);
1.191 + User::WaitForRequest(s);
1.192 + RThread().SetPriority(EPriorityMuchMore);
1.193 + t.Close();
1.194 + test.End();
1.195 + }
1.196 +
1.197 +TInt Test1Thread(TAny*)
1.198 + {
1.199 + M1.Signal();
1.200 + return 0;
1.201 + }
1.202 +
1.203 +void Test1()
1.204 + {
1.205 + test.Start(_L("Test signalling from wrong thread"));
1.206 + TInt r=M1.CreateLocal();
1.207 + test(r==KErrNone);
1.208 + M1.Wait();
1.209 + RThread t;
1.210 + r=t.Create(_L("Test1"),Test1Thread,0x1000,NULL,NULL);
1.211 + test(r==KErrNone);
1.212 + TRequestStatus s;
1.213 + t.Logon(s);
1.214 + t.Resume();
1.215 + TBool jit = User::JustInTime();
1.216 + User::SetJustInTime(EFalse);
1.217 + User::WaitForRequest(s);
1.218 + User::SetJustInTime(jit);
1.219 + test(s==EAccessDenied);
1.220 + test(t.ExitType()==EExitPanic);
1.221 + test(t.ExitReason()==EAccessDenied);
1.222 + test(t.ExitCategory()==_L("KERN-EXEC"));
1.223 + t.Close();
1.224 + M1.Close();
1.225 + test.End();
1.226 + }
1.227 +
1.228 +/*****************************************************************************
1.229 + * Mutex priority inheritance
1.230 + *****************************************************************************/
1.231 +
1.232 +const TInt KTestDelay = 1000000;
1.233 +
1.234 +TInt LowThread(TAny* aPtr)
1.235 + {
1.236 + TInt& count=*(TInt*)aPtr;
1.237 + FOREVER
1.238 + {
1.239 + M1.Wait();
1.240 + ++count;
1.241 + BusyWait(KTestDelay);
1.242 + M1.Signal();
1.243 + User::WaitForAnyRequest();
1.244 + }
1.245 + }
1.246 +
1.247 +TInt MedThread(TAny* aPtr)
1.248 + {
1.249 + TInt& count=*(TInt*)aPtr;
1.250 + FOREVER
1.251 + {
1.252 + ++count;
1.253 + User::WaitForAnyRequest();
1.254 + }
1.255 + }
1.256 +
1.257 +TInt HighThread(TAny* aPtr)
1.258 + {
1.259 + TInt& count=*(TInt*)aPtr;
1.260 + FOREVER
1.261 + {
1.262 + M2.Wait();
1.263 + ++count;
1.264 + M1.Wait();
1.265 + ++count;
1.266 + BusyWait(KTestDelay);
1.267 + M1.Signal();
1.268 + M2.Signal();
1.269 + User::WaitForAnyRequest();
1.270 + }
1.271 + }
1.272 +
1.273 +void TestMutex1()
1.274 + {
1.275 + test.Start(_L("Test mutex priority inheritance"));
1.276 +
1.277 + test.Next(_L("Create mutex"));
1.278 + TInt r=M1.CreateLocal();
1.279 + test(r==KErrNone);
1.280 +
1.281 + test.Next(_L("Create low priority thread"));
1.282 + TInt lowcount=0;
1.283 + RThread low;
1.284 + r=low.Create(_L("low"),LowThread,0x1000,NULL,&lowcount);
1.285 + test(r==KErrNone);
1.286 + low.SetPriority(EPriorityMuchLess);
1.287 + test(Exists(_L("low")));
1.288 +
1.289 + test.Next(_L("Create medium priority thread"));
1.290 + TInt medcount=0;
1.291 + RThread med;
1.292 + r=med.Create(_L("med"),MedThread,0x1000,NULL,&medcount);
1.293 + test(r==KErrNone);
1.294 + med.SetPriority(EPriorityNormal);
1.295 + test(Exists(_L("med")));
1.296 +
1.297 + test.Next(_L("Start low priority thread"));
1.298 + low.Resume();
1.299 + User::AfterHighRes(KTestDelay/10);
1.300 + test(lowcount==1);
1.301 +// MCOUNT(M1,0);
1.302 +
1.303 + test.Next(_L("Start medium priority thread"));
1.304 + med.Resume();
1.305 + User::AfterHighRes(KTestDelay/10);
1.306 + test(medcount==1);
1.307 + Kick(med);
1.308 + User::AfterHighRes(KTestDelay/10);
1.309 + test(medcount==2);
1.310 + Kick(med);
1.311 +
1.312 + M1.Wait();
1.313 + test(lowcount==1);
1.314 + test(medcount==2);
1.315 + test.Next(_L("Wait, check medium runs"));
1.316 + User::AfterHighRes(KTestDelay/10);
1.317 + test(medcount==3);
1.318 + M1.Signal();
1.319 +
1.320 + test.Next(_L("Create mutex 2"));
1.321 + r=M2.CreateLocal();
1.322 + test(r==KErrNone);
1.323 +
1.324 + test.Next(_L("Create high priority thread"));
1.325 + TInt highcount=0;
1.326 + RThread high;
1.327 + r=high.Create(_L("high"),HighThread,0x1000,NULL,&highcount);
1.328 + test(r==KErrNone);
1.329 + high.SetPriority(EPriorityMore);
1.330 + test(Exists(_L("high")));
1.331 +
1.332 + Kick(low);
1.333 + User::AfterHighRes(KTestDelay/10);
1.334 +// MCOUNT(M1,0);
1.335 + Kick(med);
1.336 +
1.337 +// MCOUNT(M2,1);
1.338 + high.Resume();
1.339 + User::AfterHighRes(KTestDelay/10);
1.340 +// MCOUNT(M2,0);
1.341 +// MCOUNT(M1,-1);
1.342 + test(highcount==1);
1.343 +
1.344 + M2.Wait();
1.345 + test(lowcount==2);
1.346 + test(medcount==3);
1.347 + test(highcount==2);
1.348 + test.Next(_L("Wait, check medium runs"));
1.349 + User::AfterHighRes(KTestDelay/10);
1.350 + test(medcount==4);
1.351 + M2.Signal();
1.352 +
1.353 + test.Next(_L("Kill threads"));
1.354 + low.Kill(0);
1.355 + med.Kill(0);
1.356 + high.Kill(0);
1.357 + low.Close();
1.358 + med.Close();
1.359 + high.Close();
1.360 + test(!Exists(_L("low")));
1.361 + test(!Exists(_L("med")));
1.362 + test(!Exists(_L("high")));
1.363 +
1.364 + M1.Close();
1.365 + test.End();
1.366 + }
1.367 +
1.368 +/*****************************************************************************
1.369 + * Utilities for mutex exhaustive state transition test
1.370 + *****************************************************************************/
1.371 +void MutexWait()
1.372 + {
1.373 + M1.Wait();
1.374 + ++Count;
1.375 + ThreadId[PutIx++]=(TUint)RThread().Id();
1.376 + }
1.377 +
1.378 +void MutexSignal()
1.379 + {
1.380 + M1.Signal();
1.381 + }
1.382 +
1.383 +typedef void (*PFV)(void);
1.384 +TInt ThreadFunction(TAny* aPtr)
1.385 + {
1.386 + PFV& f=*(PFV*)aPtr;
1.387 + FOREVER
1.388 + {
1.389 + MutexWait();
1.390 + if (f)
1.391 + f();
1.392 + MutexSignal();
1.393 + User::WaitForAnyRequest();
1.394 + }
1.395 + }
1.396 +
1.397 +void Exit()
1.398 + {
1.399 + User::Exit(0);
1.400 + }
1.401 +
1.402 +TUint CreateThread(RThread& t, TInt n, TAny* aPtr)
1.403 + {
1.404 + TBuf<4> b;
1.405 + b.Num(n);
1.406 + TInt r=t.Create(b,ThreadFunction,0x1000,NULL,aPtr);
1.407 + test(r==KErrNone);
1.408 + t.Resume();
1.409 + TUint id=t.Id();
1.410 + test.Printf(_L("id=%d\n"),id);
1.411 + return id;
1.412 + }
1.413 +
1.414 +/*
1.415 +Possible thread relationships with mutex:
1.416 + Holding
1.417 + Waiting
1.418 + Waiting + suspended
1.419 + Hold Pending
1.420 +
1.421 +Need to verify correct behaviour when the following actions occur for each of these states:
1.422 + Suspend thread
1.423 + Resume thread
1.424 + Change thread priority
1.425 + Thread exits
1.426 + Thread is killed
1.427 + Mutex deleted
1.428 +*/
1.429 +
1.430 +PFV HoldExtra;
1.431 +void KickMain()
1.432 + {
1.433 + RThread me;
1.434 + Kick(Main);
1.435 + User::WaitForAnyRequest();
1.436 + me.SetPriority(EPriorityMuchMore);
1.437 + MutexSignal(); // this should wake up t8
1.438 + MutexWait();
1.439 + MutexSignal(); // this should wake up t9
1.440 + MutexWait();
1.441 + Kick(Main);
1.442 + User::WaitForAnyRequest();
1.443 + if (HoldExtra)
1.444 + HoldExtra();
1.445 + }
1.446 +
1.447 +void RackEmUp(RThread* t, PFV* f, TUint* id)
1.448 + {
1.449 + // set up t4 holding
1.450 + // t1, t2, t5, t10 waiting
1.451 + // t3, t6, t7 waiting+suspended
1.452 + // t8, t9 pending
1.453 + MCOUNT(M1,1); // check mutex free
1.454 + Kick(t[4]);
1.455 + f[4]=&KickMain;
1.456 + User::WaitForAnyRequest();
1.457 + MCOUNT(M1,0); // check mutex now held
1.458 + TInt i;
1.459 + for (i=1; i<=10; ++i)
1.460 + if (i!=4)
1.461 + Kick(t[i]); // wake up threads
1.462 + User::After(50000); // let threads wait
1.463 + MCOUNT(M1,-9); // check 9 threads waiting
1.464 + Kick(t[4]);
1.465 + User::WaitForAnyRequest();
1.466 + MCOUNT(M1,-7); // check 7 threads waiting
1.467 + NUMCHECK(3);
1.468 + IDCHECK(id4); // from the initial wait
1.469 + IDCHECK(id4); // now have t8, t9 pending, t4 holding, rest waiting
1.470 + IDCHECK(id4); // now have t8, t9 pending, t4 holding, rest waiting
1.471 + t[4].SetPriority(EPriorityNormal);
1.472 + t[7].Resume(); // test resume when not suspended
1.473 + MCOUNT(M1,-7); // check 7 threads waiting
1.474 + t[3].Suspend();
1.475 + t[6].Suspend();
1.476 + t[7].Suspend(); // now have required state
1.477 + t[3].Suspend(); // suspend and resume t3 again for good measure
1.478 + t[3].Resume();
1.479 + MCOUNT(M1,-7); // check 7 threads waiting
1.480 + HoldExtra=NULL;
1.481 + }
1.482 +
1.483 +void SimpleCheck(TInt n, const TUint* id, ...)
1.484 + {
1.485 + VA_LIST list;
1.486 + VA_START(list,id);
1.487 + User::After(50000); // let stuff happen
1.488 + NUMCHECK(n);
1.489 + TInt i;
1.490 + for (i=0; i<n; ++i)
1.491 + {
1.492 + TInt tn=VA_ARG(list,TInt);
1.493 + IDCHECK(id[tn]);
1.494 + }
1.495 + }
1.496 +
1.497 +void Resurrect(TInt n, TThreadPriority aPriority, RThread* t, PFV* f, TUint* id)
1.498 + {
1.499 + f[n]=NULL;
1.500 + id[n]=CreateThread(t[n],n,f+n);
1.501 + t[n].SetPriority(EPriorityRealTime);
1.502 + t[n].SetPriority(aPriority);
1.503 + NUMCHECK(1);
1.504 + IDCHECK(id[n]);
1.505 + }
1.506 +
1.507 +/*****************************************************************************
1.508 + * Mutex exhaustive state transition test
1.509 + *****************************************************************************/
1.510 +void TestMutex2()
1.511 + {
1.512 + test.Start(_L("Test mutex state transitions"));
1.513 + RThread t[11];
1.514 + TUint id[11];
1.515 + PFV f[11]={NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
1.516 + id[0]=(TUint)RThread().Id();
1.517 + PutIx=0;
1.518 + GetIx=0;
1.519 + Count=0;
1.520 + test.Next(_L("Create mutex"));
1.521 + TInt r=M1.CreateLocal();
1.522 + test(r==KErrNone);
1.523 + MCOUNT(M1,1);
1.524 + MutexWait();
1.525 + MCOUNT(M1,0);
1.526 + IDCHECK(id[0]);
1.527 + test.Next(_L("Create threads"));
1.528 + TInt i;
1.529 + for (i=1; i<=5; ++i)
1.530 + id[i]=CreateThread(t[i],i,f+i);
1.531 + User::After(50000); // let threads wait on mutex
1.532 + MCOUNT(M1,-5); // check 5 threads waiting
1.533 + for (i=-4; i<=0; ++i)
1.534 + {
1.535 + MutexSignal(); // wake up next thread
1.536 + MutexWait();
1.537 + MCOUNT(M1,i); // check right number of threads waiting
1.538 + IDCHECK(id0); // check we got mutex back straight away
1.539 + }
1.540 + MutexSignal();
1.541 + User::After(50000); // let threads claim mutex
1.542 + MutexWait();
1.543 + MCOUNT(M1,0); // check no threads waiting
1.544 + for (i=1; i<=5; ++i)
1.545 + {
1.546 + IDCHECK(id[i]); // check they ran in order t1...t5
1.547 + Kick(t[i]); // wake up thread
1.548 + }
1.549 + IDCHECK(id0); // check we got it back last
1.550 + t[4].SetPriority(EPriorityMore); // make t4 higher priority
1.551 + User::After(50000); // let threads wait on mutex
1.552 + MCOUNT(M1,-5); // check 5 threads waiting
1.553 +// temp = M1.Count();
1.554 + MutexSignal();
1.555 +// temp = M1.Count();
1.556 + User::After(50000); // let threads claim mutex
1.557 + MutexWait();
1.558 +// temp = M1.Count();
1.559 + MCOUNT(M1,0); // check no threads waiting
1.560 + IDCHECK(id4); // check they ran in order t4,t1,t2,t3,t5
1.561 + IDCHECK(id1);
1.562 + IDCHECK(id2);
1.563 + IDCHECK(id3);
1.564 + IDCHECK(id5);
1.565 + IDCHECK(id0);
1.566 + t[4].SetPriority(EPriorityNormal); // make t4 normal priority
1.567 + for (i=1; i<=5; ++i)
1.568 + Kick(t[i]); // wake up thread
1.569 + User::After(50000); // let threads wait on mutex
1.570 + MCOUNT(M1,-5); // check 5 threads waiting
1.571 +
1.572 + t[3].SetPriority(EPriorityMore); // make t3 higher priority
1.573 +// temp = M1.Count();
1.574 + MutexSignal();
1.575 +// temp = M1.Count();
1.576 + User::After(50000); // let threads claim mutex
1.577 + MutexWait();
1.578 +// temp = M1.Count();
1.579 + MCOUNT(M1,0); // check no threads waiting
1.580 + IDCHECK(id3); // check they ran in order t3,t1,t2,t4,t5
1.581 + IDCHECK(id1);
1.582 + IDCHECK(id2);
1.583 + IDCHECK(id4);
1.584 + IDCHECK(id5);
1.585 + IDCHECK(id0);
1.586 + t[3].SetPriority(EPriorityNormal); // make t4 normal priority
1.587 + for (i=1; i<=5; ++i)
1.588 + Kick(t[i]); // wake up threads
1.589 + User::After(50000); // let threads wait on mutex
1.590 + MCOUNT(M1,-5); // check 5 threads waiting
1.591 +
1.592 + t[2].SetPriority(EPriorityMore); // make t2 higher priority
1.593 + t[1].SetPriority(EPriorityLess); // make t1 lower priority
1.594 + MutexSignal();
1.595 + User::After(50000); // let threads claim mutex
1.596 + MutexWait();
1.597 + MCOUNT(M1,0); // check no threads waiting
1.598 + IDCHECK(id2); // check they ran in order t2,t3,t4,t5,t1
1.599 + IDCHECK(id3);
1.600 + IDCHECK(id4);
1.601 + IDCHECK(id5);
1.602 + IDCHECK(id1);
1.603 + IDCHECK(id0);
1.604 +
1.605 + for (i=1; i<=5; ++i)
1.606 + Kick(t[i]); // wake up threads
1.607 + User::After(50000); // let threads wait on mutex
1.608 + MCOUNT(M1,-5); // check 5 threads waiting
1.609 + MutexSignal();
1.610 + User::After(50000); // let threads claim mutex
1.611 + MutexWait();
1.612 + MCOUNT(M1,0); // check no threads waiting
1.613 + IDCHECK(id2); // check they ran in order t2,t3,t4,t5,t1
1.614 + IDCHECK(id3);
1.615 + IDCHECK(id4);
1.616 + IDCHECK(id5);
1.617 + IDCHECK(id1);
1.618 + IDCHECK(id0);
1.619 +
1.620 + test(Exists(2));
1.621 + for (i=1; i<=5; ++i)
1.622 + Kick(t[i]); // wake up threads
1.623 + User::After(50000); // let threads wait on mutex
1.624 + MCOUNT(M1,-5); // check 5 threads waiting
1.625 + f[2]=&Exit; // make t2 exit while holding the mutex
1.626 + MutexSignal();
1.627 + User::After(50000); // let threads claim mutex
1.628 + MutexWait();
1.629 + MCOUNT(M1,0); // check no threads waiting
1.630 + test(t[2].ExitType()==EExitKill); // check t2 has exited
1.631 + t[2].Close();
1.632 + test(!Exists(2));
1.633 + IDCHECK(id2); // check they ran in order t2,t3,t4,t5,t1
1.634 + IDCHECK(id3);
1.635 + IDCHECK(id4);
1.636 + IDCHECK(id5);
1.637 + IDCHECK(id1);
1.638 + IDCHECK(id0);
1.639 + f[2]=NULL;
1.640 + id[2]=CreateThread(t[2],2,f+2); // recreate t2
1.641 + User::After(50000); // let new t2 wait on mutex
1.642 + MCOUNT(M1,-1); // check 1 thread waiting
1.643 + MutexSignal();
1.644 + User::After(50000); // let t2 claim mutex
1.645 + MutexWait();
1.646 + MCOUNT(M1,0); // check no threads waiting
1.647 + IDCHECK(id2);
1.648 + IDCHECK(id0);
1.649 +
1.650 + t[2].SetPriority(EPriorityLess); // make t2 lower priority
1.651 + for (i=1; i<=5; ++i)
1.652 + Kick(t[i]); // wake up threads
1.653 + User::After(50000); // let threads wait on mutex
1.654 + MCOUNT(M1,-5); // check 5 threads waiting
1.655 + MutexSignal(); // t3 now pending
1.656 + MCOUNT(M1,-3); // check 4 threads waiting, mutex free
1.657 + t[3].Suspend(); // this should wake up t4
1.658 + MCOUNT(M1,-2); // check 3 threads waiting, mutex free
1.659 + User::After(50000); // let threads claim mutex
1.660 + MutexWait();
1.661 + MCOUNT(M1,0); // check no threads still waiting
1.662 + IDCHECK(id4); // check they ran in order t4,t5,t1,t2
1.663 + IDCHECK(id5);
1.664 + IDCHECK(id1);
1.665 + IDCHECK(id2);
1.666 + IDCHECK(id0);
1.667 + Kick(t[1]); // wake up t1
1.668 + User::After(50000); // let thread wait on mutex
1.669 + MCOUNT(M1,-1); // check 1 thread waiting
1.670 + t[3].Resume(); // resume pending t3
1.671 + MutexSignal();
1.672 + User::After(50000); // let t2 claim mutex
1.673 + MutexWait();
1.674 + MCOUNT(M1,0); // check no threads waiting
1.675 + IDCHECK(id3); // check order t3,t1
1.676 + IDCHECK(id1);
1.677 + IDCHECK(id0);
1.678 +
1.679 + for (i=1; i<=5; ++i)
1.680 + Kick(t[i]); // wake up threads
1.681 + User::After(50000); // let threads wait on mutex
1.682 + MCOUNT(M1,-5); // check 5 threads waiting
1.683 + t[4].Suspend(); // suspend t4
1.684 + MCOUNT(M1,-5); // check 5 threads waiting
1.685 + t[4].Suspend(); // suspend t4 again
1.686 + MCOUNT(M1,-5); // check 5 threads waiting
1.687 + MutexSignal();
1.688 + User::After(50000); // let threads claim mutex
1.689 + MutexWait();
1.690 + MCOUNT(M1,-1); // check 1 thread still waiting
1.691 + IDCHECK(id3); // check they ran in order t3,t5,t1,t2
1.692 + IDCHECK(id5);
1.693 + IDCHECK(id1);
1.694 + IDCHECK(id2);
1.695 + IDCHECK(id0);
1.696 + MutexSignal();
1.697 + t[4].Resume();
1.698 + User::After(50000); // let threads claim mutex
1.699 + MutexWait();
1.700 + IDCHECK(id0); // check thread didn't get mutex (still suspended)
1.701 + MutexSignal();
1.702 + t[4].Resume();
1.703 + User::After(50000); // let threads claim mutex
1.704 + MutexWait();
1.705 + IDCHECK(id4); // check order t4 then this
1.706 + IDCHECK(id0);
1.707 +
1.708 + for (i=1; i<=5; ++i)
1.709 + Kick(t[i]); // wake up threads
1.710 + User::After(50000); // let threads wait on mutex
1.711 + MCOUNT(M1,-5); // check 5 threads waiting
1.712 + MutexWait(); // wait on mutex again
1.713 + IDCHECK(id0);
1.714 + MutexSignal(); // signal once
1.715 + MCOUNT(M1,-5); // check 5 threads still waiting
1.716 + MutexSignal(); // signal again
1.717 + MCOUNT(M1,-3); // check one thread has been woken up and mutex is now free
1.718 + User::After(50000); // let threads claim mutex
1.719 + MutexWait();
1.720 + MCOUNT(M1,0); // check no threads still waiting
1.721 + IDCHECK(id3); // check they ran in order t3,t4,t5,t1,t2
1.722 + IDCHECK(id4);
1.723 + IDCHECK(id5);
1.724 + IDCHECK(id1);
1.725 + IDCHECK(id2);
1.726 + IDCHECK(id0);
1.727 +
1.728 + test.Next(_L("Create more threads"));
1.729 + for (i=6; i<=10; ++i)
1.730 + id[i]=CreateThread(t[i],i,f+i);
1.731 + User::After(50000); // let threads wait on mutex
1.732 + MCOUNT(M1,-5); // check 5 threads waiting
1.733 + MutexSignal();
1.734 + User::After(50000); // let threads claim mutex
1.735 + MCOUNT(M1,1); // check no threads still waiting and mutex free
1.736 + IDCHECK(id6); // check they ran in order t6,t7,t8,t9,t10
1.737 + IDCHECK(id7);
1.738 + IDCHECK(id8);
1.739 + IDCHECK(id9);
1.740 + IDCHECK(id10);
1.741 + t[8].SetPriority(EPriorityMore); // t1-t3=less, t4-t7=normal, t8-t10 more, t0 much more
1.742 + t[9].SetPriority(EPriorityMore);
1.743 + t[10].SetPriority(EPriorityMore);
1.744 + t[2].SetPriority(EPriorityLess);
1.745 + t[3].SetPriority(EPriorityLess);
1.746 +
1.747 + RackEmUp(t,f,id);
1.748 + SimpleCheck(0,NULL,NULL); // holding thread still blocked
1.749 + Kick(t[4]);
1.750 + SimpleCheck(6,id,10,8,9,5,1,2); // 3,6,7 suspended
1.751 + t[3].Resume();
1.752 + t[6].Resume();
1.753 + t[7].Resume();
1.754 + SimpleCheck(3,id,6,7,3); // 3,6,7 resumed
1.755 +
1.756 + RackEmUp(t,f,id);
1.757 + SimpleCheck(0,NULL,NULL); // holding thread still blocked
1.758 + Kick(t[4]);
1.759 + t[4].Suspend();
1.760 + SimpleCheck(0,NULL,NULL); // holding thread suspended
1.761 + t[4].Resume();
1.762 + SimpleCheck(6,id,10,8,9,5,1,2); // 3,6,7 suspended
1.763 + t[3].Resume();
1.764 + t[6].Resume();
1.765 + t[7].Resume();
1.766 + SimpleCheck(3,id,6,7,3); // 3,6,7 resumed
1.767 +
1.768 + RackEmUp(t,f,id);
1.769 + Kick(t[4]);
1.770 + t[4].SetPriority(EPriorityRealTime);
1.771 + MCOUNT(M1,-5); // should be 6 waiting, mutex free
1.772 + t[4].SetPriority(EPriorityNormal);
1.773 + t[8].SetPriority(EPriorityRealTime); // change pending thread priority
1.774 + MCOUNT(M1,-4); // should be 5 waiting, mutex free
1.775 + t[8].SetPriority(EPriorityMore);
1.776 + NUMCHECK(1);
1.777 + IDCHECK(id8);
1.778 + t[3].SetPriority(EPriorityRealTime); // change suspended thread priority
1.779 + SimpleCheck(5,id,9,10,5,1,2); // 3,6,7 suspended
1.780 + t[6].Resume();
1.781 + t[7].Resume();
1.782 + t[3].Resume(); // this should run right away
1.783 + NUMCHECK(1);
1.784 + IDCHECK(id3);
1.785 + SimpleCheck(2,id,6,7); // 6,7 resumed
1.786 + t[3].SetPriority(EPriorityLess);
1.787 +
1.788 + RackEmUp(t,f,id);
1.789 + Kick(t[4]);
1.790 + t[1].SetPriority(EPriorityRealTime); // change waiting thread priority
1.791 + // this should run right away
1.792 + NUMCHECK(1);
1.793 + IDCHECK(id1);
1.794 + t[1].SetPriority(EPriorityLess);
1.795 + // t8,t9,t10 should now be pending
1.796 + MCOUNT(M1,1-5);
1.797 + t[8].Suspend(); // this should wake up t5
1.798 + t[9].Suspend(); // this should wake up t2
1.799 + MCOUNT(M1,1-3);
1.800 + t[8].Suspend(); // this should have no further effect
1.801 + t[8].Resume(); // this should have no further effect
1.802 + MCOUNT(M1,1-3);
1.803 + SimpleCheck(3,id,10,5,2);
1.804 + MCOUNT(M1,1-3);
1.805 + t[3].Resume();
1.806 + t[6].Resume();
1.807 + t[7].Resume();
1.808 + t[8].Resume();
1.809 + t[9].Resume();
1.810 + SimpleCheck(5,id,8,9,6,7,3);
1.811 +
1.812 + RackEmUp(t,f,id);
1.813 + MCOUNT(M1,-7);
1.814 + t[8].Suspend(); // this shouldn't wake anything up
1.815 + t[9].Suspend(); // this shouldn't wake anything up
1.816 + MCOUNT(M1,-7);
1.817 + Kick(t[4]);
1.818 + t[4].SetPriority(EPriorityRealTime);
1.819 + MCOUNT(M1,1-6); // should be 6 waiting, mutex free, t10 pending
1.820 + t[4].SetPriority(EPriorityNormal);
1.821 + t[10].SetPriority(EPriorityLess); // this should wake up t5
1.822 + MCOUNT(M1,1-5); // should be 5 waiting, mutex free, t10, t5 pending
1.823 + SimpleCheck(4,id,5,10,1,2);
1.824 + t[3].SetPriority(EPriorityRealTime); // boost suspended+waiting thread
1.825 + MCOUNT(M1,1-3); // should be 3 waiting+suspended, mutex free, t8, t9 pending+suspended
1.826 + t[6].Resume();
1.827 + t[7].Resume();
1.828 + t[8].Resume();
1.829 + t[9].Resume();
1.830 + t[3].Resume(); // this should run immediately
1.831 + MCOUNT(M1,1); // t8,t9,t6,t7 pending, mutex free
1.832 + NUMCHECK(1);
1.833 + IDCHECK(id3); // t3 should have run
1.834 + t[3].SetPriority(EPriorityLess);
1.835 + t[9].SetPriority(EPriorityMuchLess); // lower pending thread priority
1.836 + SimpleCheck(4,id,8,6,7,9);
1.837 + t[9].SetPriority(EPriorityMore);
1.838 + t[10].SetPriority(EPriorityMore);
1.839 +
1.840 + RackEmUp(t,f,id);
1.841 + MCOUNT(M1,-7);
1.842 + t[8].Suspend(); // this shouldn't wake anything up
1.843 + t[9].Suspend(); // this shouldn't wake anything up
1.844 + MCOUNT(M1,-7);
1.845 + Kick(t[4]);
1.846 + MCOUNT(M1,-7);
1.847 + t[4].SetPriority(EPriorityRealTime);
1.848 + MCOUNT(M1,1-6); // should be 6 waiting, mutex free, t10 pending, t8,t9 pending+suspended
1.849 + t[4].SetPriority(EPriorityNormal);
1.850 + t[10].SetPriority(EPriorityMuchLess); // lower pending thread priority
1.851 + MCOUNT(M1,1-5); // should now be 5 waiting, mutex free, t10,t5 pending, t8,t9 pending+suspended
1.852 + t[6].Resume();
1.853 + t[7].Resume();
1.854 + t[3].Resume(); // this gets made READY straight away
1.855 + SimpleCheck(7,id,5,6,7,3,1,2,10);
1.856 + t[8].Resume();
1.857 + t[9].Resume();
1.858 + SimpleCheck(2,id,8,9);
1.859 + t[10].SetPriority(EPriorityMore);
1.860 +
1.861 + RackEmUp(t,f,id);
1.862 + MCOUNT(M1,-7);
1.863 + Kick(t[4]);
1.864 + t[9].Kill(0); // kill pending thread
1.865 + t[9].Close();
1.866 + test(!Exists(9));
1.867 + t[1].Kill(0); // kill waiting thread
1.868 + t[1].Close();
1.869 + test(!Exists(1));
1.870 + t[6].Kill(0); // kill suspended+waiting thread
1.871 + t[6].Close();
1.872 + t[7].Resume();
1.873 + t[3].Resume();
1.874 + test(!Exists(6));
1.875 + SimpleCheck(6,id,10,8,5,7,2,3); // 8 runs first and gets blocked behind 10
1.876 + Resurrect(9,EPriorityMore,t,f,id);
1.877 + Resurrect(1,EPriorityLess,t,f,id);
1.878 + Resurrect(6,EPriorityNormal,t,f,id);
1.879 +
1.880 + RackEmUp(t,f,id);
1.881 + MCOUNT(M1,-7);
1.882 + t[8].Suspend(); // this shouldn't wake anything up
1.883 + t[9].Suspend(); // this shouldn't wake anything up
1.884 + MCOUNT(M1,-7);
1.885 + Kick(t[4]);
1.886 + MCOUNT(M1,-7);
1.887 + t[4].SetPriority(EPriorityRealTime);
1.888 + MCOUNT(M1,1-6); // should be 6 waiting, mutex free, t10 pending, t8,t9 pending+suspended
1.889 + t[4].SetPriority(EPriorityNormal);
1.890 + t[10].Kill(0); // kill pending thread - this should wake up t5
1.891 + t[10].Close();
1.892 + test(!Exists(10));
1.893 + MCOUNT(M1,1-5); // should be 5 waiting, mutex free, t5 pending, t8,t9 pending+suspended
1.894 + t[5].SetPriority(EPriorityRealTime); // this should make t5 run
1.895 + MCOUNT(M1,1-4); // should be 4 waiting, mutex free, t1 pending, t8,t9 pending+suspended
1.896 + t[5].SetPriority(EPriorityNormal);
1.897 + NUMCHECK(1);
1.898 + IDCHECK(id5);
1.899 + t[8].SetPriority(EPriorityRealTime); // this shouldn't make anything happen
1.900 + MCOUNT(M1,1-4); // mutex free, t1 pending, t8,t9 pending+suspended, t3,t6,t7 wait+susp, t2 waiting
1.901 + NUMCHECK(0);
1.902 + t[8].Resume();
1.903 + MCOUNT(M1,1-3); // mutex free, t1,t2 pending, t9 pending+suspended, t3,t6,t7 wait+susp
1.904 + NUMCHECK(1);
1.905 + IDCHECK(id8);
1.906 + t[8].SetPriority(EPriorityMore);
1.907 + t[3].Resume();
1.908 + t[6].Resume();
1.909 + t[7].Resume();
1.910 + t[9].Resume();
1.911 + SimpleCheck(6,id,9,6,7,1,2,3);
1.912 + Resurrect(10,EPriorityMore,t,f,id);
1.913 +
1.914 + RackEmUp(t,f,id);
1.915 + MCOUNT(M1,-7);
1.916 + t[8].Suspend(); // this shouldn't wake anything up
1.917 + t[9].Suspend(); // this shouldn't wake anything up
1.918 + MCOUNT(M1,-7);
1.919 + Kick(t[4]);
1.920 + MCOUNT(M1,-7);
1.921 + t[4].SetPriority(EPriorityRealTime);
1.922 + MCOUNT(M1,1-6); // mutex free, t10 pending, t8,t9 pending+susp, t3,t6,t7 wait+susp, t1,t2,t5 wait
1.923 + t[4].SetPriority(EPriorityNormal);
1.924 + t[1].SetPriority(EPriorityRealTime); // this should be able to run and claim the mutex
1.925 + NUMCHECK(1);
1.926 + IDCHECK(id1);
1.927 + MCOUNT(M1,1-4); // mutex free, t10,t5 pending, t8,t9 pending+susp, t3,t6,t7 wait+susp, t2 wait
1.928 + t[1].SetPriority(EPriorityLess);
1.929 + t[3].Resume();
1.930 + t[6].Resume();
1.931 + t[7].Resume();
1.932 + t[9].Resume();
1.933 + t[8].Resume();
1.934 + SimpleCheck(8,id,10,9,8,5,6,7,3,2);
1.935 +
1.936 + RackEmUp(t,f,id);
1.937 + MCOUNT(M1,-7);
1.938 + Kick(t[4]);
1.939 + M1.Close(); // close the mutex - non-suspended threads should all panic with KERN-EXEC 0
1.940 + TBool jit = User::JustInTime();
1.941 + User::SetJustInTime(EFalse);
1.942 + User::After(1000000);
1.943 + User::SetJustInTime(jit);
1.944 + for (i=1; i<=10; ++i)
1.945 + {
1.946 + if (i==3 || i==6 || i==7)
1.947 + {
1.948 + test(t[i].ExitType()==EExitPending);
1.949 + }
1.950 + else
1.951 + {
1.952 + test(t[i].ExitType()==EExitPanic);
1.953 + test(t[i].ExitReason()==EBadHandle);
1.954 + test(t[i].ExitCategory()==_L("KERN-EXEC"));
1.955 + t[i].Close();
1.956 + test(!Exists(i));
1.957 + }
1.958 + }
1.959 + t[3].Resume();
1.960 + t[6].Resume();
1.961 + t[7].Resume();
1.962 + User::SetJustInTime(EFalse);
1.963 + User::After(1000000);
1.964 + User::SetJustInTime(jit);
1.965 + for (i=1; i<=10; ++i)
1.966 + {
1.967 + if (i==3 || i==6 || i==7)
1.968 + {
1.969 + test(t[i].ExitType()==EExitPanic);
1.970 + test(t[i].ExitReason()==EBadHandle);
1.971 + test(t[i].ExitCategory()==_L("KERN-EXEC"));
1.972 + t[i].Close();
1.973 + test(!Exists(i));
1.974 + }
1.975 + }
1.976 +
1.977 + test.End();
1.978 + }
1.979 +
1.980 +/*****************************************************************************
1.981 + * Mutex benchmarks
1.982 + *****************************************************************************/
1.983 +TInt MutexSpeed(TAny* aPtr)
1.984 + {
1.985 + TInt& count=*(TInt*)aPtr;
1.986 + RThread().SetPriority(EPriorityMore);
1.987 + FOREVER
1.988 + {
1.989 + M1.Wait();
1.990 + M1.Signal();
1.991 + ++count;
1.992 + }
1.993 + }
1.994 +
1.995 +TInt MutexSpeed2(TAny* aPtr)
1.996 + {
1.997 + TInt& count=*(TInt*)aPtr;
1.998 + RThread().SetPriority(EPriorityMore);
1.999 + FOREVER
1.1000 + {
1.1001 + M1.Wait();
1.1002 + M1.Wait();
1.1003 + M1.Signal();
1.1004 + M1.Signal();
1.1005 + ++count;
1.1006 + }
1.1007 + }
1.1008 +
1.1009 +void TestMutexSpeed()
1.1010 + {
1.1011 + test.Start(_L("Test mutex speed"));
1.1012 + TInt count=0;
1.1013 + TInt r=M1.CreateLocal();
1.1014 + test(r==KErrNone);
1.1015 +
1.1016 + RThread t;
1.1017 + r=t.Create(_L("Speed"),MutexSpeed,0x1000,NULL,&count);
1.1018 + test(r==KErrNone);
1.1019 + t.SetPriority(EPriorityRealTime);
1.1020 + t.Resume();
1.1021 + User::AfterHighRes(1000000);
1.1022 + t.Kill(0);
1.1023 + t.Close();
1.1024 + test(!Exists(_L("Speed")));
1.1025 + test.Printf(_L("%d wait/signal in 1 second\n"),count);
1.1026 +
1.1027 + TInt count2=0;
1.1028 + r=t.Create(_L("Speed2"),MutexSpeed2,0x1000,NULL,&count2);
1.1029 + test(r==KErrNone);
1.1030 + t.SetPriority(EPriorityRealTime);
1.1031 + t.Resume();
1.1032 + User::AfterHighRes(1000000);
1.1033 + t.Kill(0);
1.1034 + t.Close();
1.1035 + test(!Exists(_L("Speed2")));
1.1036 + test.Printf(_L("%d double wait/signal in 1 second\n"),count2);
1.1037 +
1.1038 + M1.Close();
1.1039 + test.End();
1.1040 + }
1.1041 +
1.1042 +/*****************************************************************************
1.1043 + * Utilities for semaphore test
1.1044 + *****************************************************************************/
1.1045 +void SemWait()
1.1046 + {
1.1047 + S.Wait();
1.1048 + ++Count;
1.1049 + ThreadId[PutIx++]=(TUint)RThread().Id();
1.1050 + }
1.1051 +
1.1052 +void SemSignal()
1.1053 + {
1.1054 + S.Signal();
1.1055 + }
1.1056 +
1.1057 +TInt SemThreadFunction(TAny* aPtr)
1.1058 + {
1.1059 + PFV& f=*(PFV*)aPtr;
1.1060 + FOREVER
1.1061 + {
1.1062 + SemWait();
1.1063 + if (f)
1.1064 + f();
1.1065 + SemSignal();
1.1066 + User::WaitForAnyRequest();
1.1067 + }
1.1068 + }
1.1069 +
1.1070 +void Wait()
1.1071 + {
1.1072 + User::WaitForAnyRequest();
1.1073 + }
1.1074 +
1.1075 +TUint CreateSemThread(RThread& t, TInt n, TAny* aPtr)
1.1076 + {
1.1077 + TBuf<4> b;
1.1078 + b.Num(n);
1.1079 + TInt r=t.Create(b,SemThreadFunction,0x1000,NULL,aPtr);
1.1080 + test(r==KErrNone);
1.1081 + t.Resume();
1.1082 + TUint id=t.Id();
1.1083 + return id;
1.1084 + }
1.1085 +
1.1086 +/*
1.1087 +Possible thread relationships with semaphore:
1.1088 + Waiting
1.1089 + Waiting + suspended
1.1090 +
1.1091 +Need to verify correct behaviour when the following actions occur for each of these states:
1.1092 + Suspend thread
1.1093 + Resume thread
1.1094 + Change thread priority
1.1095 + Thread exits
1.1096 + Thread is killed
1.1097 + Semaphore deleted
1.1098 +*/
1.1099 +
1.1100 +void RackEmUp2(RThread* t, PFV* f, TUint* id)
1.1101 + {
1.1102 + // set up
1.1103 + // t1, t2, t4, t5, t6, t8, t9 waiting
1.1104 + // t3, t7, t10 waiting+suspended
1.1105 + (void)f;
1.1106 + MCOUNT(S,2); // check semaphore level = 2
1.1107 + SemWait();
1.1108 + SemWait();
1.1109 + MCOUNT(S,0); // check semaphore level = 0
1.1110 + NUMCHECK(2);
1.1111 + IDCHECK(id0);
1.1112 + IDCHECK(id0);
1.1113 + TInt i;
1.1114 + for (i=1; i<=10; ++i)
1.1115 + Kick(t[i]); // wake up threads
1.1116 + User::After(50000); // let threads wait
1.1117 + MCOUNT(S,-10); // check 10 threads waiting
1.1118 + t[7].Resume(); // test resume when not suspended
1.1119 + MCOUNT(S,-10); // check 7 threads waiting
1.1120 + t[3].Suspend();
1.1121 + t[7].Suspend();
1.1122 + t[10].Suspend(); // now have required state
1.1123 + t[3].Suspend(); // suspend and resume t3 again for good measure
1.1124 + t[3].Resume();
1.1125 + MCOUNT(S,-7); // check 7 threads waiting
1.1126 + }
1.1127 +
1.1128 +void Resurrect2(TInt n, TThreadPriority aPriority, RThread* t, PFV* f, TUint* id)
1.1129 + {
1.1130 + f[n]=NULL;
1.1131 + id[n]=CreateSemThread(t[n],n,f+n);
1.1132 + t[n].SetPriority(EPriorityRealTime);
1.1133 + t[n].SetPriority(aPriority);
1.1134 + NUMCHECK(1);
1.1135 + IDCHECK(id[n]);
1.1136 + }
1.1137 +
1.1138 +/*****************************************************************************
1.1139 + * Semaphore exhaustive state transition test
1.1140 + *****************************************************************************/
1.1141 +void TestSemaphore()
1.1142 + {
1.1143 + test.Start(_L("Test semaphore state transitions"));
1.1144 + RThread t[11];
1.1145 + TUint id[11];
1.1146 + PFV f[11]={NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
1.1147 + id[0]=(TUint)RThread().Id();
1.1148 + PutIx=0;
1.1149 + GetIx=0;
1.1150 + Count=0;
1.1151 + test.Next(_L("Create semaphore"));
1.1152 + TInt r=S.CreateLocal(2);
1.1153 + test(r==KErrNone);
1.1154 + MCOUNT(S,2);
1.1155 + SemWait();
1.1156 + MCOUNT(S,1);
1.1157 + SemSignal();
1.1158 + MCOUNT(S,2);
1.1159 + SemWait();
1.1160 + SemWait();
1.1161 + MCOUNT(S,0);
1.1162 + S.Signal(2);
1.1163 + MCOUNT(S,2);
1.1164 + NUMCHECK(3);
1.1165 + IDCHECK(id0);
1.1166 + IDCHECK(id0);
1.1167 + IDCHECK(id0);
1.1168 + test.Next(_L("Create threads"));
1.1169 + TInt i;
1.1170 + for (i=1; i<=10; ++i)
1.1171 + {
1.1172 + id[i]=CreateSemThread(t[i],i,f+i);
1.1173 + f[i]=&Wait;
1.1174 + }
1.1175 + t[8].SetPriority(EPriorityMore); // t1-t3=less, t4-t7=normal, t8-t10 more, t0 much more
1.1176 + t[9].SetPriority(EPriorityMore);
1.1177 + t[10].SetPriority(EPriorityMore);
1.1178 + t[1].SetPriority(EPriorityLess);
1.1179 + t[2].SetPriority(EPriorityLess);
1.1180 + t[3].SetPriority(EPriorityLess);
1.1181 + User::After(50000);
1.1182 + MCOUNT(S,-8); // check 8 waiting
1.1183 + NUMCHECK(2);
1.1184 + IDCHECK(id8);
1.1185 + IDCHECK(id9); // check t8,t9 got through
1.1186 + t[8].SetPriority(EPriorityRealTime);
1.1187 + Kick(t[8]); // let t8 run and signal
1.1188 + t[8].SetPriority(EPriorityMore);
1.1189 + MCOUNT(S,-7); // check 7 waiting
1.1190 + User::After(50000); // let next thread obtain semaphore
1.1191 + MCOUNT(S,-7); // check 7 waiting
1.1192 + NUMCHECK(1);
1.1193 + IDCHECK(id10); // check t10 got it
1.1194 + Kick(t[10]); // let t10 run and signal
1.1195 + User::After(50000); // let next thread obtain semaphore
1.1196 + MCOUNT(S,-6); // check 6 waiting
1.1197 + NUMCHECK(1);
1.1198 + IDCHECK(id4); // check t4 got it
1.1199 + t[1].SetPriority(EPriorityRealTime); // boost t1
1.1200 + MCOUNT(S,-6); // check 6 still waiting
1.1201 + User::After(50000); // let next thread obtain semaphore
1.1202 + MCOUNT(S,-6); // check 6 still waiting
1.1203 + NUMCHECK(0);
1.1204 + Kick(t[9]); // make t9 ready to run and signal
1.1205 + MCOUNT(S,-6); // check 6 still waiting
1.1206 + User::After(50000); // let next thread obtain semaphore
1.1207 + MCOUNT(S,-5); // check 5 waiting
1.1208 + NUMCHECK(1);
1.1209 + IDCHECK(id1); // check t1 got it
1.1210 + t[1].SetPriority(EPriorityLess);
1.1211 + Kick(t[1]); // kick all remaining threads
1.1212 + Kick(t[2]);
1.1213 + Kick(t[3]);
1.1214 + Kick(t[4]);
1.1215 + Kick(t[5]);
1.1216 + Kick(t[6]);
1.1217 + Kick(t[7]);
1.1218 + User::After(50000); // let them run and obtain/signal the semaphore
1.1219 + MCOUNT(S,2); // check semaphore now back to initial level
1.1220 + SimpleCheck(5,id,5,6,7,2,3);
1.1221 +
1.1222 + for (i=1; i<=10; ++i)
1.1223 + f[i]=NULL;
1.1224 + RackEmUp2(t,f,id); // set up threads waiting on semaphore again
1.1225 + S.Signal();
1.1226 + SimpleCheck(7,id,8,9,4,5,6,1,2); // let them go
1.1227 + MCOUNT(S,1);
1.1228 + S.Wait();
1.1229 + t[3].SetPriority(EPriorityRealTime); // change suspended thread priority
1.1230 + t[7].Resume();
1.1231 + SimpleCheck(0,id); // t7 should wait for signal
1.1232 + S.Signal();
1.1233 + SimpleCheck(1,id,7);
1.1234 + MCOUNT(S,1);
1.1235 + t[3].Resume();
1.1236 + t[10].Resume();
1.1237 + NUMCHECK(1);
1.1238 + IDCHECK(id3); // t3 should have grabbed semaphore as soon as we resumed it
1.1239 + SimpleCheck(1,id,10);
1.1240 + t[3].SetPriority(EPriorityLess);
1.1241 + S.Signal(); // put level back to 2
1.1242 +
1.1243 + RackEmUp2(t,f,id); // set up threads waiting on semaphore again
1.1244 + S.Signal();
1.1245 + SimpleCheck(7,id,8,9,4,5,6,1,2); // let them go
1.1246 + MCOUNT(S,1);
1.1247 + S.Wait();
1.1248 + t[3].SetPriority(EPriorityRealTime); // change suspended thread priority
1.1249 + t[7].Resume();
1.1250 + SimpleCheck(0,id); // t7 should wait for signal
1.1251 + S.Signal();
1.1252 + SimpleCheck(1,id,7);
1.1253 + MCOUNT(S,1);
1.1254 + t[10].Resume();
1.1255 + t[3].Resume(); // t3 not woken up here since t10 has already been given the semaphore
1.1256 + NUMCHECK(0);
1.1257 + SimpleCheck(2,id,10,3);
1.1258 + t[3].SetPriority(EPriorityLess);
1.1259 + S.Signal(); // put level back to 2
1.1260 +
1.1261 + RackEmUp2(t,f,id); // set up threads waiting on semaphore again
1.1262 + S.Signal();
1.1263 + SimpleCheck(7,id,8,9,4,5,6,1,2); // let them go
1.1264 + MCOUNT(S,1);
1.1265 + S.Wait();
1.1266 + t[3].SetPriority(EPriorityRealTime); // change suspended thread priority
1.1267 + t[7].Resume();
1.1268 + SimpleCheck(0,id); // t7 should wait for signal
1.1269 + S.Signal();
1.1270 + S.Signal(); // put level back to 2
1.1271 + SimpleCheck(1,id,7);
1.1272 + MCOUNT(S,2);
1.1273 + t[10].Resume();
1.1274 + t[3].Resume(); // t3 and t10 both woken up here, t3 should run and signal
1.1275 + MCOUNT(S,1);
1.1276 + NUMCHECK(1);
1.1277 + IDCHECK(id3);
1.1278 + SimpleCheck(1,id,10);
1.1279 + t[3].SetPriority(EPriorityLess);
1.1280 +
1.1281 + RackEmUp2(t,f,id); // set up threads waiting on semaphore again
1.1282 + t[9].Kill(0); // kill waiting thread
1.1283 + t[9].Close();
1.1284 + test(!Exists(9));
1.1285 + t[10].Kill(0); // kill suspended thread
1.1286 + t[10].Close();
1.1287 + test(!Exists(10));
1.1288 + MCOUNT(S,-6);
1.1289 + f[5]=&Exit; // get t5 to exit after acquiring semaphore
1.1290 + S.Signal();
1.1291 + SimpleCheck(3,id,8,4,5); // let them go
1.1292 + MCOUNT(S,-3); // check one signal has been lost due to t5 exiting
1.1293 + t[5].Close();
1.1294 + test(!Exists(5));
1.1295 + t[3].Resume();
1.1296 + t[7].Resume();
1.1297 + MCOUNT(S,-5);
1.1298 + S.Signal();
1.1299 + SimpleCheck(5,id,6,7,1,2,3); // let them go
1.1300 + MCOUNT(S,1);
1.1301 + Resurrect2(9,EPriorityMore,t,f,id);
1.1302 + Resurrect2(10,EPriorityMore,t,f,id);
1.1303 + Resurrect2(5,EPriorityNormal,t,f,id);
1.1304 + S.Signal();
1.1305 +
1.1306 + RackEmUp2(t,f,id); // set up threads waiting on semaphore again
1.1307 + f[5]=&Exit; // get t5 to exit after acquiring semaphore
1.1308 + S.Close(); // close semaphore - threads should panic except for 5
1.1309 +
1.1310 + TBool jit = User::JustInTime();
1.1311 + User::SetJustInTime(EFalse);
1.1312 + User::After(1000000);
1.1313 + User::SetJustInTime(jit);
1.1314 + for (i=1; i<=10; ++i)
1.1315 + {
1.1316 + if (i==3 || i==7 || i==10)
1.1317 + {
1.1318 + test(t[i].ExitType()==EExitPending);
1.1319 + }
1.1320 + else if (i!=5)
1.1321 + {
1.1322 + test(t[i].ExitType()==EExitPanic);
1.1323 + test(t[i].ExitReason()==EBadHandle);
1.1324 + test(t[i].ExitCategory()==_L("KERN-EXEC"));
1.1325 + t[i].Close();
1.1326 + test(!Exists(i));
1.1327 + }
1.1328 + else
1.1329 + {
1.1330 + test(t[i].ExitType()==EExitKill);
1.1331 + test(t[i].ExitReason()==0);
1.1332 + t[i].Close();
1.1333 + test(!Exists(i));
1.1334 + }
1.1335 + }
1.1336 + t[3].Resume();
1.1337 + t[7].Resume();
1.1338 + t[10].Resume();
1.1339 + User::SetJustInTime(EFalse);
1.1340 + User::After(1000000);
1.1341 + User::SetJustInTime(jit);
1.1342 + for (i=1; i<=10; ++i)
1.1343 + {
1.1344 + if (i==3 || i==7 || i==10)
1.1345 + {
1.1346 + test(t[i].ExitType()==EExitPanic);
1.1347 + test(t[i].ExitReason()==EBadHandle);
1.1348 + test(t[i].ExitCategory()==_L("KERN-EXEC"));
1.1349 + t[i].Close();
1.1350 + test(!Exists(i));
1.1351 + }
1.1352 + }
1.1353 +
1.1354 + test.End();
1.1355 + }
1.1356 +
1.1357 +/*****************************************************************************
1.1358 + * Semaphore benchmarks
1.1359 + *****************************************************************************/
1.1360 +TInt SemSpeed(TAny* aPtr)
1.1361 + {
1.1362 + TInt& count=*(TInt*)aPtr;
1.1363 + RThread().SetPriority(EPriorityMore);
1.1364 + FOREVER
1.1365 + {
1.1366 + S.Wait();
1.1367 + S.Signal();
1.1368 + ++count;
1.1369 + }
1.1370 + }
1.1371 +
1.1372 +void TestSemSpeed()
1.1373 + {
1.1374 + test.Start(_L("Test semaphore speed"));
1.1375 + TInt count=0;
1.1376 + TInt r=S.CreateLocal(1);
1.1377 + test(r==KErrNone);
1.1378 +
1.1379 + RThread t;
1.1380 + r=t.Create(_L("SemSpeed"),SemSpeed,0x1000,NULL,&count);
1.1381 + test(r==KErrNone);
1.1382 + t.SetPriority(EPriorityRealTime);
1.1383 + t.Resume();
1.1384 + User::AfterHighRes(1000000);
1.1385 + t.Kill(0);
1.1386 + t.Close();
1.1387 + test(!Exists(_L("SemSpeed")));
1.1388 + test.Printf(_L("%d wait/signal in 1 second\n"),count);
1.1389 +
1.1390 + S.Close();
1.1391 + test.End();
1.1392 + }
1.1393 +
1.1394 +
1.1395 +GLDEF_C TInt E32Main()
1.1396 + {
1.1397 + test.Title();
1.1398 +
1.1399 + test.Start(_L("Test mutexes and semaphores"));
1.1400 + RThread().SetPriority(EPriorityMuchMore);
1.1401 + TInt r=Main.Duplicate(RThread());
1.1402 + test(r==KErrNone);
1.1403 +
1.1404 + Test0();
1.1405 + Test1();
1.1406 + TestMutex1();
1.1407 + TestMutex2();
1.1408 + TestSemaphore();
1.1409 +
1.1410 + TestMutexSpeed();
1.1411 + TestSemSpeed();
1.1412 +
1.1413 + Main.Close();
1.1414 + test.End();
1.1415 + return KErrNone;
1.1416 + }
1.1417 +