diff --git a/mfbt/Atomics.h b/mfbt/Atomics.h index 03ae7c34f35..ab2b85f19b4 100644 --- a/mfbt/Atomics.h +++ b/mfbt/Atomics.h @@ -934,7 +934,7 @@ class Atomic; * swap method is provided. */ template -class Atomic::value>::Type> +class Atomic::value && !IsSame::value>::Type> : public detail::AtomicBaseIncDec { typedef typename detail::AtomicBaseIncDec Base; @@ -1006,6 +1006,44 @@ class Atomic::value>::Type> Atomic(Atomic& aOther) MOZ_DELETE; }; +/** + * Atomic implementation for boolean types. + * + * The atomic store and load operations and the atomic swap method is provided. + * + * Note: + * + * - sizeof(Atomic) != sizeof(bool) for some implementations of + * bool and/or some implementations of std::atomic. This is allowed in + * [atomic.types.generic]p9. + * + * - It's not obvious whether the 8-bit atomic functions on Windows are always + * inlined or not. If they are not inlined, the corresponding functions in the + * runtime library are not available on Windows XP. This is why we implement + * Atomic with an underlying type of uint32_t. + */ +template +class Atomic + : protected detail::AtomicBase +{ + typedef typename detail::AtomicBase Base; + + public: + MOZ_CONSTEXPR Atomic() : Base() {} + MOZ_CONSTEXPR Atomic(bool aInit) : Base(aInit) {} + + // We provide boolean wrappers for the underlying AtomicBase methods. + operator bool() const { return Base::operator uint32_t(); } + bool operator=(bool aValue) { return Base::operator=(aValue); } + bool exchange(bool aValue) { return Base::exchange(aValue); } + bool compareExchange(bool aOldValue, bool aNewValue) { + return Base::compareExchange(aOldValue, aNewValue); + } + + private: + Atomic(Atomic& aOther) MOZ_DELETE; +}; + } // namespace mozilla #endif /* mozilla_Atomics_h */ diff --git a/mfbt/tests/TestAtomics.cpp b/mfbt/tests/TestAtomics.cpp index 9ed21495655..e1289c8d668 100644 --- a/mfbt/tests/TestAtomics.cpp +++ b/mfbt/tests/TestAtomics.cpp @@ -165,6 +165,36 @@ TestEnumWithOrdering() MOZ_ASSERT(atomic == EnumType_3, "CAS should have changed atomic's value."); } +template +static void +TestBoolWithOrdering() +{ + Atomic atomic(false); + MOZ_ASSERT(atomic == false, "Atomic variable did not initialize"); + + // Test assignment + DebugOnly result; + result = (atomic = true); + MOZ_ASSERT(atomic == true, "Atomic assignment failed"); + MOZ_ASSERT(result == true, "Atomic assignment returned the wrong value"); + + // Test exchange. + atomic = false; + result = atomic.exchange(true); + MOZ_ASSERT(atomic == true, "Atomic exchange did not work"); + MOZ_ASSERT(result == false, "Atomic exchange returned the wrong value"); + + // Test CAS. + atomic = false; + DebugOnly boolResult = atomic.compareExchange(true, false); + MOZ_ASSERT(!boolResult, "CAS should have returned false."); + MOZ_ASSERT(atomic == false, "CAS shouldn't have done anything."); + + boolResult = atomic.compareExchange(false, true); + MOZ_ASSERT(boolResult, "CAS should have succeeded."); + MOZ_ASSERT(atomic == true, "CAS should have changed atomic's value."); +} + template static void TestType() @@ -191,6 +221,14 @@ TestEnum() TestEnumWithOrdering(); } +static void +TestBool() +{ + TestBoolWithOrdering(); + TestBoolWithOrdering(); + TestBoolWithOrdering(); +} + int main() { TestType(); @@ -202,4 +240,5 @@ int main() TestPointer(); TestPointer(); TestEnum(); + TestBool(); }