kerneltest/e32test/dll/t_dllwsd.cpp
changeset 0 a41df078684a
--- /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();
+	}
+