kerneltest/e32test/system/t_atomic_common.cpp
author Adrian Taylor <adrian@macrobug.com>
Tue, 10 Nov 2009 20:10:34 +0000
changeset 1 cb3e90eb7d89
parent 0 a41df078684a
child 43 c1f20ce4abcf
permissions -rw-r--r--
Improving comments on panics generated by CActive::SetActive. Patch slightly altered based on comments by John Imhofe.

// Copyright (c) 2008-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\system\t_atomic_common.cpp
// 
//

#ifdef __KERNEL_MODE__
#include <kernel/kernel.h>
#else
#define	__E32TEST_EXTENSION__

#include <e32test.h>

extern RTest test;

#define __INCLUDE_FUNC_NAMES__
#endif

#define __INCLUDE_ATOMIC_FUNCTIONS__
#define __INCLUDE_CONTROL_FUNCTIONS__
#define __INCLUDE_FUNCTION_ATTRIBUTES__

#include "t_atomic.h"

#define DEBUGPRINTVAR(x)	\
	{	\
	const TUint8* p = (const TUint8*)&(x);	\
	DEBUGPRINT("Line %d: " #x "=%02x %02x %02x %02x  %02x %02x %02x %02x", __LINE__, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);	\
	}

extern "C" {

// Simulated versions of atomic functions without the atomicity
#define __LOAD(T)	return *(T*)a
#define	__STORE(T)	*(T*)a=v; return v
#define	__SWP(T)	T oldv=*(T*)a; *(T*)a=v; return oldv
#define __CAS(T)	if (*(T*)a==*q) {*(T*)a=v; return 1;} *q=*(T*)a; return 0
#define __ADD(T)	T oldv=*(T*)a; *(T*)a=(T)(oldv+v); return oldv
#define __AND(T)	T oldv=*(T*)a; *(T*)a=(T)(oldv&v); return oldv
#define __IOR(T)	T oldv=*(T*)a; *(T*)a=(T)(oldv|v); return oldv
#define __XOR(T)	T oldv=*(T*)a; *(T*)a=(T)(oldv^v); return oldv
#define __AXO(T)	T oldv=*(T*)a; *(T*)a=(T)((oldv&u)^v); return oldv
#define __TA(T)		T oldv=*(T*)a; *(T*)a=(T)(oldv+((oldv>=t)?u:v)); return oldv

TUint8	__nonatomic_load8(const volatile TAny* a)
	{
	__LOAD(TUint8);
	}

TUint8	__nonatomic_store8(volatile TAny* a, TUint8 v)
	{
	__STORE(TUint8);
	}

TUint8	__nonatomic_swp8(volatile TAny* a, TUint8 v)
	{
	__SWP(TUint8);
	}

TBool	__nonatomic_cas8(volatile TAny* a, TUint8* q, TUint8 v)
	{
	__CAS(TUint8);
	}

TUint8	__nonatomic_add8(volatile TAny* a, TUint8 v)
	{
	__ADD(TUint8);
	}

TUint8	__nonatomic_and8(volatile TAny* a, TUint8 v)
	{
	__AND(TUint8);
	}

TUint8	__nonatomic_ior8(volatile TAny* a, TUint8 v)
	{
	__IOR(TUint8);
	}

TUint8	__nonatomic_xor8(volatile TAny* a, TUint8 v)
	{
	__XOR(TUint8);
	}

TUint8	__nonatomic_axo8(volatile TAny* a, TUint8 u, TUint8 v)
	{
	__AXO(TUint8);
	}

TUint8	__nonatomic_tau8(volatile TAny* a, TUint8 t, TUint8 u, TUint8 v)
	{
	__TA(TUint8);
	}

TInt8	__nonatomic_tas8(volatile TAny* a, TInt8 t, TInt8 u, TInt8 v)
	{
	__TA(TInt8);
	}


TUint16	__nonatomic_load16(const volatile TAny* a)
	{
	__LOAD(TUint16);
	}

TUint16	__nonatomic_store16(volatile TAny* a, TUint16 v)
	{
	__STORE(TUint16);
	}

TUint16	__nonatomic_swp16(volatile TAny* a, TUint16 v)
	{
	__SWP(TUint16);
	}

TBool	__nonatomic_cas16(volatile TAny* a, TUint16* q, TUint16 v)
	{
	__CAS(TUint16);
	}

TUint16	__nonatomic_add16(volatile TAny* a, TUint16 v)
	{
	__ADD(TUint16);
	}

TUint16	__nonatomic_and16(volatile TAny* a, TUint16 v)
	{
	__AND(TUint16);
	}

TUint16	__nonatomic_ior16(volatile TAny* a, TUint16 v)
	{
	__IOR(TUint16);
	}

TUint16	__nonatomic_xor16(volatile TAny* a, TUint16 v)
	{
	__XOR(TUint16);
	}

TUint16	__nonatomic_axo16(volatile TAny* a, TUint16 u, TUint16 v)
	{
	__AXO(TUint16);
	}

TUint16	__nonatomic_tau16(volatile TAny* a, TUint16 t, TUint16 u, TUint16 v)
	{
	__TA(TUint16);
	}

TInt16	__nonatomic_tas16(volatile TAny* a, TInt16 t, TInt16 u, TInt16 v)
	{
	__TA(TInt16);
	}


TUint32	__nonatomic_load32(const volatile TAny* a)
	{
	__LOAD(TUint32);
	}

TUint32	__nonatomic_store32(volatile TAny* a, TUint32 v)
	{
	__STORE(TUint32);
	}

TUint32	__nonatomic_swp32(volatile TAny* a, TUint32 v)
	{
	__SWP(TUint32);
	}

TBool	__nonatomic_cas32(volatile TAny* a, TUint32* q, TUint32 v)
	{
	__CAS(TUint32);
	}

TUint32	__nonatomic_add32(volatile TAny* a, TUint32 v)
	{
	__ADD(TUint32);
	}

TUint32	__nonatomic_and32(volatile TAny* a, TUint32 v)
	{
	__AND(TUint32);
	}

TUint32	__nonatomic_ior32(volatile TAny* a, TUint32 v)
	{
	__IOR(TUint32);
	}

TUint32	__nonatomic_xor32(volatile TAny* a, TUint32 v)
	{
	__XOR(TUint32);
	}

TUint32	__nonatomic_axo32(volatile TAny* a, TUint32 u, TUint32 v)
	{
	__AXO(TUint32);
	}

TUint32	__nonatomic_tau32(volatile TAny* a, TUint32 t, TUint32 u, TUint32 v)
	{
	__TA(TUint32);
	}

TInt32	__nonatomic_tas32(volatile TAny* a, TInt32 t, TInt32 u, TInt32 v)
	{
	__TA(TInt32);
	}


TUint64	__nonatomic_load64(const volatile TAny* a)
	{
	__LOAD(TUint64);
	}

TUint64	__nonatomic_store64(volatile TAny* a, TUint64 v)
	{
	__STORE(TUint64);
	}

TUint64	__nonatomic_swp64(volatile TAny* a, TUint64 v)
	{
	__SWP(TUint64);
	}

TBool	__nonatomic_cas64(volatile TAny* a, TUint64* q, TUint64 v)
	{
	__CAS(TUint64);
	}

TUint64	__nonatomic_add64(volatile TAny* a, TUint64 v)
	{
	__ADD(TUint64);
	}

TUint64	__nonatomic_and64(volatile TAny* a, TUint64 v)
	{
	__AND(TUint64);
	}

TUint64	__nonatomic_ior64(volatile TAny* a, TUint64 v)
	{
	__IOR(TUint64);
	}

TUint64	__nonatomic_xor64(volatile TAny* a, TUint64 v)
	{
	__XOR(TUint64);
	}

TUint64	__nonatomic_axo64(volatile TAny* a, TUint64 u, TUint64 v)
	{
	__AXO(TUint64);
	}

TUint64	__nonatomic_tau64(volatile TAny* a, TUint64 t, TUint64 u, TUint64 v)
	{
	__TA(TUint64);
	}

TInt64	__nonatomic_tas64(volatile TAny* a, TInt64 t, TInt64 u, TInt64 v)
	{
	__TA(TInt64);
	}

} // extern "C"


#define	DEBUGPRINTxyrc()	\
		DEBUGPRINTVAR(x);	\
		DEBUGPRINTVAR(y);	\
		DEBUGPRINTVAR(r);	\
		DEBUGPRINTVAR(c)

template<class T> TInt DoLoadTest(TInt aIndex, TAny* aPtr, T aInitialValue)
	{
#ifdef __EXTRA_DEBUG__
	DEBUGPRINT("DoLoadTest %d %08x", aIndex, aPtr);
#endif
	typename TLoadFn<T>::F atomic = (typename TLoadFn<T>::F)AtomicFuncPtr[aIndex];
	typename TLoadFn<T>::F control = (typename TLoadFn<T>::F)ControlFuncPtr[aIndex];
	T& x = *(T*)aPtr;
	x = aInitialValue;
	T y = aInitialValue;
	T r = atomic(&x);
	T c = control(&y);
	if (r!=c || x!=y)
		{
		DEBUGPRINTxyrc();
		return __LINE__;
		}
	return 0;
	}

template<class T> TInt DoRmw1Test(TInt aIndex, TAny* aPtr, T aInitialValue, T a1)
	{
#ifdef __EXTRA_DEBUG__
	DEBUGPRINT("DoRmw1Test %d %08x", aIndex, aPtr);
#endif
	typename TRmw1Fn<T>::F atomic = (typename TRmw1Fn<T>::F)AtomicFuncPtr[aIndex];
	typename TRmw1Fn<T>::F control = (typename TRmw1Fn<T>::F)ControlFuncPtr[aIndex];
	T& x = *(T*)aPtr;
	x = aInitialValue;
	T y = aInitialValue;
	T r = atomic(&x,a1);
	T c = control(&y,a1);
	if (r!=c || x!=y)
		{
		DEBUGPRINTxyrc();
		return __LINE__;
		}
	return 0;
	}

template<class T> TInt DoRmw2Test(TInt aIndex, TAny* aPtr, T aInitialValue, T a1, T a2)
	{
#ifdef __EXTRA_DEBUG__
	DEBUGPRINT("DoRmw2Test %d %08x", aIndex, aPtr);
#endif
	typename TRmw2Fn<T>::F atomic = (typename TRmw2Fn<T>::F)AtomicFuncPtr[aIndex];
	typename TRmw2Fn<T>::F control = (typename TRmw2Fn<T>::F)ControlFuncPtr[aIndex];
	T& x = *(T*)aPtr;
	x = aInitialValue;
	T y = aInitialValue;
	T r = atomic(&x,a1,a2);
	T c = control(&y,a1,a2);
	if (r!=c || x!=y)
		{
		DEBUGPRINTxyrc();
		return __LINE__;
		}
	return 0;
	}

template<class T> TInt DoRmw3Test(TInt aIndex, TAny* aPtr, T aInitialValue, T a1, T a2, T a3)
	{
#ifdef __EXTRA_DEBUG__
	DEBUGPRINT("DoRmw3Test %d %08x", aIndex, aPtr);
#endif
	typename TRmw3Fn<T>::F atomic = (typename TRmw3Fn<T>::F)AtomicFuncPtr[aIndex];
	typename TRmw3Fn<T>::F control = (typename TRmw3Fn<T>::F)ControlFuncPtr[aIndex];
	T& x = *(T*)aPtr;
	x = aInitialValue;
	T y = aInitialValue;
	T r = atomic(&x,a1,a2,a3);
	T c = control(&y,a1,a2,a3);
	if (r!=c || x!=y)
		{
		DEBUGPRINTxyrc();
		return __LINE__;
		}
	return 0;
	}

template<class T> TInt DoCasTest(TInt aIndex, TAny* aPtr, T aInitialValue, T aExpectedValue, T aFinalValue)
	{
#ifdef __EXTRA_DEBUG__
	DEBUGPRINT("DoCasTest %d %08x", aIndex, aPtr);
#endif
	typename TCasFn<T>::F atomic = (typename TCasFn<T>::F)AtomicFuncPtr[aIndex];
	typename TCasFn<T>::F control = (typename TCasFn<T>::F)ControlFuncPtr[aIndex];
	T& x = *(T*)aPtr;
	x = aInitialValue;
	T ex = aExpectedValue;
	T y = aInitialValue;
	T ey = aExpectedValue;
	TBool r = atomic(&x,&ex,aFinalValue);
	TBool c = control(&y,&ey,aFinalValue);
	TInt line = 0;
	if (r && !c)
		line = __LINE__;
	else if (!r && c)
		line = __LINE__;
	else if (x!=y)
		line = __LINE__;
	else if (ex!=ey)
		line = __LINE__;
	else if (r && x!=aFinalValue)
		line = __LINE__;
	else if (!r && ex!=aInitialValue)
		line = __LINE__;
	if (line)
		{
		DEBUGPRINT("r=%d",r);
		DEBUGPRINTVAR(x);
		DEBUGPRINTVAR(ex);
		DEBUGPRINT("c=%d",c);
		DEBUGPRINTVAR(y);
		DEBUGPRINTVAR(ey);
		}
	return line;
	}



TEnclosed::TEnclosed(TInt aSize)
	{
	iOffset = -1;
	iSize = aSize;
	iData = (TUint64*)((T_UintPtr(i_Data) + 7) &~ 7);	// align up to next 8 byte boundary
	iBackup = iData + 8;
	}

TAny* TEnclosed::Ptr()
	{
	return ((TUint8*)iData + iOffset);
	}

TInt TEnclosed::Next()
	{
	const TInt KLimit[8] = {8, 16, 0, 32, 0, 0, 0, 32};
	if (iOffset<0)
		iOffset = 0;
	else
		{
		TInt r = Verify();
		if (r!=0)
			return r;
		iOffset += iSize;
		}
	if (iOffset >= KLimit[iSize-1])
		return KErrEof;
	Init();
	return KErrNone;
	}

void TEnclosed::Init()
	{
	TUint32 x = iOffset+1;
	x |= (x<<8);
	x |= (x<<16);
	TUint32* d = (TUint32*)iData;
	TUint32* b = (TUint32*)iBackup;
	TInt i;
	for (i=0; i<16; ++i)
		{
		*d++ = x;
		*b++ = x;
		x = 69069*x + 41;
		}
	}

TInt TEnclosed::Verify()
	{
	TUint8* d = (TUint8*)iData;
	const TUint8* b = (const TUint8*)iBackup;
	TInt i;
	for (i=0; i<iSize; ++i)
		d[iOffset+i] = b[iOffset+i];
	if (memcompare(b,64,d,64))
		{
		DEBUGPRINT("FAIL! iOffset=%02x, sizeof(T)=%1d", iOffset, iSize);
		for (i=0; i<64; ++i)
			{
			if (d[i]!=b[i])
				{
				DEBUGPRINT("d[%02x]=%02x b[%02x]=%02x", i, d[i], i, b[i]);
				}
			}
		return __LINE__;
		}
	return 0;
	}


TInt TDGBase::Execute()
	{
	PFV af0 = AtomicFuncPtr[iIndex];
	PFV cf0 = ControlFuncPtr[iIndex];
	if (!af0 || !cf0)
		return __LINE__;
	TUint attr = FuncAttr[iIndex];
	TInt type = ATTR_TO_TYPE(attr);
	TInt size = ATTR_TO_SIZE(attr);
	TInt func = ATTR_TO_FUNC(attr);
	if (type==EFuncTypeInvalid)
		return __LINE__;
#ifdef __EXTRA_DEBUG__
	TInt ord = ATTR_TO_ORD(attr);
	DEBUGPRINT("A=%08x T=%d O=%d S=%d F=%d", attr, type, ord, size, func);
#endif
	TEnclosed enc(size);
	TInt res = 0;
	while ( (res = enc.Next()) == KErrNone )
		{
#ifdef __EXTRA_DEBUG__
		DEBUGPRINT("Offset %02x", enc.Offset());
#endif
		TAny* ptr = enc.Ptr();
		switch (type)
			{
			case EFuncTypeLoad:
				{
				switch (size)
					{
					case 1:	res = DoLoadTest<TUint8>(iIndex, ptr, (TUint8)i0); break;
					case 2:	res = DoLoadTest<TUint16>(iIndex, ptr, (TUint16)i0); break;
					case 4:	res = DoLoadTest<TUint32>(iIndex, ptr, (TUint32)i0); break;
					case 8:	res = DoLoadTest<TUint64>(iIndex, ptr, i0); break;
					default: res = __LINE__; break;
					}
				break;
				}
			case EFuncTypeRmw1:
				{
				switch (size)
					{
					case 1:	res = DoRmw1Test<TUint8>(iIndex, ptr, (TUint8)i0, (TUint8)i1); break;
					case 2:	res = DoRmw1Test<TUint16>(iIndex, ptr, (TUint16)i0, (TUint16)i1); break;
					case 4:	res = DoRmw1Test<TUint32>(iIndex, ptr, (TUint32)i0, (TUint32)i1); break;
					case 8:	res = DoRmw1Test<TUint64>(iIndex, ptr, i0, i1); break;
					default: res = __LINE__; break;
					}
				break;
				}
			case EFuncTypeRmw2:
				{
				switch (size)
					{
					case 1:	res = DoRmw2Test<TUint8>(iIndex, ptr, (TUint8)i0, (TUint8)i1, (TUint8)i2); break;
					case 2:	res = DoRmw2Test<TUint16>(iIndex, ptr, (TUint16)i0, (TUint16)i1, (TUint16)i2); break;
					case 4:	res = DoRmw2Test<TUint32>(iIndex, ptr, (TUint32)i0, (TUint32)i1, (TUint32)i2); break;
					case 8:	res = DoRmw2Test<TUint64>(iIndex, ptr, i0, i1, i2); break;
					default: res = __LINE__; break;
					}
				break;
				}
			case EFuncTypeRmw3:
				{
				if (func==EAtomicFuncTAU)
					{
					switch (size)
						{
						case 1:	res = DoRmw3Test<TUint8>(iIndex, ptr, (TUint8)i0, (TUint8)i1, (TUint8)i2, (TUint8)i3); break;
						case 2:	res = DoRmw3Test<TUint16>(iIndex, ptr, (TUint16)i0, (TUint16)i1, (TUint16)i2, (TUint16)i3); break;
						case 4:	res = DoRmw3Test<TUint32>(iIndex, ptr, (TUint32)i0, (TUint32)i1, (TUint32)i2, (TUint32)i3); break;
						case 8:	res = DoRmw3Test<TUint64>(iIndex, ptr, i0, i1, i2, i3); break;
						default: res = __LINE__; break;
						}
					}
				else if (func==EAtomicFuncTAS)
					{
					switch (size)
						{
						case 1:	res = DoRmw3Test<TInt8>(iIndex, ptr, (TInt8)i0, (TInt8)i1, (TInt8)i2, (TInt8)i3); break;
						case 2:	res = DoRmw3Test<TInt16>(iIndex, ptr, (TInt16)i0, (TInt16)i1, (TInt16)i2, (TInt16)i3); break;
						case 4:	res = DoRmw3Test<TInt32>(iIndex, ptr, (TInt32)i0, (TInt32)i1, (TInt32)i2, (TInt32)i3); break;
						case 8:	res = DoRmw3Test<TInt64>(iIndex, ptr, i0, i1, i2, i3); break;
						default: res = __LINE__; break;
						}
					}
				else
					res = __LINE__;
				break;
				}
			case EFuncTypeCas:
				{
				switch (size)
					{
					case 1:	res = DoCasTest<TUint8>(iIndex, ptr, (TUint8)i0, (TUint8)i1, (TUint8)i2); break;
					case 2:	res = DoCasTest<TUint16>(iIndex, ptr, (TUint16)i0, (TUint16)i1, (TUint16)i2); break;
					case 4:	res = DoCasTest<TUint32>(iIndex, ptr, (TUint32)i0, (TUint32)i1, (TUint32)i2); break;
					case 8:	res = DoCasTest<TUint64>(iIndex, ptr, i0, i1, i2); break;
					default: res = __LINE__; break;
					}
				break;
				}
			default:
				res = __LINE__;
				break;
			}
		if (res)
			return res;
		}
	if (res == KErrEof)
		res = 0;
	return res;
	}

#ifndef __KERNEL_MODE__
void TDGBase::Dump(const char* aTitle)
	{
	TPtrC8 fname8((const TText8*)FuncName[iIndex]);
	TBuf<64> fname;
	fname.Copy(fname8);
	DEBUGPRINT(aTitle);
	DEBUGPRINT("iIndex=%d (%S)", iIndex, &fname);
	DEBUGPRINT("i0 = %08x %08x", I64HIGH(i0), I64LOW(i0));
	DEBUGPRINT("i1 = %08x %08x", I64HIGH(i1), I64LOW(i1));
	DEBUGPRINT("i2 = %08x %08x", I64HIGH(i2), I64LOW(i2));
	DEBUGPRINT("i3 = %08x %08x", I64HIGH(i3), I64LOW(i3));
	}
#endif

template<class T> TInt DoSwap(TAny* aPtr, TPerThread* aT, TAtomicAction& aA, T*)
	{
	typename TRmw1Fn<T>::F atomic = (typename TRmw1Fn<T>::F)AtomicFuncPtr[aA.iIndex];
	T newv = (T)aA.i0;
	T orig = atomic(aPtr, newv);
	T xr = (T)(newv ^ orig);
	aT->iXor ^= xr;
	T diff = (T)(newv - orig);
	aT->iDiff += diff;
	return 0;
	}

template<class T> TInt DoAdd(TAny* aPtr, TPerThread* aT, TAtomicAction& aA, T*)
	{
	typename TRmw1Fn<T>::F atomic = (typename TRmw1Fn<T>::F)AtomicFuncPtr[aA.iIndex];
	T arg = (T)aA.i0;
	T orig = atomic(aPtr, arg);
	T xr = (T)((arg+orig) ^ orig);
	aT->iXor ^= xr;
	aT->iDiff += arg;
	return 0;
	}

template<class T> TInt DoXor(TAny* aPtr, TPerThread* aT, TAtomicAction& aA, T*)
	{
	typename TRmw1Fn<T>::F atomic = (typename TRmw1Fn<T>::F)AtomicFuncPtr[aA.iIndex];
	T arg = (T)aA.i0;
	T orig = atomic(aPtr, arg);
	T diff = (T)((arg^orig) - orig);
	aT->iDiff += diff;
	aT->iXor ^= arg;
	return 0;
	}

template<class T> TInt DoAndOr(TAny* aPtr, TPerThread* aT, TAtomicAction& aA, T*)
	{
	typename TRmw1Fn<T>::F atomic_and = (typename TRmw1Fn<T>::F)AtomicFuncPtr[aA.iIndex];
	typename TRmw1Fn<T>::F atomic_or = (typename TRmw1Fn<T>::F)AtomicFuncPtr[aA.iIndex+4];
	T aarg = (T)aA.i0;
	T oarg = (T)aA.i1;
	T aorig = atomic_and(aPtr, aarg);
	T oorig = atomic_or(aPtr, oarg);
	T adiff = (T)((aorig & aarg) - aorig);
	T odiff = (T)((oorig | oarg) - oorig);
	aT->iDiff += adiff + odiff;
	T axor = (T)((aorig & aarg) ^ aorig);
	T oxor = (T)((oorig | oarg) ^ oorig);
	aT->iXor ^= axor ^ oxor;
	return 0;
	}

template<class T> TInt DoAxo(TAny* aPtr, TPerThread* aT, TAtomicAction& aA, T*)
	{
	typename TRmw2Fn<T>::F atomic = (typename TRmw2Fn<T>::F)AtomicFuncPtr[aA.iIndex];
	T aarg = (T)aA.i0;
	T xarg = (T)aA.i1;
	T orig = atomic(aPtr, aarg, xarg);
	T newv = (T)((orig & aarg) ^ xarg);
	aT->iDiff += (newv - orig);
	aT->iXor ^= (newv ^ orig);
	return 0;
	}

template<class T> TInt DoThAdd(TAny* aPtr, TPerThread* aT, TAtomicAction& aA, T*)
	{
	typename TRmw3Fn<T>::F atomic = (typename TRmw3Fn<T>::F)AtomicFuncPtr[aA.iIndex];
	T thr = (T)aA.i0;
	T arg1 = (T)aA.i1;
	T arg2 = (T)aA.i2;
	T orig = atomic(aPtr, thr, arg1, arg2);
	T newv = (T)((orig >= thr) ? (orig + arg1) : (orig + arg2));
	aT->iDiff += (orig >= thr) ? arg1 : arg2;
	aT->iXor ^= (newv ^ orig);
	return 0;
	}

template<class T> TInt DoCas(TAny* aPtr, TPerThread* aT, TAtomicAction& aA, T*)
	{
	typename TCasFn<T>::F atomic = (typename TCasFn<T>::F)AtomicFuncPtr[aA.iIndex];
	T orig = *(const volatile T*)aPtr;
	T newv;
	TBool done = FALSE;
	TUint32 fails = 0xffffffffu;
	do	{
		++fails;
		newv = Transform<T>::F(orig);
		done = atomic(aPtr, &orig, newv);
		} while(!done);
	aT->iFailCount += fails;
	++aT->iDiff;
	aT->iXor ^= (newv ^ orig);
	return 0;
	}

volatile TUint Dummy;
extern "C" TInt DoAtomicAction(TAny* aPtr, TPerThread* aT, TAtomicAction& aA)
	{
	TUint x = TUint(aT)*0x9E3779B9u;
	x = (x>>8)&15;
	while(x--)
		++Dummy;
	TInt r = KErrNotSupported;
	TUint attr = FuncAttr[aA.iIndex];
	TUint func = ATTR_TO_FUNC(attr);
	TUint size = ATTR_TO_SIZE(attr);
	switch (size)
		{
		case 1:
			{
			TUint8 xx;
			TUint8* dummy = &xx;
			TInt8 yy;
			TInt8* sdummy = &yy;
			switch (func)
				{
				case EAtomicFuncSWP:	r=DoSwap<TUint8>(aPtr, aT, aA, dummy); break;
				case EAtomicFuncADD:	r=DoAdd<TUint8>(aPtr, aT, aA, dummy); break;
				case EAtomicFuncAND:	r=DoAndOr<TUint8>(aPtr, aT, aA, dummy); break;
				case EAtomicFuncXOR:	r=DoXor<TUint8>(aPtr, aT, aA, dummy); break;
				case EAtomicFuncAXO:	r=DoAxo<TUint8>(aPtr, aT, aA, dummy); break;
				case EAtomicFuncTAU:	r=DoThAdd<TUint8>(aPtr, aT, aA, dummy); break;
				case EAtomicFuncTAS:	r=DoThAdd<TInt8>(aPtr, aT, aA, sdummy); break;
				case EAtomicFuncCAS:	r=DoCas<TUint8>(aPtr, aT, aA, dummy); break;
				default: break;
				}
			break;
			}
		case 2:
			{
			TUint16 xx;
			TUint16* dummy = &xx;
			TInt16 yy;
			TInt16* sdummy = &yy;
			switch (func)
				{
				case EAtomicFuncSWP:	r=DoSwap<TUint16>(aPtr, aT, aA, dummy); break;
				case EAtomicFuncADD:	r=DoAdd<TUint16>(aPtr, aT, aA, dummy); break;
				case EAtomicFuncAND:	r=DoAndOr<TUint16>(aPtr, aT, aA, dummy); break;
				case EAtomicFuncXOR:	r=DoXor<TUint16>(aPtr, aT, aA, dummy); break;
				case EAtomicFuncAXO:	r=DoAxo<TUint16>(aPtr, aT, aA, dummy); break;
				case EAtomicFuncTAU:	r=DoThAdd<TUint16>(aPtr, aT, aA, dummy); break;
				case EAtomicFuncTAS:	r=DoThAdd<TInt16>(aPtr, aT, aA, sdummy); break;
				case EAtomicFuncCAS:	r=DoCas<TUint16>(aPtr, aT, aA, dummy); break;
				default: break;
				}
			break;
			}
		case 4:
			{
			TUint32 xx;
			TUint32* dummy = &xx;
			TInt32 yy;
			TInt32* sdummy = &yy;
			switch (func)
				{
				case EAtomicFuncSWP:	r=DoSwap<TUint32>(aPtr, aT, aA, dummy); break;
				case EAtomicFuncADD:	r=DoAdd<TUint32>(aPtr, aT, aA, dummy); break;
				case EAtomicFuncAND:	r=DoAndOr<TUint32>(aPtr, aT, aA, dummy); break;
				case EAtomicFuncXOR:	r=DoXor<TUint32>(aPtr, aT, aA, dummy); break;
				case EAtomicFuncAXO:	r=DoAxo<TUint32>(aPtr, aT, aA, dummy); break;
				case EAtomicFuncTAU:	r=DoThAdd<TUint32>(aPtr, aT, aA, dummy); break;
				case EAtomicFuncTAS:	r=DoThAdd<TInt32>(aPtr, aT, aA, sdummy); break;
				case EAtomicFuncCAS:	r=DoCas<TUint32>(aPtr, aT, aA, dummy); break;
				default: break;
				}
			break;
			}
		case 8:
			{
			TUint64A xx;
			TUint64* dummy = &xx;
			TInt64A yy;
			TInt64* sdummy = &yy;
			switch (func)
				{
				case EAtomicFuncSWP:	r=DoSwap<TUint64>(aPtr, aT, aA, dummy); break;
				case EAtomicFuncADD:	r=DoAdd<TUint64>(aPtr, aT, aA, dummy); break;
				case EAtomicFuncAND:	r=DoAndOr<TUint64>(aPtr, aT, aA, dummy); break;
				case EAtomicFuncXOR:	r=DoXor<TUint64>(aPtr, aT, aA, dummy); break;
				case EAtomicFuncAXO:	r=DoAxo<TUint64>(aPtr, aT, aA, dummy); break;
				case EAtomicFuncTAU:	r=DoThAdd<TUint64>(aPtr, aT, aA, dummy); break;
				case EAtomicFuncTAS:	r=DoThAdd<TInt64>(aPtr, aT, aA, sdummy); break;
				case EAtomicFuncCAS:	r=DoCas<TUint64>(aPtr, aT, aA, dummy); break;
				default: break;
				}
			break;
			}
		default:
			break;
		}
	++aT->iCount;
	return r;
	}