kerneltest/e32test/system/t_atomic_common.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 0 a41df078684a
child 43 c1f20ce4abcf
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// 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;
	}