sl@0: // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // e32test\system\t_atomic.h sl@0: // sl@0: // sl@0: sl@0: #include sl@0: sl@0: #ifdef __VC32__ sl@0: #pragma warning( disable : 4244 ) /* conversion to shorter type - possible loss of data */ sl@0: #endif sl@0: sl@0: const TInt KMaxThreads = 8; sl@0: sl@0: #ifdef __KERNEL_MODE__ sl@0: #include sl@0: #undef DEBUGPRINT sl@0: #define DEBUGPRINT Kern::Printf sl@0: #else sl@0: extern void UPrintf(const char*, ...); sl@0: #undef DEBUGPRINT sl@0: #define DEBUGPRINT UPrintf sl@0: #endif sl@0: sl@0: #undef __INT64_ALIGNED__ sl@0: #if (defined(__GNUC__) && (__GNUC__ >= 3)) || defined(__EABI__) sl@0: #define __INT64_ALIGNED__ sl@0: #endif sl@0: sl@0: #ifdef __INT64_ALIGNED__ sl@0: typedef TUint64 TUint64A; sl@0: typedef TInt64 TInt64A; sl@0: #else sl@0: sl@0: class TUint64A sl@0: { sl@0: public: sl@0: inline const TUint64* operator&() const sl@0: { return ((const TUint64*)((T_UintPtr(this)+7)&~7)); } sl@0: inline TUint64* operator&() sl@0: { return ((TUint64*)((T_UintPtr(this)+7)&~7)); } sl@0: private: sl@0: TUint64 i_Data[2]; sl@0: }; sl@0: sl@0: class TInt64A sl@0: { sl@0: public: sl@0: inline const TInt64* operator&() const sl@0: { return ((const TInt64*)((T_UintPtr(this)+7)&~7)); } sl@0: inline TInt64* operator&() sl@0: { return ((TInt64*)((T_UintPtr(this)+7)&~7)); } sl@0: private: sl@0: TUint64 i_Data[2]; sl@0: }; sl@0: sl@0: #endif sl@0: sl@0: struct TDGBase sl@0: { sl@0: TInt Execute(); sl@0: void Dump(const char*); sl@0: sl@0: TUint64 i0; sl@0: TUint64 i1; sl@0: TUint64 i2; sl@0: TUint64 i3; sl@0: TInt iIndex; sl@0: }; sl@0: sl@0: struct TAtomicAction sl@0: { sl@0: TUint64 i0; // first parameter to operation sl@0: TUint64 i1; // second parameter to operation sl@0: TUint64 i2; // third parameter to operation sl@0: TInt iIndex; // index of atomic function sl@0: TInt iThread; // thread identifier sl@0: }; sl@0: sl@0: struct TPerThread sl@0: { sl@0: TUint64 iDiff; // accumulated difference sl@0: TUint64 iXor; // accumulated XOR sl@0: TUint64 iFailCount; // failure count for CAS operations sl@0: TUint64 iCount; // iteration count sl@0: }; sl@0: sl@0: extern "C" TInt DoAtomicAction(TAny* aPtr, TPerThread* aT, TAtomicAction& aA); sl@0: sl@0: enum TMemoryOrder sl@0: { sl@0: EOrderRelaxed=0, sl@0: EOrderAcquire=1, sl@0: EOrderRelease=2, sl@0: EOrderOrdered=3, sl@0: }; sl@0: sl@0: enum TAtomicFunc sl@0: { sl@0: EAtomicFuncLOAD=0, sl@0: EAtomicFuncSTORE=1, sl@0: EAtomicFuncSWP=2, sl@0: EAtomicFuncADD=3, sl@0: EAtomicFuncAND=4, sl@0: EAtomicFuncIOR=5, sl@0: EAtomicFuncXOR=6, sl@0: EAtomicFuncAXO=7, sl@0: EAtomicFuncTAU=8, sl@0: EAtomicFuncTAS=9, sl@0: EAtomicFuncCAS=10, sl@0: EAtomicFuncN sl@0: }; sl@0: sl@0: enum TFuncType sl@0: { sl@0: EFuncTypeInvalid=0, sl@0: EFuncTypeLoad=1, sl@0: EFuncTypeRmw1=2, sl@0: EFuncTypeRmw2=3, sl@0: EFuncTypeRmw3=4, sl@0: EFuncTypeCas=5, sl@0: }; sl@0: sl@0: #define FUNCS_PER_SIZE (TUint(EAtomicFuncN)*4) sl@0: #define TOTAL_FUNCS (FUNCS_PER_SIZE*4) sl@0: #define INDEXES_PER_SIZE (16*4) sl@0: #define TOTAL_INDEXES (INDEXES_PER_SIZE*4) sl@0: sl@0: #define FUNCATTR(func,size,ord,type) ((TUint(func)<<24)|(TUint(size)<<16)|(TUint(ord)<<8)|(TUint(type))) sl@0: #define ATTR_TO_TYPE(attr) ((attr)&0xff) sl@0: #define ATTR_TO_ORD(attr) (((attr)>>8)&0xff) sl@0: #define ATTR_TO_SIZE(attr) (((attr)>>16)&0xff) sl@0: #define ATTR_TO_FUNC(attr) (((attr)>>24)&0xff) sl@0: #define FUNCATTR2(func,size,type) \ sl@0: FUNCATTR(func,size,EOrderRelaxed,type), FUNCATTR(func,size,EOrderAcquire,type), FUNCATTR(func,size,EOrderRelease,type), FUNCATTR(func,size,EOrderOrdered,type) sl@0: #define FUNCATTR2A(func,size,type) \ sl@0: 0, FUNCATTR(func,size,EOrderAcquire,type), 0, 0 sl@0: #define FUNCATTR2B(func,size,type) \ sl@0: 0, 0, FUNCATTR(func,size,EOrderRelease,type), FUNCATTR(func,size,EOrderOrdered,type) sl@0: #define FUNCATTR3(size) \ sl@0: FUNCATTR2A(EAtomicFuncLOAD,size,EFuncTypeLoad), \ sl@0: FUNCATTR2B(EAtomicFuncSTORE,size,EFuncTypeRmw1), \ sl@0: FUNCATTR2(EAtomicFuncSWP,size,EFuncTypeRmw1), \ sl@0: FUNCATTR2(EAtomicFuncADD,size,EFuncTypeRmw1), \ sl@0: FUNCATTR2(EAtomicFuncAND,size,EFuncTypeRmw1), \ sl@0: FUNCATTR2(EAtomicFuncIOR,size,EFuncTypeRmw1), \ sl@0: FUNCATTR2(EAtomicFuncXOR,size,EFuncTypeRmw1), \ sl@0: FUNCATTR2(EAtomicFuncAXO,size,EFuncTypeRmw2), \ sl@0: FUNCATTR2(EAtomicFuncTAU,size,EFuncTypeRmw3), \ sl@0: FUNCATTR2(EAtomicFuncTAS,size,EFuncTypeRmw3), \ sl@0: FUNCATTR2(EAtomicFuncCAS,size,EFuncTypeCas), \ sl@0: 0, 0, 0, 0, \ sl@0: 0, 0, 0, 0, \ sl@0: 0, 0, 0, 0, \ sl@0: 0, 0, 0, 0, \ sl@0: 0, 0, 0, 0 sl@0: sl@0: sl@0: #define __DO_STRINGIFY__(x) #x sl@0: #define __STRINGIFY__(x) __DO_STRINGIFY__(x) sl@0: #define __concat3__(a,b,c) a##b##c sl@0: #define __concat5__(a,b,c,d,e) a##b##c##d##e sl@0: #define FUNCNAME(func,size,ord) __STRINGIFY__(__concat3__(func,size,ord)) sl@0: #define ATOMICFUNC(func,size,ord) __concat5__(__e32_atomic_,func,_,ord,size) sl@0: #define CONTROLFUNC(func,size,ord) __concat3__(__nonatomic_,func,size) sl@0: #define FUNCNAME2(func,size) FUNCNAME(func,size,rlx), FUNCNAME(func,size,acq), FUNCNAME(func,size,rel), FUNCNAME(func,size,ord) sl@0: #define FUNCNAME3(size) \ sl@0: FUNCNAME2(load,size), \ sl@0: FUNCNAME2(store,size), \ sl@0: FUNCNAME2(swp,size), \ sl@0: FUNCNAME2(add,size), \ sl@0: FUNCNAME2(and,size), \ sl@0: FUNCNAME2(ior,size), \ sl@0: FUNCNAME2(xor,size), \ sl@0: FUNCNAME2(axo,size), \ sl@0: FUNCNAME2(tau,size), \ sl@0: FUNCNAME2(tas,size), \ sl@0: FUNCNAME2(cas,size), \ sl@0: "", "", "", "", \ sl@0: "", "", "", "", \ sl@0: "", "", "", "", \ sl@0: "", "", "", "", \ sl@0: "", "", "", "" sl@0: sl@0: sl@0: #define ATOMICFUNC2(func,size) (PFV)&ATOMICFUNC(func,size,rlx), (PFV)&ATOMICFUNC(func,size,acq), (PFV)&ATOMICFUNC(func,size,rel), (PFV)&ATOMICFUNC(func,size,ord) sl@0: #define ATOMICFUNC2A(func,size) 0, (PFV)&ATOMICFUNC(func,size,acq), 0, 0 sl@0: #define ATOMICFUNC2B(func,size) 0, 0, (PFV)&ATOMICFUNC(func,size,rel), (PFV)&ATOMICFUNC(func,size,ord) sl@0: #define ATOMICFUNC3(size) \ sl@0: ATOMICFUNC2A(load,size), \ sl@0: ATOMICFUNC2B(store,size), \ sl@0: ATOMICFUNC2(swp,size), \ sl@0: ATOMICFUNC2(add,size), \ sl@0: ATOMICFUNC2(and,size), \ sl@0: ATOMICFUNC2(ior,size), \ sl@0: ATOMICFUNC2(xor,size), \ sl@0: ATOMICFUNC2(axo,size), \ sl@0: ATOMICFUNC2(tau,size), \ sl@0: ATOMICFUNC2(tas,size), \ sl@0: ATOMICFUNC2(cas,size), \ sl@0: 0, 0, 0, 0, \ sl@0: 0, 0, 0, 0, \ sl@0: 0, 0, 0, 0, \ sl@0: 0, 0, 0, 0, \ sl@0: 0, 0, 0, 0 sl@0: sl@0: sl@0: #define CONTROLFUNC2(func,size) (PFV)&CONTROLFUNC(func,size,rlx), (PFV)&CONTROLFUNC(func,size,acq), (PFV)&CONTROLFUNC(func,size,rel), (PFV)&CONTROLFUNC(func,size,ord) sl@0: #define CONTROLFUNC2A(func,size) 0, (PFV)&CONTROLFUNC(func,size,acq), 0, 0 sl@0: #define CONTROLFUNC2B(func,size) 0, 0, (PFV)&CONTROLFUNC(func,size,rel), (PFV)&CONTROLFUNC(func,size,ord) sl@0: #define CONTROLFUNC3(size) \ sl@0: CONTROLFUNC2A(load,size), \ sl@0: CONTROLFUNC2B(store,size), \ sl@0: CONTROLFUNC2(swp,size), \ sl@0: CONTROLFUNC2(add,size), \ sl@0: CONTROLFUNC2(and,size), \ sl@0: CONTROLFUNC2(ior,size), \ sl@0: CONTROLFUNC2(xor,size), \ sl@0: CONTROLFUNC2(axo,size), \ sl@0: CONTROLFUNC2(tau,size), \ sl@0: CONTROLFUNC2(tas,size), \ sl@0: CONTROLFUNC2(cas,size), \ sl@0: 0, 0, 0, 0, \ sl@0: 0, 0, 0, 0, \ sl@0: 0, 0, 0, 0, \ sl@0: 0, 0, 0, 0, \ sl@0: 0, 0, 0, 0 sl@0: sl@0: sl@0: #ifdef __INCLUDE_FUNC_NAMES__ sl@0: extern "C" const char* FuncName[] = sl@0: { sl@0: FUNCNAME3(8), sl@0: FUNCNAME3(16), sl@0: FUNCNAME3(32), sl@0: FUNCNAME3(64) sl@0: }; sl@0: #endif sl@0: sl@0: typedef void (*PFV)(); sl@0: sl@0: #ifdef __INCLUDE_ATOMIC_FUNCTIONS__ sl@0: extern "C" const PFV AtomicFuncPtr[] = sl@0: { sl@0: ATOMICFUNC3(8), sl@0: ATOMICFUNC3(16), sl@0: ATOMICFUNC3(32), sl@0: ATOMICFUNC3(64) sl@0: }; sl@0: #endif sl@0: sl@0: #ifdef __INCLUDE_CONTROL_FUNCTIONS__ sl@0: extern "C" { sl@0: sl@0: // Simulated versions of atomic functions without the atomicity sl@0: extern TUint8 __nonatomic_load8(const volatile TAny* a); sl@0: extern TUint8 __nonatomic_store8(volatile TAny* a, TUint8 v); sl@0: extern TUint8 __nonatomic_swp8(volatile TAny* a, TUint8 v); sl@0: extern TBool __nonatomic_cas8(volatile TAny* a, TUint8* q, TUint8 v); sl@0: extern TUint8 __nonatomic_add8(volatile TAny* a, TUint8 v); sl@0: extern TUint8 __nonatomic_and8(volatile TAny* a, TUint8 v); sl@0: extern TUint8 __nonatomic_ior8(volatile TAny* a, TUint8 v); sl@0: extern TUint8 __nonatomic_xor8(volatile TAny* a, TUint8 v); sl@0: extern TUint8 __nonatomic_axo8(volatile TAny* a, TUint8 u, TUint8 v); sl@0: extern TUint8 __nonatomic_tau8(volatile TAny* a, TUint8 t, TUint8 u, TUint8 v); sl@0: extern TInt8 __nonatomic_tas8(volatile TAny* a, TInt8 t, TInt8 u, TInt8 v); sl@0: sl@0: extern TUint16 __nonatomic_load16(const volatile TAny* a); sl@0: extern TUint16 __nonatomic_store16(volatile TAny* a, TUint16 v); sl@0: extern TUint16 __nonatomic_swp16(volatile TAny* a, TUint16 v); sl@0: extern TBool __nonatomic_cas16(volatile TAny* a, TUint16* q, TUint16 v); sl@0: extern TUint16 __nonatomic_add16(volatile TAny* a, TUint16 v); sl@0: extern TUint16 __nonatomic_and16(volatile TAny* a, TUint16 v); sl@0: extern TUint16 __nonatomic_ior16(volatile TAny* a, TUint16 v); sl@0: extern TUint16 __nonatomic_xor16(volatile TAny* a, TUint16 v); sl@0: extern TUint16 __nonatomic_axo16(volatile TAny* a, TUint16 u, TUint16 v); sl@0: extern TUint16 __nonatomic_tau16(volatile TAny* a, TUint16 t, TUint16 u, TUint16 v); sl@0: extern TInt16 __nonatomic_tas16(volatile TAny* a, TInt16 t, TInt16 u, TInt16 v); sl@0: sl@0: extern TUint32 __nonatomic_load32(const volatile TAny* a); sl@0: extern TUint32 __nonatomic_store32(volatile TAny* a, TUint32 v); sl@0: extern TUint32 __nonatomic_swp32(volatile TAny* a, TUint32 v); sl@0: extern TBool __nonatomic_cas32(volatile TAny* a, TUint32* q, TUint32 v); sl@0: extern TUint32 __nonatomic_add32(volatile TAny* a, TUint32 v); sl@0: extern TUint32 __nonatomic_and32(volatile TAny* a, TUint32 v); sl@0: extern TUint32 __nonatomic_ior32(volatile TAny* a, TUint32 v); sl@0: extern TUint32 __nonatomic_xor32(volatile TAny* a, TUint32 v); sl@0: extern TUint32 __nonatomic_axo32(volatile TAny* a, TUint32 u, TUint32 v); sl@0: extern TUint32 __nonatomic_tau32(volatile TAny* a, TUint32 t, TUint32 u, TUint32 v); sl@0: extern TInt32 __nonatomic_tas32(volatile TAny* a, TInt32 t, TInt32 u, TInt32 v); sl@0: sl@0: extern TUint64 __nonatomic_load64(const volatile TAny* a); sl@0: extern TUint64 __nonatomic_store64(volatile TAny* a, TUint64 v); sl@0: extern TUint64 __nonatomic_swp64(volatile TAny* a, TUint64 v); sl@0: extern TBool __nonatomic_cas64(volatile TAny* a, TUint64* q, TUint64 v); sl@0: extern TUint64 __nonatomic_add64(volatile TAny* a, TUint64 v); sl@0: extern TUint64 __nonatomic_and64(volatile TAny* a, TUint64 v); sl@0: extern TUint64 __nonatomic_ior64(volatile TAny* a, TUint64 v); sl@0: extern TUint64 __nonatomic_xor64(volatile TAny* a, TUint64 v); sl@0: extern TUint64 __nonatomic_axo64(volatile TAny* a, TUint64 u, TUint64 v); sl@0: extern TUint64 __nonatomic_tau64(volatile TAny* a, TUint64 t, TUint64 u, TUint64 v); sl@0: extern TInt64 __nonatomic_tas64(volatile TAny* a, TInt64 t, TInt64 u, TInt64 v); sl@0: sl@0: } // extern "C" sl@0: sl@0: sl@0: extern "C" const PFV ControlFuncPtr[] = sl@0: { sl@0: CONTROLFUNC3(8), sl@0: CONTROLFUNC3(16), sl@0: CONTROLFUNC3(32), sl@0: CONTROLFUNC3(64) sl@0: }; sl@0: #endif sl@0: sl@0: #ifdef __INCLUDE_FUNCTION_ATTRIBUTES__ sl@0: extern "C" const TUint FuncAttr[] = sl@0: { sl@0: FUNCATTR3(1), sl@0: FUNCATTR3(2), sl@0: FUNCATTR3(4), sl@0: FUNCATTR3(8) sl@0: }; sl@0: #endif sl@0: sl@0: template sl@0: struct TLoadFn // load sl@0: { sl@0: typedef T (*F)(const volatile TAny*); sl@0: }; sl@0: sl@0: template sl@0: struct TRmw1Fn // store, swp, add, and, ior, xor sl@0: { sl@0: typedef T (*F)(volatile TAny*, T); sl@0: }; sl@0: sl@0: template sl@0: struct TRmw2Fn // axo sl@0: { sl@0: typedef T (*F)(volatile TAny*, T, T); sl@0: }; sl@0: sl@0: template sl@0: struct TRmw3Fn // tau, tas sl@0: { sl@0: typedef T (*F)(volatile TAny*, T, T, T); sl@0: }; sl@0: sl@0: template sl@0: struct TCasFn // cas sl@0: { sl@0: typedef TBool (*F)(volatile TAny*, T*, T); sl@0: }; sl@0: sl@0: class TEnclosed sl@0: { sl@0: public: sl@0: TEnclosed(TInt aSize); sl@0: TAny* Ptr(); sl@0: TInt Next(); sl@0: void Init(); sl@0: TInt Verify(); sl@0: TInt Offset() const {return iOffset;} sl@0: private: sl@0: TUint64* iData; sl@0: TUint64* iBackup; sl@0: TUint64 i_Data[17]; sl@0: TInt iOffset; sl@0: TInt iSize; sl@0: }; sl@0: sl@0: template sl@0: class Transform sl@0: { sl@0: public: sl@0: inline static T A(); sl@0: inline static T B(); sl@0: static T F(T aOrig); // return Ax+B mod M (M=2^n, n=number of bits in T) sl@0: static T Pow(T aBase, TUint64 aExp); // return aBase^aExp mod M sl@0: static T PowerSum(T aBase, TUint64 aExp); // return 1 + T + T^2 + ... + T^(aExp-1) mod M sl@0: static T F_iter(T aOrig, TUint64 aCount); // return result of applying F iterated aCount times to aOrig sl@0: }; sl@0: sl@0: TEMPLATE_SPECIALIZATION inline TUint8 Transform::A() sl@0: { return 19; } sl@0: TEMPLATE_SPECIALIZATION inline TUint8 Transform::B() sl@0: { return 29; } sl@0: sl@0: TEMPLATE_SPECIALIZATION inline TUint16 Transform::A() sl@0: { return 487; } sl@0: TEMPLATE_SPECIALIZATION inline TUint16 Transform::B() sl@0: { return 12983; } sl@0: sl@0: TEMPLATE_SPECIALIZATION inline TUint32 Transform::A() sl@0: { return 29943829; } sl@0: TEMPLATE_SPECIALIZATION inline TUint32 Transform::B() sl@0: { return 104729; } sl@0: sl@0: TEMPLATE_SPECIALIZATION inline TUint64 Transform::A() sl@0: { return UI64LIT(2862933555777941757); } sl@0: TEMPLATE_SPECIALIZATION inline TUint64 Transform::B() sl@0: { return UI64LIT(104917093); } sl@0: sl@0: template sl@0: T Transform::F(T aOrig) sl@0: { sl@0: return (T)(aOrig * Transform::A() + Transform::B()); sl@0: } sl@0: sl@0: template sl@0: T Transform::Pow(T aBase, TUint64 aExp) sl@0: { sl@0: T result(1); sl@0: T multiplier(aBase); sl@0: while (aExp) sl@0: { sl@0: if (aExp&1) sl@0: result *= multiplier; sl@0: aExp >>= 1; sl@0: if (aExp) sl@0: multiplier *= multiplier; sl@0: } sl@0: return (T)result; sl@0: } sl@0: sl@0: template sl@0: T Transform::PowerSum(T aBase, TUint64 aExp) sl@0: { sl@0: T result(0); sl@0: T multiplier(aBase); sl@0: T inter(1); sl@0: while (aExp) sl@0: { sl@0: if (aExp&1) sl@0: { sl@0: result *= multiplier; sl@0: result += inter; sl@0: } sl@0: aExp >>= 1; sl@0: if (aExp) sl@0: { sl@0: inter *= (multiplier + 1); sl@0: multiplier *= multiplier; sl@0: } sl@0: } sl@0: return (T)result; sl@0: } sl@0: sl@0: template sl@0: T Transform::F_iter(T aOrig, TUint64 aCount) sl@0: { sl@0: return (T)(Pow(A(),aCount)*aOrig + PowerSum(A(),aCount)*B()); sl@0: } sl@0: sl@0: sl@0: sl@0: #ifdef __EPOC32__ sl@0: _LIT(KAtomicTestLddName,"D_ATOMIC"); sl@0: sl@0: class RTestAtomic : public RBusLogicalChannel sl@0: { sl@0: public: sl@0: enum TControl sl@0: { sl@0: ETDGExecuteK=0, sl@0: EInitialise=1, sl@0: ERetrieve=2, sl@0: ESetCurrentThreadTimeslice=3, sl@0: ESwitchExecTables=4, sl@0: EGetKernelMemoryAddress=5, sl@0: EMaxControl sl@0: }; sl@0: sl@0: #ifndef __KERNEL_MODE__ sl@0: public: sl@0: inline TInt Open() sl@0: { return DoCreate(KAtomicTestLddName,TVersion(),KNullUnit,NULL,NULL); } sl@0: public: sl@0: inline TInt TDGExecuteK(TDGBase& a) sl@0: { return DoControl(ETDGExecuteK, &a); } sl@0: inline TInt Initialise(TUint64 aValue) sl@0: { return DoControl(EInitialise, &aValue); } sl@0: inline TUint64 Retrieve() sl@0: { TUint64 x; DoControl(ERetrieve, &x); return x; } sl@0: inline TInt SetCurrentThreadTimeslice(TInt aTimeslice) sl@0: { return DoControl(ESetCurrentThreadTimeslice, (TAny*)aTimeslice); } sl@0: inline TInt SwitchExecTables(TInt aThread) sl@0: { return DoControl(ESwitchExecTables, (TAny*)aThread); } sl@0: inline TAny* KernelMemoryAddress() sl@0: { return (TAny*)DoControl(EGetKernelMemoryAddress); } sl@0: sl@0: static TInt GetThreadInfo(TPerThread& aInfo); sl@0: static TInt SetThreadInfo(const TPerThread& aInfo); sl@0: static TInt AtomicAction(TAtomicAction& aAction); sl@0: static TInt RestoreExecTable(); sl@0: #endif sl@0: }; sl@0: #endif sl@0: sl@0: