diff options
author | Armando Montanez <amontanez@google.com> | 2021-04-16 09:52:26 -0700 |
---|---|---|
committer | CQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2021-04-16 20:25:10 +0000 |
commit | 58f22dc65f55831b65613da1abd14215fdcebb96 (patch) | |
tree | 4e8426aa6c7f70dc85458e99d7d57daea56ac747 | |
parent | a082d7fc6a0542c4e3c7361dd99b2362379f1685 (diff) | |
download | pigweed-58f22dc65f55831b65613da1abd14215fdcebb96.tar.gz |
pw_persistent_ram: Default construct from mutator
Allows users of a persistent RAM object to optionally default-construct
an object when requesting a Mutator handle.
Change-Id: I228d8afd31ada60414cddf9a9bebc2fd5a908830
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/41340
Pigweed-Auto-Submit: Armando Montanez <amontanez@google.com>
Reviewed-by: Ewout van Bekkum <ewout@google.com>
Commit-Queue: Armando Montanez <amontanez@google.com>
-rw-r--r-- | pw_persistent_ram/BUILD.gn | 5 | ||||
-rw-r--r-- | pw_persistent_ram/docs.rst | 11 | ||||
-rw-r--r-- | pw_persistent_ram/persistent_test.cc | 38 | ||||
-rw-r--r-- | pw_persistent_ram/public/pw_persistent_ram/persistent.h | 21 |
4 files changed, 67 insertions, 8 deletions
diff --git a/pw_persistent_ram/BUILD.gn b/pw_persistent_ram/BUILD.gn index 729656f4e..f99228003 100644 --- a/pw_persistent_ram/BUILD.gn +++ b/pw_persistent_ram/BUILD.gn @@ -47,7 +47,10 @@ pw_test_group("tests") { } pw_test("persistent_test") { - deps = [ ":pw_persistent_ram" ] + deps = [ + ":pw_persistent_ram", + dir_pw_random, + ] sources = [ "persistent_test.cc" ] } diff --git a/pw_persistent_ram/docs.rst b/pw_persistent_ram/docs.rst index 5286c8675..19384bd74 100644 --- a/pw_persistent_ram/docs.rst +++ b/pw_persistent_ram/docs.rst @@ -188,13 +188,14 @@ object's checksum is updated to reflect the changes. // Once this scope ends, we know the persistent object has been updated // to reflect changes. { - auto& mutable_crash_info = persistent_crash_info.mutator(); - vsnprintf(mutable_crash_info.reason, - sizeof(mutable_crash_info.reason), + auto& mutable_crash_info = + persistent_crash_info.mutator(GetterAction::kReset); + vsnprintf(mutable_crash_info->reason, + sizeof(mutable_crash_info->reason), fmt, args); - mutable_crash_info.uptime_ms = system::GetUptimeMs(); - mutable_crash_info.boot_id = system::GetBootId(); + mutable_crash_info->uptime_ms = system::GetUptimeMs(); + mutable_crash_info->boot_id = system::GetBootId(); } // ... } diff --git a/pw_persistent_ram/persistent_test.cc b/pw_persistent_ram/persistent_test.cc index 868ec1dc3..bd3de4f8b 100644 --- a/pw_persistent_ram/persistent_test.cc +++ b/pw_persistent_ram/persistent_test.cc @@ -16,6 +16,7 @@ #include <type_traits> #include "gtest/gtest.h" +#include "pw_random/xor_shift.h" namespace pw::persistent_ram { namespace { @@ -92,6 +93,13 @@ class MutablePersistentTest : public ::testing::Test { // Emulate invalidation of persistent section(s). void ZeroPersistentMemory() { memset(&buffer_, 0, sizeof(buffer_)); } + void RandomFillMemory() { + random::XorShiftStarRng64 rng(0x9ad75); + StatusWithSize sws = rng.Get(std::span<std::byte>( + reinterpret_cast<std::byte*>(&buffer_), sizeof(buffer_))); + ASSERT_TRUE(sws.ok()); + ASSERT_EQ(sws.size(), sizeof(buffer_)); + } // Allocate a chunk of aligned storage that can be independently controlled. std::aligned_storage_t<sizeof(Persistent<Coordinate>), @@ -134,5 +142,35 @@ TEST_F(MutablePersistentTest, DefaultConstructionAndDestruction) { } } +TEST_F(MutablePersistentTest, ResetObject) { + { + // Emulate a boot where the persistent sections were lost and ended up in + // random data. + RandomFillMemory(); + auto& persistent = *(new (&buffer_) Persistent<Coordinate>()); + + // Default construct of a Coordinate. + ASSERT_FALSE(persistent.has_value()); + { + auto mutable_persistent = persistent.mutator(GetterAction::kReset); + mutable_persistent->x = 42; + } + + EXPECT_EQ(42, persistent.value().x); + EXPECT_EQ(0, persistent.value().y); + EXPECT_EQ(0, persistent.value().z); + + persistent.~Persistent(); // Emulate shutdown / global destructors. + } + + { + // Emulate a boot where persistent memory was kept as is. + auto& persistent = *(new (&buffer_) Persistent<Coordinate>()); + ASSERT_TRUE(persistent.has_value()); + EXPECT_EQ(42, persistent.value().x); + EXPECT_EQ(0, persistent.value().y); + } +} + } // namespace } // namespace pw::persistent_ram diff --git a/pw_persistent_ram/public/pw_persistent_ram/persistent.h b/pw_persistent_ram/public/pw_persistent_ram/persistent.h index 556fd53c2..6067d3b03 100644 --- a/pw_persistent_ram/public/pw_persistent_ram/persistent.h +++ b/pw_persistent_ram/public/pw_persistent_ram/persistent.h @@ -24,6 +24,15 @@ namespace pw::persistent_ram { +// Behavior to use when attempting to get a handle to the underlying data stored +// in persistent memory. +enum class GetterAction { + // Default-construct the object before returning a handle. + kReset, + // Assert that the object is valid before returning a handle. + kAssertValid, +}; + // The Persistent class intentionally uses uninitialized memory, which triggers // compiler warnings. Disable those warnings for this file. PW_MODIFY_DIAGNOSTICS_PUSH(); @@ -119,9 +128,17 @@ class Persistent { // Get a mutable handle to the underlying data. // + // Args: + // action: Whether to default-construct the underlying value before + // providing a mutator, or to assert that the object is valid + // without modifying the underlying data. // Precondition: has_value() must be true. - Mutator mutator() { - PW_ASSERT(has_value()); + Mutator mutator(GetterAction action = GetterAction::kAssertValid) { + if (action == GetterAction::kReset) { + emplace(); + } else { + PW_ASSERT(has_value()); + } return Mutator(*this); } |