kerneltest/e32test/pipe/t_pipe4.cpp
author Slion
Tue, 08 Dec 2009 08:11:42 +0100
branchanywhere
changeset 19 f6d3d9676ee4
parent 0 a41df078684a
permissions -rw-r--r--
Trying to figure out how to implement my WINC like compatibility layer. Going the emulation way is probably not so smart. We should not use the kernel but rather hook native functions in the Exec calls.

// Copyright (c) 2002-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\pipe\t_pipe4.cpp
// This is very similar to User::WaitForRequest() but allows the User
// to specify multiple TRequestStatus objects to wait on. The function
// will return when the first TRequestStatus object completes.
// / Header Files////////
// 
//

/**
 @STMTestCaseID			KBASE-T_PIPE4-0218
 @SYMPREQ				PREQ1460
 @SYMREQ					REQ6142
 @SYMCR					CR0923
 @SYMTestCaseDesc		User::WaitForNRequests functional test
 @SYMTestPriority		High
 @SYMTestActions			Tests the operation of the API User::WaitForNRequests().
 @SYMTestExpectedResults	Test should pass
*/

#define __E32TEST_EXTENSION__

#include <e32test.h>
#include <e32svr.h>
#include <e32des8.h>
#include <e32des8_private.h>
#include <e32cmn.h>
#include <e32cmn_private.h>
#include <e32std.h>
#include <e32std_private.h>

#include "rpipe.h"

//// Test Objects for All threads////

LOCAL_D RTest test(_L("t_pipe4"));
LOCAL_D RTest test2(_L("t_pipe_t2"));
LOCAL_D RTest test3(_L("t_pipe_t3"));
LOCAL_D RTest test4(_L("t_pipe_t4"));
LOCAL_D RTest test5(_L("t_pipe_t5"));

//// Thread Name Constants //////
_LIT(KThread2Name, "WaitThread");
_LIT(KThread3Name, "NotifyDataThread");
_LIT(KThread4Name, "NotifySpaceThread");
_LIT(KThread5Name, "CancelNotifyThread");

_LIT(KPipe1Name,"TestPipeP");
_LIT(KPipe2Name,"TestPipeQ");
_LIT(KPipe3Name,"TestPipeR");
_LIT(KPipe4Name,"TestPipeS");
_LIT(KPipe5Name,"TestPipeT");


_LIT8(KTestDataNum,"1234567890");



const TInt KHeapSize=0x2000;


// Following class is used to pass thread handle information to different threads.
class TData
	{
public:
	TData(RPipe* aPipe, RPipe *bPipe, TInt aSize);
	RPipe* rPipe;								// Pipe Read handle
	RPipe* wPipe;								// Pipe Write handle
	TInt iSize;


	};

TData::TData(RPipe * aPipe , RPipe *bPipe, TInt aSize) {
	rPipe = aPipe;
	wPipe = bPipe;
	iSize = aSize;

}

////////////////////////////////////////////////////
//// WaitThread : Function opens the Read handle
////			for the pipe passed to it.
////
////			CPipeName --> Pipe Name
////			aData 	  --> Read Write Handle
////
////////////////////////////////////////////////////
TBufC<100> 		cPipeName;

TInt WaitThread(TAny* aData) {

	test2.Start(_L("PIPE TEST:WaitThread Entry"));
	TInt 		ret;

	TData& data = *(TData *)aData; 					// aData will have pipe handles and size.

	ret = data.rPipe->Open(cPipeName,RPipe::EOpenToRead);
	test2 (ret == KErrNone);

	test2.Printf(_L("PIPE TEST:WaitThread Exit\n"));
	test2.End();
	test2.Close();
	return KErrNone;
}

////////////////////////////////////////////////////
//// NotifyDataThread :
////			Function writes data into the pipe.
////
////			aData 	  --> Read Write Handle
////
////////////////////////////////////////////////////

