kerneltest/e32test/dma/dmasim.cpp
branchRCL_3
changeset 43 c1f20ce4abcf
parent 22 2f92ad2dc5db
child 44 3e88ff8f41d5
--- a/kerneltest/e32test/dma/dmasim.cpp	Thu Aug 19 11:14:22 2010 +0300
+++ b/kerneltest/e32test/dma/dmasim.cpp	Tue Aug 31 16:34:26 2010 +0300
@@ -1,4 +1,4 @@
-// Copyright (c) 2002-2010 Nokia Corporation and/or its subsidiary(-ies).
+// 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"
@@ -355,37 +355,69 @@
 public:
 	static void StartEmulation();
 	static void StopEmulation();
+	static TBool InISR();
+	static void Synchronize();
 private:
 	enum { KPeriod = 1 }; // in ms
+	enum { EDmaSimIdle=0u, EDmaSimStarted=1u, EDmaSimInISR=2u, EDmaSimStopping=0x80000000u };
 	static void TickCB(TAny* aThis);
 	static NTimer Timer;
+	static volatile TInt StartStop;
 	};
 
 NTimer DmacSim::Timer;
+volatile TInt DmacSim::StartStop;
 
 void DmacSim::StartEmulation()
 	{
+	__DMA_ASSERTA(StartStop==EDmaSimIdle);
 	new (&Timer) NTimer(&TickCB, 0);
+	__e32_atomic_store_ord32(&StartStop, EDmaSimStarted);
 	__DMA_ASSERTA(Timer.OneShot(KPeriod, EFalse) == KErrNone);
 	}
 
 void DmacSim::StopEmulation()
 	{
-	// Ensure that timer really is cancelled.
-	TBool cancelled = EFalse;
-	do
-		{
-		cancelled = Timer.Cancel();
-		}
-	while(!cancelled);
+	TInt orig = __e32_atomic_tas_ord32(&StartStop, (TInt)EDmaSimStarted, (TInt)EDmaSimStopping, 0);
+	if (orig == EDmaSimIdle)
+		return;		// wasn't running
+	// loop until we succeed in cancelling the timer or the timer callback
+	// notices that we are shutting down
+	while (!Timer.Cancel() && __e32_atomic_load_acq32(&StartStop)!=EDmaSimIdle)
+		{}
+	__e32_atomic_store_ord32(&StartStop, EDmaSimIdle);
 	}
 
 void DmacSim::TickCB(TAny*)
 	{
-	DmacSb::DoTransfer();
-	DmacDb::DoTransfer();
-	DmacSg::DoTransfer();
-	__DMA_ASSERTA(Timer.Again(KPeriod) == KErrNone);
+	TInt orig = (TInt)__e32_atomic_ior_acq32(&StartStop, EDmaSimInISR);
+	if (orig >= 0)
+		{
+		DmacSb::DoTransfer();
+		DmacDb::DoTransfer();
+		DmacSg::DoTransfer();
+		}
+	orig = (TInt)__e32_atomic_and_rel32(&StartStop, (TUint32)~EDmaSimInISR);
+	if (orig < 0)
+		{
+		__e32_atomic_store_rel32(&StartStop, EDmaSimIdle);
+		return;
+		}
+	TInt r = Timer.Again(KPeriod);
+	if (r == KErrArgument)
+		r = Timer.OneShot(KPeriod);
+	__DMA_ASSERTA(r == KErrNone);
+	}
+
+TBool DmacSim::InISR()
+	{
+	return __e32_atomic_load_acq32(&StartStop) & EDmaSimInISR;
+	}
+
+void DmacSim::Synchronize()
+	{
+	while (InISR())
+		{}
 	}
 
 //////////////////////////////////////////////////////////////////////////////
@@ -442,6 +474,7 @@
 void DSimSbController::StopTransfer(const TDmaChannel& aChannel)
 	{
 	__e32_atomic_and_ord32(&DmacSb::ControlStatus[aChannel.PslId()], (TUint32)~DmacSb::ECsRun);
+	DmacSim::Synchronize();
 	}
 
 
@@ -542,6 +575,7 @@
 void DSimDbController::StopTransfer(const TDmaChannel& aChannel)
 	{
 	__e32_atomic_and_ord32(&DmacDb::ControlStatus[aChannel.PslId()], (TUint32)~(DmacDb::ECsRun|DmacDb::ECsPrg));
+	DmacSim::Synchronize();
 	}
 
 
@@ -672,6 +706,7 @@
 void DSimSgController::StopTransfer(const TDmaChannel& aChannel)
 	{
 	__e32_atomic_and_ord32(&DmacSg::ChannelControl[aChannel.PslId()], (TUint32)~DmacSg::EChannelBitRun);
+	DmacSim::Synchronize();
 	}