--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/mmu/t_asid.cpp Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,240 @@
+// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// e32test\misc\t_asid.cpp
+//
+//
+#define __E32TEST_EXTENSION__
+#include <e32test.h>
+#include <e32svr.h>
+#include <u32std.h>
+
+#include "t_asid.h"
+#include "d_asid.h"
+
+#define TEST_R(r, e) if (!(e)) {RDebug::Printf("Failure at line %d, r = %d", __LINE__, r); return r; }
+
+_LIT(KDummyProcessName,"T_ASID_DUMMY");
+
+RTest test(_L("T_ASID"));
+
+const TUint KMaxAsids = 256; // On arm and current version of FMM has maximum of 256 active processes at once.
+const TUint KLeakedProcesses = KMaxAsids<<1;
+
+void TestMaxAsids()
+ {
+ test.Printf(_L("Attempt to load > %d zombie processes\n"), KMaxAsids);
+ RProcess* processes = new RProcess[KLeakedProcesses];
+ TUint i = 0;
+ for (; i < KLeakedProcesses; i++)
+ {
+ test_KErrNone(processes[i].Create(KDummyProcessName, KNullDesC));
+ TRequestStatus s;
+ processes[i].Logon(s);
+ test_Equal(KRequestPending, s.Int());
+ processes[i].Resume();
+ User::WaitForRequest(s);
+ if (processes[i].ExitType()!=EExitKill || processes[i].ExitReason()!=KErrNone)
+ {
+ TExitCategoryName aExitCategory = processes[i].ExitCategory();
+ test.Printf(_L("Exit %d,%d,%S\n"),processes[i].ExitType(),processes[i].ExitReason(),&aExitCategory);
+ test(0);
+ }
+ }
+ // Clean up the process handles here.
+ for (i = 0; i < KLeakedProcesses; i++)
+ processes[i].Close();
+ delete[] processes;
+ }
+
+
+TInt TestIpcThread(TAny*)
+ {
+ // Start a server for zombie to connect to.
+ RServer2 ipcServer;
+ TInt r = ipcServer.CreateGlobal(KAsidIpcServerName);
+ TEST_R(r, r == KErrNone);
+ RMessage2 ipcMessage;
+ for (TUint i = 0; i < 300; i++)
+ {
+ // Start the process.
+ RProcess zombie;
+ TInt r = zombie.Create(KDummyProcessName, KAsidIpcServerName);
+ TEST_R(r, r == KErrNone);
+ TRequestStatus s;
+ zombie.Logon(s);
+ TEST_R(s.Int(), s.Int() == KRequestPending);
+ zombie.Resume();
+
+ // Wait for the connect and ipc message from the zombie
+ ipcServer.Receive(ipcMessage);
+ TEST_R(ipcMessage.Function(), ipcMessage.Function() == EConnect);
+ ipcMessage.Complete(KErrNone);
+ ipcServer.Receive(ipcMessage);
+ TEST_R(ipcMessage.Function(), ipcMessage.Function() == EIpcData);
+
+ TUint8 array1[KAsidDesLen];
+ memset(array1, KAsidValue, KAsidDesLen);
+ TPtr8 buf1(array1, KAsidDesLen, KAsidDesLen);
+
+ TUint8 array[KAsidDesLen];
+ TPtr8 buf(array, KAsidDesLen);
+ test_Equal(KErrNone, ipcMessage.Read(0, buf));
+ r = ipcMessage.Read(0, buf);
+ TEST_R(r, r == KErrNone);
+ r = buf.Compare(buf1);
+ TEST_R(r, r == 0);
+ ipcMessage.Complete(KErrNone);
+
+ // Try to read from the client while it is exiting.
+ ipcServer.Receive(ipcMessage);
+ TEST_R(ipcMessage.Function(), ipcMessage.Function() == EIpcData);
+ User::After(5*i);
+
+ r = ipcMessage.Read(0, buf);
+ //RDebug::Printf("%d", r);
+
+ // Wait for client to exit.
+ User::WaitForRequest(s);
+ TEST_R(s.Int(), s.Int() == KErrNone);
+ ipcServer.Receive(ipcMessage); // Clear out the disconnect message.
+ TEST_R(ipcMessage.Function(), ipcMessage.Function() == EDisConnect);
+ ipcMessage.Complete(KErrNone);
+ zombie.Close();
+ }
+ ipcServer.Close();
+ return KErrNone;
+ }
+
+
+TInt TestDesThread(TAny*)
+ {
+ RAsidLdd asidLdd;
+ TInt r = asidLdd.Open();
+ TEST_R(r, r == KErrNone);
+ RMessage2 desMessage;
+ RServer2 desServer;
+ // Start a server for zombie to connect to.
+ r = desServer.CreateGlobal(KAsidDesServerName);
+ TEST_R(r, r == KErrNone);
+
+ for (TUint i = 0; i < 300; i++)
+ {
+ // Start the process.
+ RProcess zombie;
+ r = zombie.Create(KDummyProcessName, KAsidDesServerName);
+ TEST_R(r, r == KErrNone);
+ TRequestStatus s;
+ zombie.Logon(s);
+ TEST_R(s.Int(), s.Int() == KRequestPending);
+ zombie.Resume();
+
+ // Wait for the connect and des message from the zombie
+ desServer.Receive(desMessage);
+ TEST_R(desMessage.Function(), desMessage.Function() == EConnect);
+ desMessage.Complete(KErrNone);
+ desServer.Receive(desMessage);
+ TEST_R(desMessage.Function(), desMessage.Function() == EDesData);
+
+ TAny* desPtr = (TAny*)desMessage.Ptr0();
+ TAny* threadPtr = (TAny*)desMessage.Ptr1();
+ // Open a handle on the client's thread to stop it being deleted.
+ r = asidLdd.OpenThread(threadPtr);
+ TEST_R(r, r == KErrNone);
+ SDesHeader desHdr;
+ desHdr.iDes = desPtr;
+ r = asidLdd.ReadDesHeader(threadPtr, desHdr);
+ TEST_R(r, r == KErrNone);
+ TEST_R(desHdr.iLength, desHdr.iLength == KAsidDesLen);
+ TEST_R(desHdr.iMaxLength, desHdr.iMaxLength == KAsidDesLen);
+ desMessage.Complete(KErrNone);
+
+ // Wait for further des message from client.
+ desServer.Receive(desMessage);
+ TEST_R(desMessage.Function(), desMessage.Function() == EDesData);
+ desPtr = (TAny*)desMessage.Ptr0();
+ TEST_R((TInt)desMessage.Ptr1(), (TInt)desMessage.Ptr1() == (TInt)threadPtr);
+
+ // Try to read descriptor header from the client while it is exiting.
+ TInt r = asidLdd.ReadDesHeader(threadPtr, desHdr);
+ User::After(5*i);
+
+ //RDebug::Printf("%d", r);
+ if (r == KErrNone)
+ {
+ TEST_R(desHdr.iLength, desHdr.iLength == KAsidDesLen);
+ TEST_R(desHdr.iMaxLength, desHdr.iMaxLength == KAsidDesLen);
+ }
+
+ // Wait for client to exit.
+ User::WaitForRequest(s);
+ TEST_R(s.Int(), s.Int() == KErrNone);
+ desServer.Receive(desMessage); // Clear out the disconnect message.
+ TEST_R(desMessage.Function(), desMessage.Function() == EDisConnect);
+ desMessage.Complete(KErrNone);
+ // Close handles in client process and thread.
+ r = asidLdd.CloseThread();
+ TEST_R(r, r == KErrNone);
+ zombie.Close();
+ }
+ desServer.Close();
+ asidLdd.Close();
+ return KErrNone;
+ }
+
+GLDEF_C TInt E32Main()
+ {
+ test.Title();
+ test.Start(_L("Test zombie processes release their ASIDs"));
+
+ // Get memory model.
+ if ((UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, NULL, NULL)&EMemModelTypeMask) < EMemModelTypeFlexible)
+ {
+ test.Printf(_L("SKIPPING TEST - Older memory models don't release ASIDs from zombie processes\n"));
+ test.End();
+ return KErrNone;
+ }
+
+ TestMaxAsids();
+
+ test.Next(_L("Test ipc message copy to a zombie process"));
+
+ test_KErrNone(TestIpcThread(NULL));
+ TestMaxAsids();
+
+ test.Next(_L("Test reading descriptor header from a zombie process"));
+ test_KErrNone(TestDesThread(NULL));
+ TestMaxAsids();
+
+ test.Next(_L("Test ipc and des header to zombie processes concurrently"));
+ RThread ipcThread;
+ RThread desThread;
+ ipcThread.Create(KNullDesC, TestIpcThread, 0x2000, NULL, NULL);
+ desThread.Create(KNullDesC, TestDesThread, 0x2000, NULL, NULL);
+ TRequestStatus ipcStatus;
+ TRequestStatus desStatus;
+ ipcThread.Logon(ipcStatus);
+ desThread.Logon(desStatus);
+ ipcThread.Resume();
+ desThread.Resume();
+
+ // Wait for threads to complete.
+ User::WaitForRequest(ipcStatus);
+ test_KErrNone(ipcStatus.Int());
+ User::WaitForRequest(desStatus);
+ test_KErrNone(desStatus.Int());
+ TestMaxAsids();
+
+ test.End();
+ return KErrNone;
+ }