TInt NotifyDataThread(TAny* aData) {

	TBufC8<50> 			cTestData(KTestDataNum); 	// Test Data
	TInt 				ret;

	test3.Start(_L("PIPE TEST:NotifyDataThread Entry"));

	TData& data = *(TData *)aData; 					// aData will have pipe handles and size.

	User::After(10000);

	ret = data.wPipe->Write(cTestData,cTestData.Length());
	test3(ret == cTestData.Length());

	test3.Printf(_L("PIPE TEST:NotifyDataThread Exit\n"));
	test3.End();
	test3.Close();
	return KErrNone;
}

////////////////////////////////////////////////////
//// NotifySpaceThread :
////			Function flush the pipe and makes
////			it free.
////
////			aData 	  --> Read Write Handle
////
////////////////////////////////////////////////////

TInt NotifySpaceThread(TAny* aData) {


	test4.Start(_L("PIPE TEST:NotifySpaceThread Entry"));

	TData& data = *(TData *)aData; 					// aData will have pipe handles and size.

//	User::After(10000000);

	data.rPipe->Flush();

	test4.Printf(_L("PIPE TEST:NotifySpaceThread Exit\n"));
	test4.End();
	test4.Close();
	return KErrNone;
}


////////////////////////////////////////////////////
//// CancelNotifyThread :
////			Function cancels Space available request
////			or Cancels Data available request.
////
////			CancelFlag  --> 1 CancelSpaceAvailable
////							0 for CancelDataAvailable
////
////			aData 	  --> Read Write Handle
////
////////////////////////////////////////////////////

TInt		CancelFlag; // 1 CancelSpaceAvailable ; 0 for CancelDataAvailable
TInt CancelNotifyThread(TAny* aData) {

	test5.Start(_L("PIPE TEST:CancelNotifyThread Entry"));

	TData& data = *(TData *)aData; 					// aData will have pipe handles and size.

	if ( CancelFlag == 1)
		data.wPipe->CancelSpaceAvailable();
	else if ( CancelFlag == 0)
		data.rPipe->CancelDataAvailable();
	else
		test5.Printf(_L("PIPE TEST: *** Illegal Cancel\n"));

	test5.Printf(_L("PIPE TEST:CancelNotifyThread Exit\n"));
	test5.End();
	test5.Close();
	return KErrNone;
}

////////////////////////////////////////////////////
//// Main Thread
////
////
////////////////////////////////////////////////////
/*


1. Create 5 (UN)Pipes.
2. Register NotifyData AVailable on 5 pipes.
3. Create Thread 1
4. Wait for n request.
5. In thread 1 write data into any one pipe. Exit
6. Main should show 1 stat variable updated.

7. Again call Wait for n request.
8. It shall come out as one stat is Available.

9. Close all the pipes. Repeat same for NotifySpace available.

10. Define 5 N-Pipes
11. Open write end and call wait till read end open.
12. Create thread 2
12. Wait for n request
13. In thread 2 , open read end of one of the pipe.
14. Main should show 1 stat variable updated.

15. Again call Wait for n request.
16. It shall come out as one stat is Available.

17. Close all the pipes. Destroy pipes.

18. Create 3 N pipe and 2 UN pipes.
19. Register 2 NDA , 2 NSA , 2 Read end wait.
20. Create thread 3 make any request successful.


*/

