0
+ − 1
// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
+ − 2
// All rights reserved.
+ − 3
// This component and the accompanying materials are made available
+ − 4
// under the terms of the License "Eclipse Public License v1.0"
+ − 5
// which accompanies this distribution, and is available
+ − 6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+ − 7
//
+ − 8
// Initial Contributors:
+ − 9
// Nokia Corporation - initial contribution.
+ − 10
//
+ − 11
// Contributors:
+ − 12
//
+ − 13
// Description:
+ − 14
// e32test\emul\t_emul.cpp
+ − 15
// Overview:
+ − 16
// Test the mechanism to escape threads from the emulator in order
+ − 17
// to block on Windows objects
+ − 18
// Test launching processes doesn't leak windows TLS indices
+ − 19
// API Information:
+ − 20
// Emulator
+ − 21
// Details:
+ − 22
// - Test the mechanism to escape threads from the emulator in order
+ − 23
// to block on Windows objects:
+ − 24
// - test escape and re-enter mechanism.
+ − 25
// - block on Windows in EPOC thread and escaped EPOC thread.
+ − 26
// Platforms/Drives/Compatibility:
+ − 27
// All.
+ − 28
// Assumptions/Requirement/Pre-requisites:
+ − 29
// Failures and causes:
+ − 30
// Base Port information:
+ − 31
//
+ − 32
//
+ − 33
+ − 34
#define __E32TEST_EXTENSION__
+ − 35
#include <f32file.h>
+ − 36
#include <e32atomics.h>
+ − 37
#include "e32std.h"
+ − 38
#include "e32std_private.h"
+ − 39
#include "e32test.h"
+ − 40
#include "emulator.h"
+ − 41
#include "t_emul.h"
+ − 42
+ − 43
#define WIN32_LEAN_AND_MEAN
+ − 44
#pragma warning( disable : 4201 ) // nonstandard extension used : nameless struct/union
+ − 45
#include <windows.h>
+ − 46
#pragma warning( default : 4201 ) // nonstandard extension used : nameless struct/union
+ − 47
+ − 48
LOCAL_D RTest test(_L("t_emul"));
+ − 49
+ − 50
static TInt ELock;
+ − 51
static HANDLE ESemaphore;
+ − 52
static TInt EResult;
+ − 53
+ − 54
TInt EscapeTimeoutThread(TAny*)
+ − 55
{
+ − 56
User::After(1000000);
+ − 57
if (__e32_atomic_add_ord32(&ELock, 1) == 0)
+ − 58
{
+ − 59
EResult=KErrTimedOut;
+ − 60
ReleaseSemaphore(ESemaphore,1,NULL);
+ − 61
}
+ − 62
return KErrNone;
+ − 63
}
+ − 64
+ − 65
TInt EscapeSignalThread(TAny*)
+ − 66
{
+ − 67
if (__e32_atomic_add_ord32(&ELock, 1) == 0)
+ − 68
{
+ − 69
EResult=KErrNone;
+ − 70
ReleaseSemaphore(ESemaphore,1,NULL);
+ − 71
}
+ − 72
return KErrNone;
+ − 73
}
+ − 74
+ − 75
TInt DoTestEscape(TBool aDoEscape)
+ − 76
//
+ − 77
// Test the mechanism to escape threads from the emulator in order to block on Windows objects
+ − 78
//
+ − 79
{
+ − 80
ELock = 0;
+ − 81
EResult = KRequestPending;
+ − 82
ESemaphore = CreateSemaphoreA(NULL,0,1,NULL);
+ − 83
test (ESemaphore != NULL);
+ − 84
RThread t1,t2;
+ − 85
TRequestStatus s1,s2;
+ − 86
TInt r = t1.Create(KNullDesC,&EscapeSignalThread,0x1000,NULL,NULL);
+ − 87
test (r == KErrNone);
+ − 88
t1.SetPriority(EPriorityLess);
+ − 89
t1.Logon(s1);
+ − 90
t1.Resume();
+ − 91
r = t2.Create(KNullDesC,&EscapeTimeoutThread,0x1000,NULL,NULL);
+ − 92
test (r == KErrNone);
+ − 93
t2.SetPriority(EPriorityMore);
+ − 94
t2.Logon(s2);
+ − 95
t2.Resume();
+ − 96
//
+ − 97
if (aDoEscape)
+ − 98
Emulator::Escape();
+ − 99
r = WaitForSingleObject(ESemaphore,INFINITE);
+ − 100
if (aDoEscape)
+ − 101
Emulator::Reenter();
+ − 102
test (r==WAIT_OBJECT_0);
+ − 103
//
+ − 104
r = EResult;
+ − 105
t1.Kill(0);
+ − 106
t2.Kill(0);
+ − 107
t1.Close();
+ − 108
t2.Close();
+ − 109
User::WaitForRequest(s1);
+ − 110
User::WaitForRequest(s2);
+ − 111
//
+ − 112
CloseHandle(ESemaphore);
+ − 113
return r;
+ − 114
}
+ − 115
+ − 116
void TestEscape()
+ − 117
//
+ − 118
// Test the mechanism to escape threads from the emulator in order to block on Windows objects
+ − 119
//
+ − 120
{
+ − 121
test.Start(_L("Test escape and reenter mechanism"));
+ − 122
for (TInt i = 0;i<10000;++i)
+ − 123
{
+ − 124
Emulator::Escape();
+ − 125
if (i%100 == 0)
+ − 126
Sleep(10);
+ − 127
Emulator::Reenter();
+ − 128
}
+ − 129
test.Next(_L("Block on Windows in EPOC thread"));
+ − 130
TInt r = DoTestEscape(EFalse);
+ − 131
test (r == KErrTimedOut);
+ − 132
test.Next(_L("Block on Windows in escaped EPOC thread"));
+ − 133
r = DoTestEscape(ETrue);
+ − 134
test (r == KErrNone);
+ − 135
test.End();
+ − 136
}
+ − 137
+ − 138
TInt CountRemainingTlsIndicies()
+ − 139
{
+ − 140
const TInt KMax = 2000;
+ − 141
+ − 142
TBool allocated[KMax];
+ − 143
memclr(allocated, sizeof(TBool) * KMax);
+ − 144
TInt i;
+ − 145
for (i = 0 ; i < KMax ; ++i)
+ − 146
{
+ − 147
TInt index = TlsAlloc();
+ − 148
if (index == TLS_OUT_OF_INDEXES)
+ − 149
break;
+ − 150
test(index >= 0 && index < KMax);
+ − 151
allocated[index] = ETrue;
+ − 152
}
+ − 153
for (TInt j = 0 ; j < KMax ; ++j)
+ − 154
{
+ − 155
if (allocated[j])
+ − 156
test(TlsFree(j));
+ − 157
}
+ − 158
return i;
+ − 159
}
+ − 160
+ − 161
void RunSlave(TSlaveAction aAction)
+ − 162
{
+ − 163
RProcess p;
+ − 164
TBuf<8> arg;
+ − 165
arg.Format(_L("%d"), aAction);
+ − 166
test_KErrNone(p.Create(KTEmulSlaveName, arg));
+ − 167
p.Resume();
+ − 168
TRequestStatus status;
+ − 169
p.Logon(status);
+ − 170
User::WaitForRequest(status);
+ − 171
test_KErrNone(status.Int());
+ − 172
test_Equal(EExitKill, p.ExitType());
+ − 173
p.Close();
+ − 174
}
+ − 175
+ − 176
void TestRuntimeCleanup()
+ − 177
{
+ − 178
test.Start(_L("Test Codewarrior runtime library is correctly cleaned up"));
+ − 179
TInt initIndicies = CountRemainingTlsIndicies();
+ − 180
+ − 181
test.Next(_L("Test creating a process doesn't leak windows TLS indicies"));
+ − 182
RunSlave(ESlaveDoNothing);
+ − 183
test_Equal(initIndicies, CountRemainingTlsIndicies());
+ − 184
+ − 185
test.Next(_L("Test leaving in an exe doesn't leak windows TLS indicies"));
+ − 186
RunSlave(ESlaveTrapExceptionInExe);
+ − 187
test_Equal(initIndicies, CountRemainingTlsIndicies());
+ − 188
+ − 189
test.Next(_L("Test leaving in a linked DLL doesn't leak windows TLS indicies"));
+ − 190
RunSlave(ESlaveTrapExceptionInLinkedDll);
+ − 191
test_Equal(initIndicies, CountRemainingTlsIndicies());
+ − 192
+ − 193
test.Next(_L("Test leaving in a loaded DLL doesn't leak windows TLS indicies"));
+ − 194
RunSlave(ESlaveTrapExceptionInLoadedDll);
+ − 195
test_Equal(initIndicies, CountRemainingTlsIndicies());
+ − 196
+ − 197
test.Next(_L("Test cleanup doesn't happen while DLL still loaded"));
+ − 198
RLibrary l;
+ − 199
test_KErrNone(l.Load(KTEmulDll2Name));
+ − 200
RunSlave(ESlaveTrapExceptionInLoadedDll);
+ − 201
TInt midCount = CountRemainingTlsIndicies();
+ − 202
test(initIndicies > midCount);
+ − 203
+ − 204
test.Next(_L("Test previous detach doesn't cause runtime to be re-initalised"));
+ − 205
TTrapExceptionInDllFunc func =
+ − 206
(TTrapExceptionInDllFunc)l.Lookup(KTrapExceptionInDllOrdinal);
+ − 207
test_NotNull(func);
+ − 208
func();
+ − 209
test_Equal(midCount, CountRemainingTlsIndicies());
+ − 210
l.Close();
+ − 211
test_Equal(initIndicies, CountRemainingTlsIndicies());
+ − 212
+ − 213
test.End();
+ − 214
}
+ − 215
+ − 216
+ − 217
void DoSomething2L()
+ − 218
{
+ − 219
test.Printf(_L("@\n"));
+ − 220
}
+ − 221
+ − 222
+ − 223
void DoSomething1L()
+ − 224
{
+ − 225
TInt i = -1, j = 1;
+ − 226
for ( ; ; )
+ − 227
{
+ − 228
i++;
+ − 229
//DoSomething2L() must only be called once , else we know that trap mechanism didn't work
+ − 230
test( i<2);
+ − 231
if (i == j)
+ − 232
{
+ − 233
User::Leave(KErrNotFound);
+ − 234
}
+ − 235
+ − 236
TRAP_IGNORE(DoSomething2L());
+ − 237
TRAPD(errr, DoSomething2L());
+ − 238
TInt r;
+ − 239
TRAP(r, DoSomething2L());
+ − 240
+ − 241
}
+ − 242
}
+ − 243
+ − 244
+ − 245
void LeaveIfArgIsTwo(TInt aCall);
+ − 246
+ − 247
class CFred : public CBase
+ − 248
{
+ − 249
public:
+ − 250
static CFred* NewLC();
+ − 251
CFred();
+ − 252
~CFred();
+ − 253
};
+ − 254
+ − 255
void DoSomething3L()
+ − 256
{
+ − 257
// Push something on the cleanup stack so we can see whyen it gets cleaned up.
+ − 258
CFred *fred = CFred::NewLC();
+ − 259
+ − 260
TInt beforeFunc=0;
+ − 261
TInt betweenFuncAndTRAPD=0;
+ − 262
TInt afterTRAPD=0;
+ − 263
for(TInt loop=1; loop<=2; ++loop)
+ − 264
{
+ − 265
++beforeFunc;
+ − 266
test.Printf(_L("Before LeaveIfArgIsTwo()\n"));
+ − 267
+ − 268
// The first time around the loop, this function call works.
+ − 269
// The second time, it leaves KErrGeneral
+ − 270
// Then when TRAP mechanism isn't working properly the emulator (correctly)
+ − 271
// would delete fred, and (incorrectly) jump to the line
+ − 272
// just after the TRAPD call a few lines further down the file!
+ − 273
LeaveIfArgIsTwo(loop);
+ − 274
+ − 275
++betweenFuncAndTRAPD;
+ − 276
test.Printf(_L("Between LeaveIfArgIsTwo() and TRAPD\n"));
+ − 277
+ − 278
TRAPD(err, test.Printf(_L("Inside TRAPD\n") ) );
+ − 279
+ − 280
+ − 281
// It should only be possible to reach this section of code by executing all the lines
+ − 282
// between LeaveIfArgIsTwo and here.
+ − 283
++afterTRAPD;
+ − 284
+ − 285
}
+ − 286
+ − 287
// Should NEVER get here because LeaveIfArgIsTwo did a leave the second time around the loop
+ − 288
test.Printf(_L("After loop (should NEVER get here) -\n\
+ − 289
beforeFunc %d\n\
+ − 290
betweenFuncAndTRAPD %d\n\
+ − 291
afterTRAPD %d\n"),
+ − 292
beforeFunc, betweenFuncAndTRAPD, afterTRAPD);
+ − 293
+ − 294
test.Printf(_L("It should be impossible for afterTRAPD to be larger than betweenFuncAndTRAPD\n"));
+ − 295
test(afterTRAPD <= betweenFuncAndTRAPD);
+ − 296
+ − 297
// Cleanup our cleanup stack.
+ − 298
CleanupStack::PopAndDestroy(&fred);
+ − 299
}
+ − 300
+ − 301
void LeaveIfArgIsTwo(TInt aCall)
+ − 302
{
+ − 303
+ − 304
test.Printf(_L("aCall %d\n"), aCall);
+ − 305
if(aCall == 2)
+ − 306
{
+ − 307
User::Leave(KErrGeneral);
+ − 308
}
+ − 309
}
+ − 310
+ − 311
CFred *CFred::NewLC()
+ − 312
{
+ − 313
CFred *self = new(ELeave) CFred;
+ − 314
CleanupStack::PushL(self);
+ − 315
return self;
+ − 316
}
+ − 317
+ − 318
CFred::CFred()
+ − 319
{
+ − 320
test.Printf(_L("CFred %x\n"), this);
+ − 321
}
+ − 322
+ − 323
CFred::~CFred()
+ − 324
{
+ − 325
test.Printf(_L("~CFred %x\n"), this);
+ − 326
}
+ − 327
+ − 328
+ − 329
+ − 330
GLDEF_C TInt E32Main()
+ − 331
//
+ − 332
//
+ − 333
//
+ − 334
{
+ − 335
test.Title();
+ − 336
test.Start(_L("Starting tests ..."));
+ − 337
+ − 338
// Turn off evil lazy dll unloading
+ − 339
RLoader l;
+ − 340
test(l.Connect()==KErrNone);
+ − 341
test(l.CancelLazyDllUnload()==KErrNone);
+ − 342
l.Close();
+ − 343
+ − 344
TestEscape();
+ − 345
#ifdef __CW32__
+ − 346
TestRuntimeCleanup();
+ − 347
#endif
+ − 348
+ − 349
// The following tests were added to test that the TRAP mechanism works correctly in case of
+ − 350
// nested TRAP's. A compiler bug (winscw) caused the following tests to fail, since the wrong
+ − 351
// trap handler would be invoked, when User::Leave() was called.
+ − 352
+ − 353
test.Next(_L("Check User::Leave is handled by the correct TRAP handler when nested TRAPs are present - Simple scenario\n"));
+ − 354
+ − 355
TRAPD(err, DoSomething1L());
+ − 356
test(err == KErrNotFound);
+ − 357
+ − 358
test.Next(_L("Check User::Leave is handled by the correct TRAP handler when nested TRAPs are present - Cleanup stack scenario\n"));
+ − 359
__UHEAP_MARK;
+ − 360
CTrapCleanup* tc = CTrapCleanup::New();
+ − 361
if (tc == 0) return KErrNoMemory;
+ − 362
+ − 363
TRAPD(err2, DoSomething3L());
+ − 364
test(err2==KErrGeneral);
+ − 365
+ − 366
delete tc;
+ − 367
__UHEAP_MARKEND;
+ − 368
+ − 369
+ − 370
test.End();
+ − 371
test.Close();
+ − 372
return KErrNone;
+ − 373
}
+ − 374