diff --git a/Source/Core/Common/Flag.h b/Source/Core/Common/Flag.h new file mode 100644 index 0000000000..9b8fa3e28e --- /dev/null +++ b/Source/Core/Common/Flag.h @@ -0,0 +1,48 @@ +// Copyright 2014 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +// Abstraction for a simple flag that can be toggled in a multithreaded way. +// It exposes a very simple API: +// * Set(bool = true): sets the Flag +// * IsSet(): tests if the flag is set +// * Clear(): clears the flag (equivalent to Set(false)). + +#pragma once + +#include + +namespace Common { + +class Flag final +{ +public: + // Declared as explicit since we do not want "= true" to work on a flag + // object - it should be made explicit that a flag is *not* a normal + // variable. + explicit Flag(bool initial_value = false) : m_val(initial_value) {} + + void Set(bool val = true) + { + m_val.store(val); + } + + void Clear() + { + Set(false); + } + + bool IsSet() const + { + return m_val.load(); + } + +private: + // We are not using std::atomic_bool here because MSVC sucks as of VC++ + // 2013 and does not implement the std::atomic_bool(bool) constructor. + // + // Re-evaluate next time we upgrade that piece of shit. + std::atomic m_val; +}; + +} // namespace Common diff --git a/Source/UnitTests/Common/CMakeLists.txt b/Source/UnitTests/Common/CMakeLists.txt index 78f9938e1c..11fa2c57e0 100644 --- a/Source/UnitTests/Common/CMakeLists.txt +++ b/Source/UnitTests/Common/CMakeLists.txt @@ -2,4 +2,5 @@ add_dolphin_test(BitFieldTest BitFieldTest.cpp common) add_dolphin_test(CommonFuncsTest CommonFuncsTest.cpp common) add_dolphin_test(FifoQueueTest FifoQueueTest.cpp common) add_dolphin_test(FixedSizeQueueTest FixedSizeQueueTest.cpp common) +add_dolphin_test(FlagTest FlagTest.cpp common) add_dolphin_test(MathUtilTest MathUtilTest.cpp common) diff --git a/Source/UnitTests/Common/FlagTest.cpp b/Source/UnitTests/Common/FlagTest.cpp new file mode 100644 index 0000000000..ef73d27728 --- /dev/null +++ b/Source/UnitTests/Common/FlagTest.cpp @@ -0,0 +1,60 @@ +// Copyright 2014 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include +#include + +#include "Common/Flag.h" + +using Common::Flag; + +TEST(Flag, Simple) +{ + Flag f; + EXPECT_FALSE(f.IsSet()); + + f.Set(); + EXPECT_TRUE(f.IsSet()); + + f.Clear(); + EXPECT_FALSE(f.IsSet()); + + f.Set(false); + EXPECT_FALSE(f.IsSet()); + + Flag f2(true); + EXPECT_TRUE(f2.IsSet()); +} + +TEST(Flag, MultiThreaded) +{ + Flag f; + int count = 0; + const int ITERATIONS_COUNT = 100000; + + auto setter = [&f]() { + for (int i = 0; i < ITERATIONS_COUNT; ++i) + { + while (f.IsSet()); + f.Set(); + } + }; + + auto clearer = [&f, &count]() { + for (int i = 0; i < ITERATIONS_COUNT; ++i) + { + while (!f.IsSet()); + count++; + f.Clear(); + } + }; + + std::thread setter_thread(setter); + std::thread clearer_thread(clearer); + + setter_thread.join(); + clearer_thread.join(); + + EXPECT_EQ(ITERATIONS_COUNT, count); +}