Update contrib.
1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // e32test\system\t_atomic_common.cpp
18 #ifdef __KERNEL_MODE__
19 #include <kernel/kernel.h>
21 #define __E32TEST_EXTENSION__
27 #define __INCLUDE_FUNC_NAMES__
30 #define __INCLUDE_ATOMIC_FUNCTIONS__
31 #define __INCLUDE_CONTROL_FUNCTIONS__
32 #define __INCLUDE_FUNCTION_ATTRIBUTES__
36 #define DEBUGPRINTVAR(x) \
38 const TUint8* p = (const TUint8*)&(x); \
39 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]); \
44 // Simulated versions of atomic functions without the atomicity
45 #define __LOAD(T) return *(T*)a
46 #define __STORE(T) *(T*)a=v; return v
47 #define __SWP(T) T oldv=*(T*)a; *(T*)a=v; return oldv
48 #define __CAS(T) if (*(T*)a==*q) {*(T*)a=v; return 1;} *q=*(T*)a; return 0
49 #define __ADD(T) T oldv=*(T*)a; *(T*)a=(T)(oldv+v); return oldv
50 #define __AND(T) T oldv=*(T*)a; *(T*)a=(T)(oldv&v); return oldv
51 #define __IOR(T) T oldv=*(T*)a; *(T*)a=(T)(oldv|v); return oldv
52 #define __XOR(T) T oldv=*(T*)a; *(T*)a=(T)(oldv^v); return oldv
53 #define __AXO(T) T oldv=*(T*)a; *(T*)a=(T)((oldv&u)^v); return oldv
54 #define __TA(T) T oldv=*(T*)a; *(T*)a=(T)(oldv+((oldv>=t)?u:v)); return oldv
56 TUint8 __nonatomic_load8(const volatile TAny* a)
61 TUint8 __nonatomic_store8(volatile TAny* a, TUint8 v)
66 TUint8 __nonatomic_swp8(volatile TAny* a, TUint8 v)
71 TBool __nonatomic_cas8(volatile TAny* a, TUint8* q, TUint8 v)
76 TUint8 __nonatomic_add8(volatile TAny* a, TUint8 v)
81 TUint8 __nonatomic_and8(volatile TAny* a, TUint8 v)
86 TUint8 __nonatomic_ior8(volatile TAny* a, TUint8 v)
91 TUint8 __nonatomic_xor8(volatile TAny* a, TUint8 v)
96 TUint8 __nonatomic_axo8(volatile TAny* a, TUint8 u, TUint8 v)
101 TUint8 __nonatomic_tau8(volatile TAny* a, TUint8 t, TUint8 u, TUint8 v)
106 TInt8 __nonatomic_tas8(volatile TAny* a, TInt8 t, TInt8 u, TInt8 v)
112 TUint16 __nonatomic_load16(const volatile TAny* a)
117 TUint16 __nonatomic_store16(volatile TAny* a, TUint16 v)
122 TUint16 __nonatomic_swp16(volatile TAny* a, TUint16 v)
127 TBool __nonatomic_cas16(volatile TAny* a, TUint16* q, TUint16 v)
132 TUint16 __nonatomic_add16(volatile TAny* a, TUint16 v)
137 TUint16 __nonatomic_and16(volatile TAny* a, TUint16 v)
142 TUint16 __nonatomic_ior16(volatile TAny* a, TUint16 v)
147 TUint16 __nonatomic_xor16(volatile TAny* a, TUint16 v)
152 TUint16 __nonatomic_axo16(volatile TAny* a, TUint16 u, TUint16 v)
157 TUint16 __nonatomic_tau16(volatile TAny* a, TUint16 t, TUint16 u, TUint16 v)
162 TInt16 __nonatomic_tas16(volatile TAny* a, TInt16 t, TInt16 u, TInt16 v)
168 TUint32 __nonatomic_load32(const volatile TAny* a)
173 TUint32 __nonatomic_store32(volatile TAny* a, TUint32 v)
178 TUint32 __nonatomic_swp32(volatile TAny* a, TUint32 v)
183 TBool __nonatomic_cas32(volatile TAny* a, TUint32* q, TUint32 v)
188 TUint32 __nonatomic_add32(volatile TAny* a, TUint32 v)
193 TUint32 __nonatomic_and32(volatile TAny* a, TUint32 v)
198 TUint32 __nonatomic_ior32(volatile TAny* a, TUint32 v)
203 TUint32 __nonatomic_xor32(volatile TAny* a, TUint32 v)
208 TUint32 __nonatomic_axo32(volatile TAny* a, TUint32 u, TUint32 v)
213 TUint32 __nonatomic_tau32(volatile TAny* a, TUint32 t, TUint32 u, TUint32 v)
218 TInt32 __nonatomic_tas32(volatile TAny* a, TInt32 t, TInt32 u, TInt32 v)
224 TUint64 __nonatomic_load64(const volatile TAny* a)
229 TUint64 __nonatomic_store64(volatile TAny* a, TUint64 v)
234 TUint64 __nonatomic_swp64(volatile TAny* a, TUint64 v)
239 TBool __nonatomic_cas64(volatile TAny* a, TUint64* q, TUint64 v)
244 TUint64 __nonatomic_add64(volatile TAny* a, TUint64 v)
249 TUint64 __nonatomic_and64(volatile TAny* a, TUint64 v)
254 TUint64 __nonatomic_ior64(volatile TAny* a, TUint64 v)
259 TUint64 __nonatomic_xor64(volatile TAny* a, TUint64 v)
264 TUint64 __nonatomic_axo64(volatile TAny* a, TUint64 u, TUint64 v)
269 TUint64 __nonatomic_tau64(volatile TAny* a, TUint64 t, TUint64 u, TUint64 v)
274 TInt64 __nonatomic_tas64(volatile TAny* a, TInt64 t, TInt64 u, TInt64 v)
282 #define DEBUGPRINTxyrc() \
288 template<class T> TInt DoLoadTest(TInt aIndex, TAny* aPtr, T aInitialValue)
290 #ifdef __EXTRA_DEBUG__
291 DEBUGPRINT("DoLoadTest %d %08x", aIndex, aPtr);
293 typename TLoadFn<T>::F atomic = (typename TLoadFn<T>::F)AtomicFuncPtr[aIndex];
294 typename TLoadFn<T>::F control = (typename TLoadFn<T>::F)ControlFuncPtr[aIndex];
308 template<class T> TInt DoRmw1Test(TInt aIndex, TAny* aPtr, T aInitialValue, T a1)
310 #ifdef __EXTRA_DEBUG__
311 DEBUGPRINT("DoRmw1Test %d %08x", aIndex, aPtr);
313 typename TRmw1Fn<T>::F atomic = (typename TRmw1Fn<T>::F)AtomicFuncPtr[aIndex];
314 typename TRmw1Fn<T>::F control = (typename TRmw1Fn<T>::F)ControlFuncPtr[aIndex];
319 T c = control(&y,a1);
328 template<class T> TInt DoRmw2Test(TInt aIndex, TAny* aPtr, T aInitialValue, T a1, T a2)
330 #ifdef __EXTRA_DEBUG__
331 DEBUGPRINT("DoRmw2Test %d %08x", aIndex, aPtr);
333 typename TRmw2Fn<T>::F atomic = (typename TRmw2Fn<T>::F)AtomicFuncPtr[aIndex];
334 typename TRmw2Fn<T>::F control = (typename TRmw2Fn<T>::F)ControlFuncPtr[aIndex];
338 T r = atomic(&x,a1,a2);
339 T c = control(&y,a1,a2);
348 template<class T> TInt DoRmw3Test(TInt aIndex, TAny* aPtr, T aInitialValue, T a1, T a2, T a3)
350 #ifdef __EXTRA_DEBUG__
351 DEBUGPRINT("DoRmw3Test %d %08x", aIndex, aPtr);
353 typename TRmw3Fn<T>::F atomic = (typename TRmw3Fn<T>::F)AtomicFuncPtr[aIndex];
354 typename TRmw3Fn<T>::F control = (typename TRmw3Fn<T>::F)ControlFuncPtr[aIndex];
358 T r = atomic(&x,a1,a2,a3);
359 T c = control(&y,a1,a2,a3);
368 template<class T> TInt DoCasTest(TInt aIndex, TAny* aPtr, T aInitialValue, T aExpectedValue, T aFinalValue)
370 #ifdef __EXTRA_DEBUG__
371 DEBUGPRINT("DoCasTest %d %08x", aIndex, aPtr);
373 typename TCasFn<T>::F atomic = (typename TCasFn<T>::F)AtomicFuncPtr[aIndex];
374 typename TCasFn<T>::F control = (typename TCasFn<T>::F)ControlFuncPtr[aIndex];
377 T ex = aExpectedValue;
379 T ey = aExpectedValue;
380 TBool r = atomic(&x,&ex,aFinalValue);
381 TBool c = control(&y,&ey,aFinalValue);
391 else if (r && x!=aFinalValue)
393 else if (!r && ex!=aInitialValue)
397 DEBUGPRINT("r=%d",r);
400 DEBUGPRINT("c=%d",c);
409 TEnclosed::TEnclosed(TInt aSize)
413 iData = (TUint64*)((T_UintPtr(i_Data) + 7) &~ 7); // align up to next 8 byte boundary
417 TAny* TEnclosed::Ptr()
419 return ((TUint8*)iData + iOffset);
422 TInt TEnclosed::Next()
424 const TInt KLimit[8] = {8, 16, 0, 32, 0, 0, 0, 32};
434 if (iOffset >= KLimit[iSize-1])
440 void TEnclosed::Init()
442 TUint32 x = iOffset+1;
445 TUint32* d = (TUint32*)iData;
446 TUint32* b = (TUint32*)iBackup;
456 TInt TEnclosed::Verify()
458 TUint8* d = (TUint8*)iData;
459 const TUint8* b = (const TUint8*)iBackup;
461 for (i=0; i<iSize; ++i)
462 d[iOffset+i] = b[iOffset+i];
463 if (memcompare(b,64,d,64))
465 DEBUGPRINT("FAIL! iOffset=%02x, sizeof(T)=%1d", iOffset, iSize);
470 DEBUGPRINT("d[%02x]=%02x b[%02x]=%02x", i, d[i], i, b[i]);
479 TInt TDGBase::Execute()
481 PFV af0 = AtomicFuncPtr[iIndex];
482 PFV cf0 = ControlFuncPtr[iIndex];
485 TUint attr = FuncAttr[iIndex];
486 TInt type = ATTR_TO_TYPE(attr);
487 TInt size = ATTR_TO_SIZE(attr);
488 TInt func = ATTR_TO_FUNC(attr);
489 if (type==EFuncTypeInvalid)
491 #ifdef __EXTRA_DEBUG__
492 TInt ord = ATTR_TO_ORD(attr);
493 DEBUGPRINT("A=%08x T=%d O=%d S=%d F=%d", attr, type, ord, size, func);
497 while ( (res = enc.Next()) == KErrNone )
499 #ifdef __EXTRA_DEBUG__
500 DEBUGPRINT("Offset %02x", enc.Offset());
502 TAny* ptr = enc.Ptr();
509 case 1: res = DoLoadTest<TUint8>(iIndex, ptr, (TUint8)i0); break;
510 case 2: res = DoLoadTest<TUint16>(iIndex, ptr, (TUint16)i0); break;
511 case 4: res = DoLoadTest<TUint32>(iIndex, ptr, (TUint32)i0); break;
512 case 8: res = DoLoadTest<TUint64>(iIndex, ptr, i0); break;
513 default: res = __LINE__; break;
521 case 1: res = DoRmw1Test<TUint8>(iIndex, ptr, (TUint8)i0, (TUint8)i1); break;
522 case 2: res = DoRmw1Test<TUint16>(iIndex, ptr, (TUint16)i0, (TUint16)i1); break;
523 case 4: res = DoRmw1Test<TUint32>(iIndex, ptr, (TUint32)i0, (TUint32)i1); break;
524 case 8: res = DoRmw1Test<TUint64>(iIndex, ptr, i0, i1); break;
525 default: res = __LINE__; break;
533 case 1: res = DoRmw2Test<TUint8>(iIndex, ptr, (TUint8)i0, (TUint8)i1, (TUint8)i2); break;
534 case 2: res = DoRmw2Test<TUint16>(iIndex, ptr, (TUint16)i0, (TUint16)i1, (TUint16)i2); break;
535 case 4: res = DoRmw2Test<TUint32>(iIndex, ptr, (TUint32)i0, (TUint32)i1, (TUint32)i2); break;
536 case 8: res = DoRmw2Test<TUint64>(iIndex, ptr, i0, i1, i2); break;
537 default: res = __LINE__; break;
543 if (func==EAtomicFuncTAU)
547 case 1: res = DoRmw3Test<TUint8>(iIndex, ptr, (TUint8)i0, (TUint8)i1, (TUint8)i2, (TUint8)i3); break;
548 case 2: res = DoRmw3Test<TUint16>(iIndex, ptr, (TUint16)i0, (TUint16)i1, (TUint16)i2, (TUint16)i3); break;
549 case 4: res = DoRmw3Test<TUint32>(iIndex, ptr, (TUint32)i0, (TUint32)i1, (TUint32)i2, (TUint32)i3); break;
550 case 8: res = DoRmw3Test<TUint64>(iIndex, ptr, i0, i1, i2, i3); break;
551 default: res = __LINE__; break;
554 else if (func==EAtomicFuncTAS)
558 case 1: res = DoRmw3Test<TInt8>(iIndex, ptr, (TInt8)i0, (TInt8)i1, (TInt8)i2, (TInt8)i3); break;
559 case 2: res = DoRmw3Test<TInt16>(iIndex, ptr, (TInt16)i0, (TInt16)i1, (TInt16)i2, (TInt16)i3); break;
560 case 4: res = DoRmw3Test<TInt32>(iIndex, ptr, (TInt32)i0, (TInt32)i1, (TInt32)i2, (TInt32)i3); break;
561 case 8: res = DoRmw3Test<TInt64>(iIndex, ptr, i0, i1, i2, i3); break;
562 default: res = __LINE__; break;
573 case 1: res = DoCasTest<TUint8>(iIndex, ptr, (TUint8)i0, (TUint8)i1, (TUint8)i2); break;
574 case 2: res = DoCasTest<TUint16>(iIndex, ptr, (TUint16)i0, (TUint16)i1, (TUint16)i2); break;
575 case 4: res = DoCasTest<TUint32>(iIndex, ptr, (TUint32)i0, (TUint32)i1, (TUint32)i2); break;
576 case 8: res = DoCasTest<TUint64>(iIndex, ptr, i0, i1, i2); break;
577 default: res = __LINE__; break;
593 #ifndef __KERNEL_MODE__
594 void TDGBase::Dump(const char* aTitle)
596 TPtrC8 fname8((const TText8*)FuncName[iIndex]);
600 DEBUGPRINT("iIndex=%d (%S)", iIndex, &fname);
601 DEBUGPRINT("i0 = %08x %08x", I64HIGH(i0), I64LOW(i0));
602 DEBUGPRINT("i1 = %08x %08x", I64HIGH(i1), I64LOW(i1));
603 DEBUGPRINT("i2 = %08x %08x", I64HIGH(i2), I64LOW(i2));
604 DEBUGPRINT("i3 = %08x %08x", I64HIGH(i3), I64LOW(i3));
608 template<class T> TInt DoSwap(TAny* aPtr, TPerThread* aT, TAtomicAction& aA, T*)
610 typename TRmw1Fn<T>::F atomic = (typename TRmw1Fn<T>::F)AtomicFuncPtr[aA.iIndex];
612 T orig = atomic(aPtr, newv);
613 T xr = (T)(newv ^ orig);
615 T diff = (T)(newv - orig);
620 template<class T> TInt DoAdd(TAny* aPtr, TPerThread* aT, TAtomicAction& aA, T*)
622 typename TRmw1Fn<T>::F atomic = (typename TRmw1Fn<T>::F)AtomicFuncPtr[aA.iIndex];
624 T orig = atomic(aPtr, arg);
625 T xr = (T)((arg+orig) ^ orig);
631 template<class T> TInt DoXor(TAny* aPtr, TPerThread* aT, TAtomicAction& aA, T*)
633 typename TRmw1Fn<T>::F atomic = (typename TRmw1Fn<T>::F)AtomicFuncPtr[aA.iIndex];
635 T orig = atomic(aPtr, arg);
636 T diff = (T)((arg^orig) - orig);
642 template<class T> TInt DoAndOr(TAny* aPtr, TPerThread* aT, TAtomicAction& aA, T*)
644 typename TRmw1Fn<T>::F atomic_and = (typename TRmw1Fn<T>::F)AtomicFuncPtr[aA.iIndex];
645 typename TRmw1Fn<T>::F atomic_or = (typename TRmw1Fn<T>::F)AtomicFuncPtr[aA.iIndex+4];
648 T aorig = atomic_and(aPtr, aarg);
649 T oorig = atomic_or(aPtr, oarg);
650 T adiff = (T)((aorig & aarg) - aorig);
651 T odiff = (T)((oorig | oarg) - oorig);
652 aT->iDiff += adiff + odiff;
653 T axor = (T)((aorig & aarg) ^ aorig);
654 T oxor = (T)((oorig | oarg) ^ oorig);
655 aT->iXor ^= axor ^ oxor;
659 template<class T> TInt DoAxo(TAny* aPtr, TPerThread* aT, TAtomicAction& aA, T*)
661 typename TRmw2Fn<T>::F atomic = (typename TRmw2Fn<T>::F)AtomicFuncPtr[aA.iIndex];
664 T orig = atomic(aPtr, aarg, xarg);
665 T newv = (T)((orig & aarg) ^ xarg);
666 aT->iDiff += (newv - orig);
667 aT->iXor ^= (newv ^ orig);
671 template<class T> TInt DoThAdd(TAny* aPtr, TPerThread* aT, TAtomicAction& aA, T*)
673 typename TRmw3Fn<T>::F atomic = (typename TRmw3Fn<T>::F)AtomicFuncPtr[aA.iIndex];
677 T orig = atomic(aPtr, thr, arg1, arg2);
678 T newv = (T)((orig >= thr) ? (orig + arg1) : (orig + arg2));
679 aT->iDiff += (orig >= thr) ? arg1 : arg2;
680 aT->iXor ^= (newv ^ orig);
684 template<class T> TInt DoCas(TAny* aPtr, TPerThread* aT, TAtomicAction& aA, T*)
686 typename TCasFn<T>::F atomic = (typename TCasFn<T>::F)AtomicFuncPtr[aA.iIndex];
687 T orig = *(const volatile T*)aPtr;
690 TUint32 fails = 0xffffffffu;
693 newv = Transform<T>::F(orig);
694 done = atomic(aPtr, &orig, newv);
696 aT->iFailCount += fails;
698 aT->iXor ^= (newv ^ orig);
702 volatile TUint Dummy;
703 extern "C" TInt DoAtomicAction(TAny* aPtr, TPerThread* aT, TAtomicAction& aA)
705 TUint x = TUint(aT)*0x9E3779B9u;
709 TInt r = KErrNotSupported;
710 TUint attr = FuncAttr[aA.iIndex];
711 TUint func = ATTR_TO_FUNC(attr);
712 TUint size = ATTR_TO_SIZE(attr);
723 case EAtomicFuncSWP: r=DoSwap<TUint8>(aPtr, aT, aA, dummy); break;
724 case EAtomicFuncADD: r=DoAdd<TUint8>(aPtr, aT, aA, dummy); break;
725 case EAtomicFuncAND: r=DoAndOr<TUint8>(aPtr, aT, aA, dummy); break;
726 case EAtomicFuncXOR: r=DoXor<TUint8>(aPtr, aT, aA, dummy); break;
727 case EAtomicFuncAXO: r=DoAxo<TUint8>(aPtr, aT, aA, dummy); break;
728 case EAtomicFuncTAU: r=DoThAdd<TUint8>(aPtr, aT, aA, dummy); break;
729 case EAtomicFuncTAS: r=DoThAdd<TInt8>(aPtr, aT, aA, sdummy); break;
730 case EAtomicFuncCAS: r=DoCas<TUint8>(aPtr, aT, aA, dummy); break;
738 TUint16* dummy = &xx;
740 TInt16* sdummy = &yy;
743 case EAtomicFuncSWP: r=DoSwap<TUint16>(aPtr, aT, aA, dummy); break;
744 case EAtomicFuncADD: r=DoAdd<TUint16>(aPtr, aT, aA, dummy); break;
745 case EAtomicFuncAND: r=DoAndOr<TUint16>(aPtr, aT, aA, dummy); break;
746 case EAtomicFuncXOR: r=DoXor<TUint16>(aPtr, aT, aA, dummy); break;
747 case EAtomicFuncAXO: r=DoAxo<TUint16>(aPtr, aT, aA, dummy); break;
748 case EAtomicFuncTAU: r=DoThAdd<TUint16>(aPtr, aT, aA, dummy); break;
749 case EAtomicFuncTAS: r=DoThAdd<TInt16>(aPtr, aT, aA, sdummy); break;
750 case EAtomicFuncCAS: r=DoCas<TUint16>(aPtr, aT, aA, dummy); break;
758 TUint32* dummy = &xx;
760 TInt32* sdummy = &yy;
763 case EAtomicFuncSWP: r=DoSwap<TUint32>(aPtr, aT, aA, dummy); break;
764 case EAtomicFuncADD: r=DoAdd<TUint32>(aPtr, aT, aA, dummy); break;
765 case EAtomicFuncAND: r=DoAndOr<TUint32>(aPtr, aT, aA, dummy); break;
766 case EAtomicFuncXOR: r=DoXor<TUint32>(aPtr, aT, aA, dummy); break;
767 case EAtomicFuncAXO: r=DoAxo<TUint32>(aPtr, aT, aA, dummy); break;
768 case EAtomicFuncTAU: r=DoThAdd<TUint32>(aPtr, aT, aA, dummy); break;
769 case EAtomicFuncTAS: r=DoThAdd<TInt32>(aPtr, aT, aA, sdummy); break;
770 case EAtomicFuncCAS: r=DoCas<TUint32>(aPtr, aT, aA, dummy); break;
778 TUint64* dummy = &xx;
780 TInt64* sdummy = &yy;
783 case EAtomicFuncSWP: r=DoSwap<TUint64>(aPtr, aT, aA, dummy); break;
784 case EAtomicFuncADD: r=DoAdd<TUint64>(aPtr, aT, aA, dummy); break;
785 case EAtomicFuncAND: r=DoAndOr<TUint64>(aPtr, aT, aA, dummy); break;
786 case EAtomicFuncXOR: r=DoXor<TUint64>(aPtr, aT, aA, dummy); break;
787 case EAtomicFuncAXO: r=DoAxo<TUint64>(aPtr, aT, aA, dummy); break;
788 case EAtomicFuncTAU: r=DoThAdd<TUint64>(aPtr, aT, aA, dummy); break;
789 case EAtomicFuncTAS: r=DoThAdd<TInt64>(aPtr, aT, aA, sdummy); break;
790 case EAtomicFuncCAS: r=DoCas<TUint64>(aPtr, aT, aA, dummy); break;