1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kerneltest/e32test/emul/t_emul.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,376 @@
1.4 +// Copyright (c) 2002-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\emul\t_emul.cpp
1.18 +// Overview:
1.19 +// Test the mechanism to escape threads from the emulator in order
1.20 +// to block on Windows objects
1.21 +// Test launching processes doesn't leak windows TLS indices
1.22 +// API Information:
1.23 +// Emulator
1.24 +// Details:
1.25 +// - Test the mechanism to escape threads from the emulator in order
1.26 +// to block on Windows objects:
1.27 +// - test escape and re-enter mechanism.
1.28 +// - block on Windows in EPOC thread and escaped EPOC thread.
1.29 +// Platforms/Drives/Compatibility:
1.30 +// All.
1.31 +// Assumptions/Requirement/Pre-requisites:
1.32 +// Failures and causes:
1.33 +// Base Port information:
1.34 +//
1.35 +//
1.36 +
1.37 +#define __E32TEST_EXTENSION__
1.38 +#include <f32file.h>
1.39 +#include <e32atomics.h>
1.40 +#include <e32std.h>
1.41 +#include <e32std_private.h>
1.42 +#include <e32ldr.h>
1.43 +#include <e32ldr_private.h>
1.44 +#include "e32test.h"
1.45 +#include "emulator.h"
1.46 +#include "t_emul.h"
1.47 +
1.48 +#define WIN32_LEAN_AND_MEAN
1.49 +#pragma warning( disable : 4201 ) // nonstandard extension used : nameless struct/union
1.50 +#include <windows.h>
1.51 +#pragma warning( default : 4201 ) // nonstandard extension used : nameless struct/union
1.52 +
1.53 +LOCAL_D RTest test(_L("t_emul"));
1.54 +
1.55 +static TInt ELock;
1.56 +static HANDLE ESemaphore;
1.57 +static TInt EResult;
1.58 +
1.59 +TInt EscapeTimeoutThread(TAny*)
1.60 + {
1.61 + User::After(1000000);
1.62 + if (__e32_atomic_add_ord32(&ELock, 1) == 0)
1.63 + {
1.64 + EResult=KErrTimedOut;
1.65 + ReleaseSemaphore(ESemaphore,1,NULL);
1.66 + }
1.67 + return KErrNone;
1.68 + }
1.69 +
1.70 +TInt EscapeSignalThread(TAny*)
1.71 + {
1.72 + if (__e32_atomic_add_ord32(&ELock, 1) == 0)
1.73 + {
1.74 + EResult=KErrNone;
1.75 + ReleaseSemaphore(ESemaphore,1,NULL);
1.76 + }
1.77 + return KErrNone;
1.78 + }
1.79 +
1.80 +TInt DoTestEscape(TBool aDoEscape)
1.81 +//
1.82 +// Test the mechanism to escape threads from the emulator in order to block on Windows objects
1.83 +//
1.84 + {
1.85 + ELock = 0;
1.86 + EResult = KRequestPending;
1.87 + ESemaphore = CreateSemaphoreA(NULL,0,1,NULL);
1.88 + test (ESemaphore != NULL);
1.89 + RThread t1,t2;
1.90 + TRequestStatus s1,s2;
1.91 + TInt r = t1.Create(KNullDesC,&EscapeSignalThread,0x1000,NULL,NULL);
1.92 + test (r == KErrNone);
1.93 + t1.SetPriority(EPriorityLess);
1.94 + t1.Logon(s1);
1.95 + t1.Resume();
1.96 + r = t2.Create(KNullDesC,&EscapeTimeoutThread,0x1000,NULL,NULL);
1.97 + test (r == KErrNone);
1.98 + t2.SetPriority(EPriorityMore);
1.99 + t2.Logon(s2);
1.100 + t2.Resume();
1.101 +//
1.102 + if (aDoEscape)
1.103 + Emulator::Escape();
1.104 + r = WaitForSingleObject(ESemaphore,INFINITE);
1.105 + if (aDoEscape)
1.106 + Emulator::Reenter();
1.107 + test (r==WAIT_OBJECT_0);
1.108 +//
1.109 + r = EResult;
1.110 + t1.Kill(0);
1.111 + t2.Kill(0);
1.112 + t1.Close();
1.113 + t2.Close();
1.114 + User::WaitForRequest(s1);
1.115 + User::WaitForRequest(s2);
1.116 +//
1.117 + CloseHandle(ESemaphore);
1.118 + return r;
1.119 + }
1.120 +
1.121 +void TestEscape()
1.122 +//
1.123 +// Test the mechanism to escape threads from the emulator in order to block on Windows objects
1.124 +//
1.125 + {
1.126 + test.Start(_L("Test escape and reenter mechanism"));
1.127 + for (TInt i = 0;i<10000;++i)
1.128 + {
1.129 + Emulator::Escape();
1.130 + if (i%100 == 0)
1.131 + Sleep(10);
1.132 + Emulator::Reenter();
1.133 + }
1.134 + test.Next(_L("Block on Windows in EPOC thread"));
1.135 + TInt r = DoTestEscape(EFalse);
1.136 + test (r == KErrTimedOut);
1.137 + test.Next(_L("Block on Windows in escaped EPOC thread"));
1.138 + r = DoTestEscape(ETrue);
1.139 + test (r == KErrNone);
1.140 + test.End();
1.141 + }
1.142 +
1.143 +TInt CountRemainingTlsIndicies()
1.144 + {
1.145 + const TInt KMax = 2000;
1.146 +
1.147 + TBool allocated[KMax];
1.148 + memclr(allocated, sizeof(TBool) * KMax);
1.149 + TInt i;
1.150 + for (i = 0 ; i < KMax ; ++i)
1.151 + {
1.152 + TInt index = TlsAlloc();
1.153 + if (index == TLS_OUT_OF_INDEXES)
1.154 + break;
1.155 + test(index >= 0 && index < KMax);
1.156 + allocated[index] = ETrue;
1.157 + }
1.158 + for (TInt j = 0 ; j < KMax ; ++j)
1.159 + {
1.160 + if (allocated[j])
1.161 + test(TlsFree(j));
1.162 + }
1.163 + return i;
1.164 + }
1.165 +
1.166 +void RunSlave(TSlaveAction aAction)
1.167 + {
1.168 + RProcess p;
1.169 + TBuf<8> arg;
1.170 + arg.Format(_L("%d"), aAction);
1.171 + test_KErrNone(p.Create(KTEmulSlaveName, arg));
1.172 + p.Resume();
1.173 + TRequestStatus status;
1.174 + p.Logon(status);
1.175 + User::WaitForRequest(status);
1.176 + test_KErrNone(status.Int());
1.177 + test_Equal(EExitKill, p.ExitType());
1.178 + p.Close();
1.179 + }
1.180 +
1.181 +void TestRuntimeCleanup()
1.182 + {
1.183 + test.Start(_L("Test Codewarrior runtime library is correctly cleaned up"));
1.184 + TInt initIndicies = CountRemainingTlsIndicies();
1.185 +
1.186 + test.Next(_L("Test creating a process doesn't leak windows TLS indicies"));
1.187 + RunSlave(ESlaveDoNothing);
1.188 + test_Equal(initIndicies, CountRemainingTlsIndicies());
1.189 +
1.190 + test.Next(_L("Test leaving in an exe doesn't leak windows TLS indicies"));
1.191 + RunSlave(ESlaveTrapExceptionInExe);
1.192 + test_Equal(initIndicies, CountRemainingTlsIndicies());
1.193 +
1.194 + test.Next(_L("Test leaving in a linked DLL doesn't leak windows TLS indicies"));
1.195 + RunSlave(ESlaveTrapExceptionInLinkedDll);
1.196 + test_Equal(initIndicies, CountRemainingTlsIndicies());
1.197 +
1.198 + test.Next(_L("Test leaving in a loaded DLL doesn't leak windows TLS indicies"));
1.199 + RunSlave(ESlaveTrapExceptionInLoadedDll);
1.200 + test_Equal(initIndicies, CountRemainingTlsIndicies());
1.201 +
1.202 + test.Next(_L("Test cleanup doesn't happen while DLL still loaded"));
1.203 + RLibrary l;
1.204 + test_KErrNone(l.Load(KTEmulDll2Name));
1.205 + RunSlave(ESlaveTrapExceptionInLoadedDll);
1.206 + TInt midCount = CountRemainingTlsIndicies();
1.207 + test(initIndicies > midCount);
1.208 +
1.209 + test.Next(_L("Test previous detach doesn't cause runtime to be re-initalised"));
1.210 + TTrapExceptionInDllFunc func =
1.211 + (TTrapExceptionInDllFunc)l.Lookup(KTrapExceptionInDllOrdinal);
1.212 + test_NotNull(func);
1.213 + func();
1.214 + test_Equal(midCount, CountRemainingTlsIndicies());
1.215 + l.Close();
1.216 + test_Equal(initIndicies, CountRemainingTlsIndicies());
1.217 +
1.218 + test.End();
1.219 + }
1.220 +
1.221 +
1.222 +void DoSomething2L()
1.223 + {
1.224 + test.Printf(_L("@\n"));
1.225 + }
1.226 +
1.227 +
1.228 +void DoSomething1L()
1.229 + {
1.230 + TInt i = -1, j = 1;
1.231 + for ( ; ; )
1.232 + {
1.233 + i++;
1.234 + //DoSomething2L() must only be called once , else we know that trap mechanism didn't work
1.235 + test( i<2);
1.236 + if (i == j)
1.237 + {
1.238 + User::Leave(KErrNotFound);
1.239 + }
1.240 +
1.241 + TRAP_IGNORE(DoSomething2L());
1.242 + TRAPD(errr, DoSomething2L());
1.243 + TInt r;
1.244 + TRAP(r, DoSomething2L());
1.245 +
1.246 + }
1.247 + }
1.248 +
1.249 +
1.250 +void LeaveIfArgIsTwo(TInt aCall);
1.251 +
1.252 +class CFred : public CBase
1.253 +{
1.254 + public:
1.255 +static CFred* NewLC();
1.256 + CFred();
1.257 + ~CFred();
1.258 +};
1.259 +
1.260 +void DoSomething3L()
1.261 + {
1.262 + // Push something on the cleanup stack so we can see whyen it gets cleaned up.
1.263 + CFred *fred = CFred::NewLC();
1.264 +
1.265 + TInt beforeFunc=0;
1.266 + TInt betweenFuncAndTRAPD=0;
1.267 + TInt afterTRAPD=0;
1.268 + for(TInt loop=1; loop<=2; ++loop)
1.269 + {
1.270 + ++beforeFunc;
1.271 + test.Printf(_L("Before LeaveIfArgIsTwo()\n"));
1.272 +
1.273 + // The first time around the loop, this function call works.
1.274 + // The second time, it leaves KErrGeneral
1.275 + // Then when TRAP mechanism isn't working properly the emulator (correctly)
1.276 + // would delete fred, and (incorrectly) jump to the line
1.277 + // just after the TRAPD call a few lines further down the file!
1.278 + LeaveIfArgIsTwo(loop);
1.279 +
1.280 + ++betweenFuncAndTRAPD;
1.281 + test.Printf(_L("Between LeaveIfArgIsTwo() and TRAPD\n"));
1.282 +
1.283 + TRAPD(err, test.Printf(_L("Inside TRAPD\n") ) );
1.284 +
1.285 +
1.286 + // It should only be possible to reach this section of code by executing all the lines
1.287 + // between LeaveIfArgIsTwo and here.
1.288 + ++afterTRAPD;
1.289 +
1.290 + }
1.291 +
1.292 + // Should NEVER get here because LeaveIfArgIsTwo did a leave the second time around the loop
1.293 + test.Printf(_L("After loop (should NEVER get here) -\n\
1.294 + beforeFunc %d\n\
1.295 + betweenFuncAndTRAPD %d\n\
1.296 + afterTRAPD %d\n"),
1.297 + beforeFunc, betweenFuncAndTRAPD, afterTRAPD);
1.298 +
1.299 + test.Printf(_L("It should be impossible for afterTRAPD to be larger than betweenFuncAndTRAPD\n"));
1.300 + test(afterTRAPD <= betweenFuncAndTRAPD);
1.301 +
1.302 + // Cleanup our cleanup stack.
1.303 + CleanupStack::PopAndDestroy(&fred);
1.304 + }
1.305 +
1.306 +void LeaveIfArgIsTwo(TInt aCall)
1.307 + {
1.308 +
1.309 + test.Printf(_L("aCall %d\n"), aCall);
1.310 + if(aCall == 2)
1.311 + {
1.312 + User::Leave(KErrGeneral);
1.313 + }
1.314 + }
1.315 +
1.316 +CFred *CFred::NewLC()
1.317 + {
1.318 + CFred *self = new(ELeave) CFred;
1.319 + CleanupStack::PushL(self);
1.320 + return self;
1.321 + }
1.322 +
1.323 +CFred::CFred()
1.324 + {
1.325 + test.Printf(_L("CFred %x\n"), this);
1.326 + }
1.327 +
1.328 +CFred::~CFred()
1.329 + {
1.330 + test.Printf(_L("~CFred %x\n"), this);
1.331 + }
1.332 +
1.333 +
1.334 +
1.335 +GLDEF_C TInt E32Main()
1.336 +//
1.337 +//
1.338 +//
1.339 + {
1.340 + test.Title();
1.341 + test.Start(_L("Starting tests ..."));
1.342 +
1.343 + // Turn off evil lazy dll unloading
1.344 + RLoader l;
1.345 + test(l.Connect()==KErrNone);
1.346 + test(l.CancelLazyDllUnload()==KErrNone);
1.347 + l.Close();
1.348 +
1.349 + TestEscape();
1.350 +#ifdef __CW32__
1.351 + TestRuntimeCleanup();
1.352 +#endif
1.353 +
1.354 + // The following tests were added to test that the TRAP mechanism works correctly in case of
1.355 + // nested TRAP's. A compiler bug (winscw) caused the following tests to fail, since the wrong
1.356 + // trap handler would be invoked, when User::Leave() was called.
1.357 +
1.358 + test.Next(_L("Check User::Leave is handled by the correct TRAP handler when nested TRAPs are present - Simple scenario\n"));
1.359 +
1.360 + TRAPD(err, DoSomething1L());
1.361 + test(err == KErrNotFound);
1.362 +
1.363 + test.Next(_L("Check User::Leave is handled by the correct TRAP handler when nested TRAPs are present - Cleanup stack scenario\n"));
1.364 + __UHEAP_MARK;
1.365 + CTrapCleanup* tc = CTrapCleanup::New();
1.366 + if (tc == 0) return KErrNoMemory;
1.367 +
1.368 + TRAPD(err2, DoSomething3L());
1.369 + test(err2==KErrGeneral);
1.370 +
1.371 + delete tc;
1.372 + __UHEAP_MARKEND;
1.373 +
1.374 +
1.375 + test.End();
1.376 + test.Close();
1.377 + return KErrNone;
1.378 + }
1.379 +