LOCAL_C void test_MainThread()
{

		RPipe			aReader1,aWriter1;			// Used to pass to thread.
		RPipe			aReader2,aWriter2;			// Used to pass to thread.
		RPipe			aReader3,aWriter3;			// Used to pass to thread.
		RPipe			aReader4,aWriter4;			// Used to pass to thread.
		RPipe			aReader5,aWriter5;			// Used to pass to thread.

		TInt			ret,aSize;
		RThread			thread2;
		RThread			thread3;
		RThread			thread4;
		RThread			thread5;

		TRequestStatus	stat1;
		TRequestStatus	stat2;
		TRequestStatus	stat3;
		TRequestStatus	stat4;
		TRequestStatus	stat5;

		TRequestStatus	s;

		TRequestStatus	*ReqArray[] =
		{
			&stat1,&stat2,&stat3,&stat4,&stat5
		};
		const TBufC<100> 		cPipeName1(KPipe1Name);
		TBufC8<50> 				cTestData(KTestDataNum); 	// Test Data



		test.Printf(_L("PIPE TEST:Main Thread Entry\n"));

//Test	1:

		aSize = 10;
		// Create 5 Pipes.
		ret = RPipe::Create( aSize,	aReader1,aWriter1,EOwnerProcess, EOwnerProcess);
		test_KErrNone(ret);
		ret = RPipe::Create( aSize,	aReader2,aWriter2,EOwnerProcess, EOwnerProcess);
		test_KErrNone(ret);
		ret = RPipe::Create( aSize,	aReader3,aWriter3,EOwnerProcess, EOwnerProcess);
		test_KErrNone(ret);
		ret = RPipe::Create( aSize,	aReader4,aWriter4,EOwnerProcess, EOwnerProcess);
		test_KErrNone(ret);
		ret = RPipe::Create( aSize,	aReader5,aWriter5,EOwnerProcess, EOwnerProcess);
		test_KErrNone(ret);
		// Register Notification for Data Available for all 5 pipes.
		aReader1.NotifyDataAvailable(stat1);
		aReader2.NotifyDataAvailable(stat2);
		aReader3.NotifyDataAvailable(stat3);
		aReader4.NotifyDataAvailable(stat4);
		aReader5.NotifyDataAvailable(stat5);


		// Pass handles for Pipe# 3
		TData data1(&aReader3,&aWriter3,aSize);

		// Create thread for Writing data into pipe.
		// This will make status variable of respective pipe as AVAILABLE
		ret = thread3.Create(
								KThread3Name, 		// Thread name
								NotifyDataThread,			// Function to be called
								KDefaultStackSize,
								KHeapSize,
								KHeapSize,
								(TAny *)&data1		// Data object containing Pipe information.
							);
		test_KErrNone(ret);
		thread3.Logon(s);
		test_Equal(KRequestPending, s.Int());

		// Start the Thread
		thread3.Resume();

		// Wait till any of the request status is Avaialble
		User::WaitForNRequest(ReqArray,5);

		// As WaitForNRequest returned. This proves test pass.
		test.Printf(_L("PIPE TEST:Test 1: Pass\n"));

		// Cancel all pending requests for other tests.
		aReader1.CancelDataAvailable();
		aReader2.CancelDataAvailable();
		aReader3.CancelDataAvailable();
		aReader4.CancelDataAvailable();
		aReader5.CancelDataAvailable();

		// Close thread.
		User::WaitForRequest(s);
		CLOSE_AND_WAIT(thread3);


//Test	2:

		// Pipes created in Test 1.
		// Write data into all the pipes and Fill it.
		aWriter1.Write(cTestData,cTestData.Length());
		aWriter2.Write(cTestData,cTestData.Length());
		aWriter3.Write(cTestData,cTestData.Length());
		aWriter4.Write(cTestData,cTestData.Length());
		aWriter5.Write(cTestData,cTestData.Length());

		// Register notification for Space availability for all pipes.
			
		aWriter1.NotifySpaceAvailable(aSize,stat1);
		aWriter2.NotifySpaceAvailable(aSize,stat2);
		aWriter3.NotifySpaceAvailable(aSize,stat3);
		aWriter4.NotifySpaceAvailable(aSize,stat4);
		aWriter5.NotifySpaceAvailable(aSize,stat5);


		// Create data object for Pipe# 5.
		TData data2(&aReader5,&aWriter5,aSize);

		// Create thread which will make space available in Pipe.
		//
		ret = thread4.Create(
								KThread4Name, 		// Thread name
								NotifySpaceThread,			// Function to be called
								KDefaultStackSize,
								KHeapSize,
								KHeapSize,
								(TAny *)&data2		// Data object containing Pipe information.
							);
		test_KErrNone(ret);
		thread4.Logon(s);
		test_Equal(KRequestPending, s.Int());

		// Start the thread.
		thread4.Resume();

		// Wait till any of the status variable status change to Avaialble
		User::WaitForNRequest(ReqArray,5);

		test.Printf(_L("PIPE TEST:Test 2: Pass\n"));

		// Cancel all pending requests.
		aWriter1.CancelSpaceAvailable();
		aWriter2.CancelSpaceAvailable();
		aWriter3.CancelSpaceAvailable();
		aWriter4.CancelSpaceAvailable();
		aWriter5.CancelSpaceAvailable();

		// Close the thread.
		User::WaitForRequest(s);
		CLOSE_AND_WAIT(thread4);

//Test	3:
		// Flush all the Pipes.
		// This is needed for NotifyDataAvailable request.
		aReader1.Flush();
		aReader2.Flush();
		aReader3.Flush();
		aReader4.Flush();
		aReader5.Flush();

		// Register NotifyDataAvailable request for all the pipes.
		
		CancelFlag = 0;	// 0 = CanceldataAvailable()
		aReader1.NotifyDataAvailable(stat1);
		aReader2.NotifyDataAvailable(stat2);
		aReader3.NotifyDataAvailable(stat3);
		aReader4.NotifyDataAvailable(stat4);
		aReader5.NotifyDataAvailable(stat5);

		TData data3(&aReader2,&aWriter2,aSize);

		ret = thread5.Create(
								KThread5Name, 		// Thread name
								CancelNotifyThread,			// Function to be called
								KDefaultStackSize,
								KHeapSize,
								KHeapSize,
								(TAny *)&data3		// Data object containing Pipe information.
							);
		test_KErrNone(ret);
		thread5.Logon(s);
		test_Equal(KRequestPending, s.Int());
		thread5.Resume();

		User::WaitForNRequest(ReqArray,5);

		test.Printf(_L("PIPE TEST:Test 3: Pass\n"));
		aReader1.CancelDataAvailable();
		aReader2.CancelDataAvailable();
		aReader3.CancelDataAvailable();
		aReader4.CancelDataAvailable();
		aReader5.CancelDataAvailable();
		User::WaitForRequest(s);
		CLOSE_AND_WAIT(thread5);


//Test	4:
		aReader1.Close();
		aWriter1.Close();
		aReader2.Close();
		aWriter2.Close();
		aReader3.Close();
		aWriter3.Close();
		aReader4.Close();
		aWriter4.Close();
		aReader5.Close();
		aWriter5.Close();

		ret = RPipe::Define(KPipe1Name,aSize);
		test_KErrNone(ret);
		ret = RPipe::Define(KPipe2Name,aSize);
		test_KErrNone(ret);
		ret = RPipe::Define(KPipe3Name,aSize);
		test_KErrNone(ret);
		ret = RPipe::Define(KPipe4Name,aSize);
		test_KErrNone(ret);
		ret = RPipe::Define(KPipe5Name,aSize);
		test_KErrNone(ret);

		aWriter1.Open(KPipe1Name,RPipe::EOpenToWrite);
		aWriter2.Open(KPipe2Name,RPipe::EOpenToWrite);
		aWriter3.Open(KPipe3Name,RPipe::EOpenToWrite);
		aWriter4.Open(KPipe4Name,RPipe::EOpenToWrite);
		aWriter5.Open(KPipe5Name,RPipe::EOpenToWrite);

		aWriter1.Wait(KPipe1Name,stat1);
		aWriter2.Wait(KPipe2Name,stat2);
		aWriter3.Wait(KPipe3Name,stat3);
		aWriter4.Wait(KPipe4Name,stat4);
		aWriter5.Wait(KPipe5Name,stat5);

		const TBufC<100> 		cPipeName2(KPipe2Name);

		TData data4(&aReader2,&aWriter2,aSize);
		cPipeName = cPipeName2;

		ret = thread2.Create(
								KThread2Name, 		// Thread name
								WaitThread,			// Function to be called
								KDefaultStackSize,
								KHeapSize,
								KHeapSize,
								(TAny *)&data4		// Data object containing Pipe information.
							);
		test_KErrNone(ret);
		thread2.Logon(s);
		test_Equal(KRequestPending, s.Int());
		thread2.Resume();
		User::WaitForNRequest(ReqArray,5);
		test.Printf(_L("PIPE TEST:Test 4: Pass\n"));
		aWriter1.CancelWait();
		aWriter2.CancelWait();
		aWriter3.CancelWait();
		aWriter4.CancelWait();
		aWriter5.CancelWait();

		aReader1.Close();		aWriter1.Close();
		aReader2.Close();		aWriter2.Close();
		aReader3.Close();		aWriter3.Close();
		aReader4.Close();		aWriter4.Close();
		aReader5.Close();		aWriter5.Close();

		User::WaitForRequest(s);
		CLOSE_AND_WAIT(thread2);

//Test	5:

		ret =aWriter1.Open(KPipe1Name,RPipe::EOpenToWrite);
		test_KErrNone(ret);
		aReader1.Close();
		//ret =aWriter1.Wait(KPipe1Name,stat1);
		aWriter1.Wait(KPipe1Name,stat1);

		ret =aWriter2.Open(KPipe2Name,RPipe::EOpenToWrite);
		test_KErrNone(ret);
		ret =aReader2.Open(KPipe2Name,RPipe::EOpenToRead);
		test_KErrNone(ret);
		ret =aWriter2.Write(cTestData,cTestData.Length());
		//ret =aWriter2.NotifySpaceAvailable(aSize,stat2);
		aWriter2.NotifySpaceAvailable(aSize,stat2);

		ret = RPipe::Create( aSize,	aReader3,aWriter3,EOwnerProcess, EOwnerProcess);
		test_KErrNone(ret);
		aReader3.Flush();
		//ret =aReader3.NotifyDataAvailable(stat3);
		aReader3.NotifyDataAvailable(stat3);

		ret = RPipe::Create( aSize,	aReader4,aWriter4,EOwnerProcess, EOwnerProcess);
		test_KErrNone(ret);
		ret =aWriter4.Write(cTestData,cTestData.Length());
		//ret =aWriter4.NotifySpaceAvailable(aSize,stat4);
		aWriter4.NotifySpaceAvailable(aSize,stat4);

		ret = RPipe::Create( aSize,	aReader5,aWriter5,EOwnerProcess, EOwnerProcess);
		test_KErrNone(ret);
		aReader5.Flush();
		//ret =aReader5.NotifyDataAvailable(stat5);
		aReader5.NotifyDataAvailable(stat5);

		TData data5(&aReader3,&aWriter3,aSize);
		cPipeName = cPipeName2;

		RThread thread6;

		ret = thread6.Create(
								KThread3Name, 		// Thread name
								NotifyDataThread,			// Function to be called
								KDefaultStackSize,
								KHeapSize,
								KHeapSize,
								(TAny *)&data5		// Data object containing Pipe information.
							);
		test_KErrNone(ret);
		thread6.Logon(s);
		test_Equal(KRequestPending, s.Int());
		thread6.Resume();
		User::WaitForNRequest(ReqArray,5);
		test.Printf(_L("PIPE TEST:Test 5: Pass\n"));

		User::WaitForRequest(s);
		CLOSE_AND_WAIT(thread6);
//Test	6:

		TData data6(&aReader2,&aWriter2,aSize);
		cPipeName = cPipeName2;

		RThread thread7;

		ret = thread7.Create(
								KThread3Name, 		// Thread name
								NotifySpaceThread,			// Function to be called
								KDefaultStackSize,
								KHeapSize,
								KHeapSize,
								(TAny *)&data6		// Data object containing Pipe information.
							);
		test_KErrNone(ret);
		thread7.Logon(s);
		test_Equal(KRequestPending, s.Int());
		thread7.Resume();

		User::WaitForNRequest(ReqArray,5);
		test.Printf(_L("PIPE TEST:Test 6: Pass\n"));


		User::WaitForRequest(s);
		CLOSE_AND_WAIT(thread7);

//Test	7:
		TData data7(&aReader1,&aWriter1,aSize);
		cPipeName = cPipeName1;

		RThread thread8;

		ret = thread8.Create(
								KThread2Name, 		// Thread name
								WaitThread,			// Function to be called
								KDefaultStackSize,
								KHeapSize,
								KHeapSize,
								(TAny *)&data7		// Data object containing Pipe information.
							);
		test_KErrNone(ret);
		thread8.Logon(s);
		test_Equal(KRequestPending, s.Int());
		thread8.Resume();

		User::WaitForNRequest(ReqArray,5);
		test.Printf(_L("PIPE TEST:Test 7: Pass\n"));


		User::WaitForRequest(s);
//		CLOSE_AND_WAIT(thread8);	DOESN'T WORK SINCE PIPE DRIVER KEEPS THE THREAD OPEN
		thread8.Close();

//Test	8:
		TData data8(&aReader4,&aWriter4,aSize);

		RThread thread9;
		
		CancelFlag = 1;	// 1 = CancelSpaceAvailable()

		ret = thread9.Create(
								KThread4Name, 		// Thread name
								CancelNotifyThread,			// Function to be called
								KDefaultStackSize,
								KHeapSize,
								KHeapSize,
								(TAny *)&data8		// Data object containing Pipe information.
							);
		test_KErrNone(ret);
		thread9.Logon(s);
		test_Equal(KRequestPending, s.Int());
		thread9.Resume();

		User::WaitForNRequest(ReqArray,5);
		test.Printf(_L("PIPE TEST:Test 8: Pass\n"));

		User::WaitForRequest(s);
		CLOSE_AND_WAIT(thread9);

//Test	9:
		TData data9(&aReader5,&aWriter5,aSize);

		RThread thread10;

		CancelFlag = 0;	// 0 = CancelDataAvailable()

		ret = thread10.Create(
								KThread5Name, 		// Thread name
								CancelNotifyThread,			// Function to be called
								KDefaultStackSize,
								KHeapSize,
								KHeapSize,
								(TAny *)&data9		// Data object containing Pipe information.
							);
		test_KErrNone(ret);
		thread10.Logon(s);
		test_Equal(KRequestPending, s.Int());
		thread10.Resume();

		
		User::WaitForNRequest(ReqArray,5);
		test.Printf(_L("PIPE TEST:Test 9: Pass\n"));

		User::WaitForRequest(s);
		CLOSE_AND_WAIT(thread10);


		aReader1.Close();		aWriter1.Close();
		aReader2.Close();		aWriter2.Close();
		aReader3.Close();		aWriter3.Close();
		aReader4.Close();		aWriter4.Close();
		aReader5.Close();		aWriter5.Close();
		ret = RPipe::Destroy(KPipe1Name);
		test_KErrNone(ret);
		ret = RPipe::Destroy(KPipe2Name);
		test_KErrNone(ret);
		ret = RPipe::Destroy(KPipe3Name);
		test_KErrNone(ret);
		ret = RPipe::Destroy(KPipe4Name);
		test_KErrNone(ret);
		ret = RPipe::Destroy(KPipe5Name);
		test_KErrNone(ret);
		
		
		test.Printf(_L("PIPE TEST:Main Thread Exit\n"));
		return;



}

////////////////////////////////////////////////////
//// RunTests:
////
////
////////////////////////////////////////////////////
LOCAL_C void RunTests(void)
{

	test.Start(_L("PIPE TEST: Testing WaitForNRequest"));

	test_MainThread();

	test.Printf(_L("PIPE TEST: Ending test.\n"));

	test.End();
	test.Close();
	return;
}


////////////////////////////////////////////////////
//// E32Main : Main entry point to test.
////
////
////////////////////////////////////////////////////


GLDEF_C TInt E32Main()

{
	TInt		ret = 0;

	ret = RPipe::Init();
	
	if (ret != KErrNone && ret != KErrAlreadyExists)
	{
	test.Printf(_L(" t_pipe4.exe PIPE TEST: Error loading driver %d\n"),ret);
	test.Printf(_L(" Exiting t_pipe4.exe\n"));

	return KErrNone;

	}
	RunTests();

	TName pddName1(RPipe::Name());
	
	ret= User::FreeLogicalDevice(pddName1);
	
	return KErrNone;
	
}