--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/dll/t_dllwsd.cpp Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,554 @@
+/*
+* Copyright (c) 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:
+*
+*/
+
+
+/**
+Overview:
+ Test DLL Writeable Static Data support
+
+API Information:
+
+
+Details:
+ - Each process has independent DLL WSD
+ - Whether DLL linked directly or indirectly
+ - Whether DLL loaded dynamically or statically
+ - DLL WSD is consistent under heavy usage by multiple processes
+ - IPC works to/from DLL WSD descriptors & TRequestStatus
+ This source file builds in 4 configurations, with each of
+ direct and indirect linking either used or not used.
+ These configurations are set by 4 MM files, t_dllwsd[d][i].mmp
+ Any of the exe created from the MMP files can be started
+ to run the tests, it does not matter which is used.
+ All exe configurations will be used during the tests.
+
+Platforms/Drives/Compatibility:
+ All.
+
+Assumptions/Requirement/Pre-requisites:
+
+
+Failures and causes:
+
+
+Base Port information:
+
+*/
+
+#define __E32TEST_EXTENSION__
+
+#include <e32test.h>
+#include <e32svr.h>
+#include <f32dbg.h>
+#include <u32std.h>
+#include "t_dllwsd_dll.h"
+#include "t_dllwsd_dlli.h"
+
+
+LOCAL_D RTest test(_L("T_DLLWSD"));
+
+enum TTestFunc
+ {
+ ETestFuncTestCons=1,
+ ETestFuncThrash1,
+ ETestFuncIpcTest,
+ ETestFuncIpcGet,
+ ETestFuncIpcReverse,
+ ETestFuncIpcSet,
+ ETestFuncPanic,
+ };
+
+// Test session for IPC use of WSD, talks to the same server as RDllWsd
+class RIpcTestSession : public RSessionBase
+ {
+ public:
+ TInt Connect()
+ {
+ return CreateSession(_L("IpcTestServer"), TVersion());
+ }
+ void Get(TBuf<60000>& buf, TRequestStatus& req)
+ {
+ SendReceive(ETestFuncIpcGet, TIpcArgs(&buf), req);
+ }
+ void Reverse(TRequestStatus& req)
+ {
+ SendReceive(ETestFuncIpcReverse, req);
+ }
+ void Set(const TBuf<60000>& buf, TRequestStatus& req)
+ {
+ SendReceive(ETestFuncIpcSet, TIpcArgs(&buf), req);
+ }
+ };
+
+#ifdef T_DLLWSD_DIRECT
+void FillBuf(TInt start, TInt inc)
+ {
+ for (int ii=0; ii<WsdBuf().Length(); ii++)
+ {
+ WsdBuf()[ii] = (unsigned short)start;
+ start += inc;
+ }
+ }
+
+TInt CheckBuf(TInt start, TInt inc)
+ {
+ for (int ii=0; ii<WsdBuf().Length(); ii++)
+ {
+ if (WsdBuf()[ii] != start)
+ return KErrGeneral;
+ start += inc;
+ }
+ return KErrNone;
+ }
+#endif
+
+class CDllWsdServer : public CServer2
+ {
+public:
+ CDllWsdServer() : CServer2(EPriorityStandard)
+ {
+ }
+ CSession2* NewSessionL(const TVersion& /*aVersion*/,const RMessage2& /*aMessage*/) const;
+ mutable TInt iCount;
+ };
+
+class CDllWsdSession : public CSession2
+ {
+public:
+ CDllWsdSession()
+ {
+ ResetConsistencyCheck();
+ }
+
+ ~CDllWsdSession()
+ {
+ // transient server immediate shutdown when last client disconnects
+ if (--((CDllWsdServer*)Server())->iCount == 0)
+ CActiveScheduler::Stop();
+ }
+
+ void ResetConsistencyCheck()
+ {
+ iX=42;
+ iY=0;
+ }
+
+ void OptResetConsistencyCheck()
+ {
+#if !defined(T_DLLWSD_DIRECT) && !defined(T_DLLWSD_INDIRECT)
+ // if DLL has been unloaded (dynamic library closed, no static link)
+ // WSD will be reset
+ ResetConsistencyCheck();
+#endif
+ }
+
+ TInt TestConsistency()
+ {
+#ifdef T_DLLWSD_DIRECT
+ // static direct
+ if (WsdFuncX() != iX++)
+ return KErrGeneral;
+ if (WsdFuncY() != iY++)
+ return KErrGeneral;
+#endif
+
+#ifdef T_DLLWSD_INDIRECT
+ // static indirect
+ if (IndWsdFuncX() != iX++)
+ return KErrGeneral;
+ if (IndWsdFuncY() != iY++)
+ return KErrGeneral;
+#endif
+
+ // dynamic direct
+ OptResetConsistencyCheck();
+ RLibrary lib;
+ TInt err = lib.Load(_L("t_dllwsd_dll"));
+ if (err) return err;
+ if ((*lib.Lookup(1))/*WsdFuncX*/() != iX++)
+ return KErrGeneral;
+ if ((*lib.Lookup(2))/*WsdFuncX*/() != iY++)
+ return KErrGeneral;
+ lib.Close();
+
+ // dynamic indirect
+ OptResetConsistencyCheck();
+ err = lib.Load(_L("t_dllwsd_dlli"));
+ if (err) return err;
+ if ((*lib.Lookup(1))/*IndWsdFuncX*/() != iX++)
+ return KErrGeneral;
+ if ((*lib.Lookup(2))/*IndWsdFuncX*/() != iY++)
+ return KErrGeneral;
+ lib.Close();
+
+ return KErrNone;
+ }
+
+ TInt Thrash1()
+ {
+ TTime start;
+ start.HomeTime();
+ TInt count = 0;
+ const TTimeIntervalMicroSeconds limit(10000000); // 10 seconds
+ for (;; count++)
+ {
+ TInt err = TestConsistency();
+ if (err) return err;
+ TTime now;
+ now.HomeTime();
+ if (now.MicroSecondsFrom(start) > limit)
+ break;
+ }
+ return count > 0 ? count : -count;
+ }
+
+ TInt IpcTest()
+ {
+#ifdef T_DLLWSD_DIRECT
+ RIpcTestSession s;
+ TInt err = s.Connect();
+ if (!err) return err;
+ WsdBuf().SetLength(WsdBuf().MaxLength());
+ for (int i=0; i<10; i++)
+ {
+ // 0..n -> buf
+ FillBuf(0,1);
+ err = CheckBuf(0,1);
+ if (!err) return err;
+
+ // buf -> server
+ s.Set(WsdBuf(), WsdReq());
+ err = CheckBuf(0,1);
+ if (!err) return err;
+
+ // use TReqestStatus in WSD
+ User::WaitForRequest(WsdReq());
+ if (!WsdReq().Int()) return WsdReq().Int();
+
+ // 0..0 -> buf
+ FillBuf(0,0);
+ err = CheckBuf(0,0);
+ if (!err) return err;
+ WsdReq() = KRequestPending;
+
+ // reverse buf on server
+ s.Reverse(WsdReq());
+
+ // local buf is still 0..0
+ err = CheckBuf(0,0);
+ if (!err) return err;
+
+ // use TReqestStatus in WSD
+ User::WaitForRequest(WsdReq());
+ if (!WsdReq().Int()) return WsdReq().Int();
+
+ // local buf is still 0..0
+ err = CheckBuf(0,0);
+ if (!err) return err;
+
+ // get buf from server
+ s.Get(WsdBuf(), WsdReq());
+ User::WaitForRequest(WsdReq());
+
+ // buf is n..0
+ err = CheckBuf(59999,-1);
+ if (!err) return err;
+ }
+ s.Close();
+ return KErrNone;
+#else
+ return KErrNotSupported;
+#endif
+ }
+
+ void ServiceL(const RMessage2& aMessage)
+ {
+#ifdef T_DLLWSD_DIRECT
+ TInt ii=0;
+#endif
+ switch (aMessage.Function())
+ {
+ case ETestFuncTestCons:
+ aMessage.Complete(TestConsistency());
+ break;
+ case ETestFuncThrash1:
+ aMessage.Complete(Thrash1());
+ break;
+ case ETestFuncIpcTest:
+ aMessage.Complete(IpcTest());
+ break;
+ case ETestFuncIpcGet:
+#ifdef T_DLLWSD_DIRECT
+ aMessage.WriteL(0, WsdBuf());
+ aMessage.Complete(KErrNone);
+#else
+ aMessage.Complete(KErrNotSupported);
+#endif
+ break;
+ case ETestFuncIpcReverse:
+#ifdef T_DLLWSD_DIRECT
+ for (ii=0; ii<WsdBuf().Length()/2; ii++)
+ {
+ TInt o = WsdBuf().Length() - 1 - ii;
+ TInt t = WsdBuf()[ii];
+ WsdBuf()[ii] = WsdBuf()[o];
+ WsdBuf()[o] = (unsigned short)t;
+ }
+ aMessage.Complete(KErrNone);
+#else
+ aMessage.Complete(KErrNotSupported);
+#endif
+ break;
+ case ETestFuncIpcSet:
+#ifdef T_DLLWSD_DIRECT
+ aMessage.ReadL(0, WsdBuf());
+ aMessage.Complete(KErrNone);
+#else
+ aMessage.Complete(KErrNotSupported);
+#endif
+ break;
+ case ETestFuncPanic:
+ User::Panic(_L("As requested..."), 0);
+ break;
+ default:
+ aMessage.Panic(_L("Unrecognised"), aMessage.Function());
+ break;
+ }
+ }
+
+ int iX;
+ int iY;
+ };
+
+CSession2* CDllWsdServer::NewSessionL(const TVersion& /*aVersion*/,const RMessage2& /*aMessage*/) const
+ {
+ iCount++;
+ return new(ELeave) CDllWsdSession;
+ }
+
+TInt SlaveMain()
+ {
+ TName name;
+ User::CommandLine(name);
+
+ CTrapCleanup* cleanup = CTrapCleanup::New();
+ if (!cleanup)
+ return KErrNoMemory;
+
+ TRAPD(err,
+ {
+ CActiveScheduler* sched=new(ELeave) CActiveScheduler;
+ CActiveScheduler::Install(sched);
+
+ CDllWsdServer* server = new(ELeave) CDllWsdServer;
+ server->StartL(name);
+
+ RProcess::Rendezvous(KErrNone);
+ CActiveScheduler::Start();
+
+ delete server;
+ delete sched;
+ });
+ delete cleanup;
+
+ return err;
+ }
+
+//
+// Master test controller
+//
+
+class RDllWsd : public RSessionBase
+ {
+public:
+ RDllWsd(const TDesC& aServerName, const TDesC& aExeName = _L("t_dllwsddi"))
+ {
+ test.Start(_L("RDllWsd create"));
+ RProcess proc;
+ test_KErrNone(proc.Create(aExeName, aServerName));
+ TRequestStatus req;
+ proc.Rendezvous(req);
+ proc.Resume();
+ User::WaitForRequest(req);
+ test_KErrNone(req.Int());
+ test_KErrNone(CreateSession(aServerName, TVersion()));
+ proc.Close();
+ test.End();
+ }
+ TInt ConsistencyTest()
+ {
+ return SendReceive(ETestFuncTestCons);
+ }
+ void ThrashTest1(TRequestStatus& aStatus)
+ {
+ SendReceive(ETestFuncThrash1, aStatus);
+ }
+ TInt IpcTest()
+ {
+ return SendReceive(ETestFuncIpcTest);
+ }
+ TInt Panic()
+ {
+ return SendReceive(ETestFuncPanic);
+ }
+ };
+
+void BasicTest()
+ {
+ test.Start(_L("BasicConsistency"));
+
+ // create a test server/process for each link variant
+ RDllWsd slaves[] =
+ {
+ RDllWsd(_L("slave1"), _L("t_dllwsd")),
+ RDllWsd(_L("slave2"), _L("t_dllwsdd")),
+ RDllWsd(_L("slave3"), _L("t_dllwsdi")),
+ RDllWsd(_L("slave4"), _L("t_dllwsddi")),
+ RDllWsd(_L("slave5"), _L("t_dllwsd")),
+ RDllWsd(_L("slave6"), _L("t_dllwsdd")),
+ RDllWsd(_L("slave7"), _L("t_dllwsdi")),
+ RDllWsd(_L("slave8"), _L("t_dllwsddi"))
+ };
+ TInt nSlaves = sizeof(slaves)/sizeof(slaves[0]);
+ TInt ii;
+ // do this a few times
+ for (TInt jj=0; jj<10; jj++)
+ {
+ // all four test variants
+ for (ii=0; ii<nSlaves; ii++)
+ {
+ // repeat the test different numbers of times, to ensure WSD values diverge
+ for (TInt kk=0; kk<ii+2; kk++)
+ {
+ // change order in which processes run the tests
+ int idx = (ii + jj) % nSlaves;
+ test_KErrNone(slaves[idx].ConsistencyTest());
+ }
+ }
+ // start and stop an extra process
+ RDllWsd extra(_L("slave9"), _L("t_dllwsddi"));
+ test_KErrNone(extra.ConsistencyTest());
+ extra.Close();
+ }
+
+ for (ii=nSlaves-1; ii>=0; ii--)
+ slaves[ii].Close();
+
+ test.End();
+ }
+
+void ThrashTest1()
+ {
+ test.Start(_L("ThrashTest1"));
+
+ // create a test server/process for each link variant
+ RDllWsd slaves[4] =
+ {
+ RDllWsd(_L("slaveA"), _L("t_dllwsd")),
+ RDllWsd(_L("slaveB"), _L("t_dllwsdd")),
+ RDllWsd(_L("slaveC"), _L("t_dllwsdi")),
+ RDllWsd(_L("slaveD"), _L("t_dllwsddi"))
+ };
+
+ TRequestStatus req[4];
+ TInt ii;
+ // start the thrash tests
+ for (ii=0; ii<4; ii++)
+ {
+ slaves[ii].ThrashTest1(req[ii]);
+ test.Printf(_L("slave %d thrash started\n"), ii);
+ }
+
+ // show some progress to indicate that things are running
+ for (ii=0; ii<8; ii++)
+ {
+ test.Printf(_L("Waiting %d\n"), ii);
+ User::After(1000000);
+ }
+ // demonstrate that test processes are still doing their stuff
+ test.Printf(_L("Still a couple of seconds to wait...\n"));
+
+ // wait till the test process are done
+ for (ii=0; ii<4; ii++)
+ {
+ User::WaitForRequest(req[ii]);
+ // show how much each process did
+ test.Printf(_L("Slave %d count = %d\n"), ii, req[ii].Int());
+ test_NotNegative(req[ii].Int());
+ }
+
+ for (ii=3; ii>=0; ii--)
+ slaves[ii].Close();
+
+ test.End();
+ }
+
+void PanicTest()
+ {
+ test.Start(_L("PanicTest1"));
+
+ // create a test server/process for each link variant
+ RDllWsd slaves[4] =
+ {
+ RDllWsd(_L("slaveP1"), _L("t_dllwsd")),
+ RDllWsd(_L("slaveP2"), _L("t_dllwsdd")),
+ RDllWsd(_L("slaveP3"), _L("t_dllwsdi")),
+ RDllWsd(_L("slaveP4"), _L("t_dllwsddi"))
+ };
+ TInt ii;
+ for (ii=0; ii<4; ii++)
+ slaves[ii].Panic();
+
+ for (ii=0; ii<4; ii++)
+ slaves[ii].Close();
+ }
+
+void IpcTest()
+ {
+ test.Start(_L("IPC test"));
+ // these two processes will use t_dllwsddi, static link variant
+ RDllWsd server(_L("IpcTestServer"));
+ RDllWsd client(_L("IpcTestClient"));
+ // client will talk to IpcTestServer, ie the server
+ test_KErrNone(client.IpcTest());
+ client.Close();
+ server.Close();
+ test.End();
+ }
+
+TInt MasterMain()
+ {
+ test.Title();
+ test.Start(_L("Test"));
+
+ BasicTest();
+ ThrashTest1();
+ IpcTest();
+// PanicTest();
+
+ test.End();
+ return KErrNone;
+ }
+
+TInt E32Main()
+ {
+ if (User::CommandLineLength() > 0) // command line contains server name
+ return SlaveMain();
+ else
+ return MasterMain();
+ }
+