sl@0: // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // e32test\thread\t_smpsafe.cpp sl@0: // sl@0: // sl@0: sl@0: #define __E32TEST_EXTENSION__ sl@0: #include sl@0: #include sl@0: #include sl@0: #include "u32std.h" sl@0: #include sl@0: #include sl@0: sl@0: ///////////////////////////////////////////////////////////////////////////// sl@0: // sl@0: //! @SYMTestCaseID KBASE-T_SMPSAFE-2700 sl@0: //! @SYMTestType UT sl@0: //! @SYMPREQ PREQ2094 sl@0: //! @SYMTestCaseDesc SMP compatibility mode test sl@0: //! @SYMTestActions sl@0: //! @SYMTestExpectedResults All tests should pass. sl@0: //! @SYMTestPriority Medium sl@0: //! @SYMTestStatus Implemented sl@0: // sl@0: // The test attempts to prove that the SMPSAFE compatibility mode mechanism sl@0: // works and correctly forces processes which contain any unsafe code to run sl@0: // as if they were on a single-cpu machine. This is done by loading and sl@0: // unloading various combinations of DLLs into the test process itself, and sl@0: // by spawning and exiting various EXEs. sl@0: // sl@0: // Two things are checked for each combination: sl@0: // sl@0: // 1) D_LDRTST is used to retrieve the relevant process's SMP unsafe count, sl@0: // the number of top-level binaries loaded into that process which are not sl@0: // SMP safe. This works on all systems, including uniprocessor, even if sl@0: // compatibility mode is not enabled, as this accounting is done sl@0: // unconditionally. sl@0: // sl@0: // 2) If the system running the test has multiple processors, and one of the sl@0: // compatibility modes is actually enabled, the test process runs a loop sl@0: // designed to see if concurrent execution of threads actually happens. sl@0: // (the loop is in smpsafe.cpp because it is shared between the test and sl@0: // the small slave programs used). sl@0: sl@0: RTest test(_L("T_SMPSAFE")); sl@0: RLdrTest ldd; sl@0: sl@0: RProcess pLoaded; sl@0: TBool SMPPlatform; sl@0: TBool CompatMode; sl@0: sl@0: extern TInt CheckAffinity(); sl@0: sl@0: // load an exe and check that it has the expected SMP unsafe count (check 1) sl@0: // don't resume/delete it yet. sl@0: void DoStartExe(RProcess& p, const TDesC &aFilename, TInt aExpectedUnsafe) sl@0: { sl@0: test_KErrNone(p.Create(aFilename, KNullDesC)); sl@0: test_Equal(aExpectedUnsafe, ldd.ProcessSMPUnsafeCount(p.Handle())); sl@0: } sl@0: sl@0: // resume the exe and if compatibility mode is available, check that the sl@0: // expected outcome of the test loop was observed (check 2) sl@0: // delete it afterward. sl@0: void DoStopExe(RProcess& p, TInt aExpectedUnsafe) sl@0: { sl@0: TRequestStatus s; sl@0: p.Logon(s); sl@0: p.Resume(); sl@0: User::WaitForRequest(s); sl@0: if (CompatMode) sl@0: test_Equal(aExpectedUnsafe ? 1 : 0, s.Int()); sl@0: test_Equal(EExitKill, p.ExitType()); sl@0: p.NotifyDestruction(s); sl@0: p.Close(); sl@0: User::WaitForRequest(s); sl@0: } sl@0: sl@0: void StartExe(const TDesC &aFilename, TInt aExpectedUnsafe) sl@0: { sl@0: DoStartExe(pLoaded, aFilename, aExpectedUnsafe); sl@0: } sl@0: sl@0: void StopExe(TInt aExpectedUnsafe) sl@0: { sl@0: DoStopExe(pLoaded, aExpectedUnsafe); sl@0: } sl@0: sl@0: // start and stop an exe, doing both checks 1 and 2. sl@0: void TryExe(const TDesC &aFilename, TInt aExpectedUnsafe) sl@0: { sl@0: RProcess p; sl@0: DoStartExe(p, aFilename, aExpectedUnsafe); sl@0: DoStopExe(p, aExpectedUnsafe); sl@0: } sl@0: sl@0: // check the main test process, both checks 1 and 2. sl@0: void CheckSelf(TInt aExpectedUnsafe) sl@0: { sl@0: test_Equal(aExpectedUnsafe, ldd.ProcessSMPUnsafeCount(RProcess().Handle())); sl@0: if (CompatMode) sl@0: test_Equal(aExpectedUnsafe ? 1 : 0, CheckAffinity()); sl@0: } sl@0: sl@0: GLDEF_C TInt E32Main() sl@0: { sl@0: RLibrary l, l2; sl@0: sl@0: // Turn off evil lazy dll unloading sl@0: RLoader ldr; sl@0: test(ldr.Connect()==KErrNone); sl@0: test(ldr.CancelLazyDllUnload()==KErrNone); sl@0: ldr.Close(); sl@0: sl@0: test.Title(); sl@0: test.Start(_L("Test SMP safe binary flag")); sl@0: sl@0: test.Next(_L("Get number of CPUs")); sl@0: TInt cpus = UserSvr::HalFunction(EHalGroupKernel, EKernelHalNumLogicalCpus, 0, 0); sl@0: test_Compare(cpus, >, 0); sl@0: SMPPlatform = cpus > 1; sl@0: if (!SMPPlatform) sl@0: { sl@0: CompatMode = EFalse; sl@0: test.Printf(_L("*****************************************************\n")); sl@0: test.Printf(_L("Uniprocessor system, not actually testing compat mode\n")); sl@0: test.Printf(_L("*****************************************************\n")); sl@0: } sl@0: else sl@0: { sl@0: test.Next(_L("Get compatibility mode setting")); sl@0: TInt flags = UserSvr::HalFunction(EHalGroupKernel, EKernelHalConfigFlags, 0, 0); sl@0: test_Compare(flags, >=, 0); sl@0: CompatMode = flags & (EKernelConfigSMPUnsafeCompat | EKernelConfigSMPUnsafeCPU0); sl@0: if (!CompatMode) sl@0: { sl@0: test.Printf(_L("*************************************************\n")); sl@0: test.Printf(_L("Compatibility mode is not enabled, not testing it\n")); sl@0: test.Printf(_L("*************************************************\n")); sl@0: } sl@0: } sl@0: sl@0: test.Next(_L("Load test LDD")); sl@0: TInt r = User::LoadLogicalDevice(_L("d_ldrtst.ldd")); sl@0: test(r==KErrNone || r==KErrAlreadyExists); sl@0: test_KErrNone(ldd.Open()); sl@0: sl@0: test.Next(_L("Check we are safe ourselves")); sl@0: CheckSelf(0); sl@0: sl@0: test.Next(_L("Check safe exe")); sl@0: StartExe(_L("smpsafe0.exe"), 0); sl@0: test.Next(_L("Load already loaded safe exe (self)")); sl@0: TryExe(_L("smpsafe0.exe"), 0); sl@0: StopExe(0); sl@0: sl@0: test.Next(_L("Check safe XIP exe")); sl@0: StartExe(_L("smpsafex0.exe"), 0); sl@0: test.Next(_L("Load already loaded safe XIP exe (self)")); sl@0: TryExe(_L("smpsafex0.exe"), 0); sl@0: StopExe(0); sl@0: sl@0: test.Next(_L("Load unsafe exe")); sl@0: StartExe(_L("smpsafe1.exe"), 1); sl@0: test.Next(_L("Load already loaded unsafe exe")); sl@0: TryExe(_L("smpsafe1.exe"), 1); sl@0: StopExe(1); sl@0: sl@0: test.Next(_L("Load safe exe directly linked to unsafe dll")); sl@0: TryExe(_L("smpsafe2.exe"), 1); sl@0: sl@0: test.Next(_L("Dynamically load unsafe dll")); sl@0: test_KErrNone(l.Load(_L("smpsafea.dll"))); sl@0: CheckSelf(1); sl@0: test.Next(_L("Load safe exe directly linked to loaded unsafe dll")); sl@0: TryExe(_L("smpsafe2.exe"), 1); sl@0: test.Next(_L("Dynamically unload unsafe dll")); sl@0: l.Close(); sl@0: CheckSelf(0); sl@0: sl@0: test.Next(_L("Load safe XIP exe directly linked to unsafe XIP dll")); sl@0: TryExe(_L("smpsafex2.exe"), 1); sl@0: sl@0: test.Next(_L("Dynamically load unsafe XIP dll")); sl@0: test_KErrNone(l.Load(_L("smpsafexa.dll"))); sl@0: CheckSelf(1); sl@0: test.Next(_L("Load safe XIP exe directly linked to loaded unsafe XIP dll")); sl@0: TryExe(_L("smpsafex2.exe"), 1); sl@0: test.Next(_L("Dynamically unload unsafe XIP dll")); sl@0: l.Close(); sl@0: CheckSelf(0); sl@0: sl@0: test.Next(_L("Load safe exe indirectly linked to unsafe dll")); sl@0: TryExe(_L("smpsafe3.exe"), 1); sl@0: sl@0: test.Next(_L("Dynamically load unsafe dll")); sl@0: test_KErrNone(l.Load(_L("smpsafea.dll"))); sl@0: CheckSelf(1); sl@0: test.Next(_L("Load safe exe indirectly linked to loaded unsafe dll")); sl@0: TryExe(_L("smpsafe3.exe"), 1); sl@0: test.Next(_L("Dynamically unload unsafe dll")); sl@0: l.Close(); sl@0: CheckSelf(0); sl@0: sl@0: test.Next(_L("Dynamically load safe dll linked to unsafe dll")); sl@0: test_KErrNone(l.Load(_L("smpsafeb.dll"))); sl@0: CheckSelf(1); sl@0: test.Next(_L("Load safe exe indirectly linked to unsafe dll, inbetween loaded")); sl@0: TryExe(_L("smpsafe3.exe"), 1); sl@0: test.Next(_L("Dynamically load unsafe dll as well")); sl@0: test_KErrNone(l2.Load(_L("smpsafea.dll"))); sl@0: CheckSelf(2); sl@0: test.Next(_L("Dynamically unload safe dll linked to unsafe dll")); sl@0: l.Close(); sl@0: CheckSelf(1); sl@0: test.Next(_L("Dynamically unload unsafe dll as well")); sl@0: l2.Close(); sl@0: CheckSelf(0); sl@0: sl@0: test.Next(_L("Load safe exe directly linked to unsafe XIP dll")); sl@0: TryExe(_L("smpsafe4.exe"), 1); sl@0: sl@0: test.Next(_L("Dynamically load unsafe XIP dll")); sl@0: test_KErrNone(l.Load(_L("smpsafexa.dll"))); sl@0: CheckSelf(1); sl@0: test.Next(_L("Load safe exe directly linked to loaded unsafe XIP dll")); sl@0: TryExe(_L("smpsafe4.exe"), 1); sl@0: test.Next(_L("Dynamically unload unsafe XIP dll")); sl@0: l.Close(); sl@0: CheckSelf(0); sl@0: sl@0: test.Next(_L("Dynamically load figure-eight dll cycle")); sl@0: test_KErrNone(l.Load(_L("smpsafec.dll"))); sl@0: CheckSelf(1); sl@0: test.Next(_L("Load figure-eight from a different point")); sl@0: test_KErrNone(l2.Load(_L("smpsafed.dll"))); sl@0: CheckSelf(2); sl@0: test.Next(_L("Unload original point")); sl@0: l.Close(); sl@0: CheckSelf(1); sl@0: test.Next(_L("Unload second point")); sl@0: l2.Close(); sl@0: CheckSelf(0); sl@0: sl@0: test.Next(_L("Close test LDD")); sl@0: ldd.Close(); sl@0: test_KErrNone(User::FreeLogicalDevice(KLdrTestLddName)); sl@0: sl@0: test.End(); sl@0: return KErrNone; sl@0: }