aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArmando Montanez <amontanez@google.com>2021-04-16 09:52:26 -0700
committerCQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com>2021-04-16 20:25:10 +0000
commit58f22dc65f55831b65613da1abd14215fdcebb96 (patch)
tree4e8426aa6c7f70dc85458e99d7d57daea56ac747
parenta082d7fc6a0542c4e3c7361dd99b2362379f1685 (diff)
downloadpigweed-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.gn5
-rw-r--r--pw_persistent_ram/docs.rst11
-rw-r--r--pw_persistent_ram/persistent_test.cc38
-rw-r--r--pw_persistent_ram/public/pw_persistent_ram/persistent.h21
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);
}