[fzl][VmoMapper] Make VmoMapper movable.
Make the VmoMapper helper object movable. Now, it may be...
++ Embedded and moved around with fbl::move
++ Heap allocated and moved around with fbl::unique_ptr
++ Heap allocated and managed with fbl::RefPtr
Test: new unit tests
Change-Id: I94be5f2ce5b29fa25c33d5cf0de5b2478e690f4d
diff --git a/system/ulib/fzl/include/lib/fzl/vmo-mapper.h b/system/ulib/fzl/include/lib/fzl/vmo-mapper.h
index b8c87f6..d02f889 100644
--- a/system/ulib/fzl/include/lib/fzl/vmo-mapper.h
+++ b/system/ulib/fzl/include/lib/fzl/vmo-mapper.h
@@ -16,6 +16,25 @@
public:
VmoMapper() = default;
~VmoMapper() { Unmap(); }
+ DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(VmoMapper);
+
+ // Move support
+ VmoMapper(VmoMapper&& other) {
+ *this = fbl::move(other);
+ }
+
+ VmoMapper& operator=(VmoMapper&& other) {
+ Unmap();
+ vmar_manager_ = fbl::move(other.vmar_manager_);
+
+ start_ = other.start_;
+ other.start_ = nullptr;
+
+ size_ = other.size_;
+ other.size_ = 0;
+
+ return *this;
+ }
// Create a new VMO and map it into our address space using the provided map
// flags and optional target VMAR. If requested, return the created VMO
@@ -62,9 +81,6 @@
void* start() const { return start_; }
uint64_t size() const { return size_; }
- // suppress default constructors
- DISALLOW_COPY_ASSIGN_AND_MOVE(VmoMapper);
-
private:
zx_status_t CheckReadyToMap(const fbl::RefPtr<VmarManager>& vmar_manager);
zx_status_t InternalMap(const zx::vmo& vmo,
diff --git a/system/utest/libfzl/vmo-vmar-tests.cpp b/system/utest/libfzl/vmo-vmar-tests.cpp
index 59ab4f5..d06e549 100644
--- a/system/utest/libfzl/vmo-vmar-tests.cpp
+++ b/system/utest/libfzl/vmo-vmar-tests.cpp
@@ -5,6 +5,7 @@
#include <lib/fzl/vmar-manager.h>
#include <lib/fzl/vmo-mapper.h>
#include <unittest/unittest.h>
+#include <zircon/limits.h>
#include <zircon/rights.h>
#include "vmo-probe.h"
@@ -284,6 +285,79 @@
END_TEST;
}
+bool vmo_mapper_move_test() {
+ BEGIN_TEST;
+
+ constexpr uint32_t ACCESS_FLAGS = ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE;
+ void* addr;
+ size_t size;
+ {
+ // Create two mappers, and make sure neither has mapped anything.
+ VmoMapper mapper1, mapper2;
+
+ ASSERT_NULL(mapper1.start());
+ ASSERT_EQ(mapper1.size(), 0);
+ ASSERT_NULL(mapper2.start());
+ ASSERT_EQ(mapper2.size(), 0);
+
+ // Create and map a page in mapper 1, make sure we can probe it.
+ zx_status_t res;
+ res = mapper1.CreateAndMap(ZX_PAGE_SIZE, ACCESS_FLAGS);
+ addr = mapper1.start();
+ size = mapper1.size();
+
+ ASSERT_EQ(res, ZX_OK);
+ ASSERT_TRUE(vmo_probe::probe_verify_region(addr, size, ACCESS_FLAGS));
+
+ // Move the mapping from mapper1 into mapper2 using assignment. Make sure
+ // the region is still mapped and has not moved in our address space.
+ mapper2 = fbl::move(mapper1);
+
+ ASSERT_NULL(mapper1.start());
+ ASSERT_EQ(mapper1.size(), 0);
+ ASSERT_EQ(mapper2.start(), addr);
+ ASSERT_EQ(mapper2.size(), size);
+ ASSERT_TRUE(vmo_probe::probe_verify_region(addr, size, ACCESS_FLAGS));
+
+ // Now do the same thing, but this time move using construction.
+ VmoMapper mapper3(fbl::move(mapper2));
+
+ ASSERT_NULL(mapper2.start());
+ ASSERT_EQ(mapper2.size(), 0);
+ ASSERT_EQ(mapper3.start(), addr);
+ ASSERT_EQ(mapper3.size(), size);
+ ASSERT_TRUE(vmo_probe::probe_verify_region(addr, size, ACCESS_FLAGS));
+
+ // Map a new region into mapper1, make sure it is OK.
+ res = mapper1.CreateAndMap(ZX_PAGE_SIZE, ACCESS_FLAGS);
+ void* second_addr = mapper1.start();
+ size_t second_size = mapper1.size();
+
+ ASSERT_EQ(res, ZX_OK);
+ ASSERT_TRUE(vmo_probe::probe_verify_region(second_addr, second_size, ACCESS_FLAGS));
+
+ // Now, move mapper3 on top of mapper1 via assignment and make sure that
+ // mapper1's old region is properly unmapped while mapper3's contents remain
+ // mapped and are properly moved.
+ mapper1 = fbl::move(mapper3);
+
+ ASSERT_NULL(mapper3.start());
+ ASSERT_EQ(mapper3.size(), 0);
+ ASSERT_EQ(mapper1.start(), addr);
+ ASSERT_EQ(mapper1.size(), size);
+ ASSERT_TRUE(vmo_probe::probe_verify_region(addr, size, ACCESS_FLAGS));
+ ASSERT_TRUE(vmo_probe::probe_verify_region(second_addr, second_size, 0));
+ }
+
+ // Finally, now that we have left the scope, the original mapping that we
+ // have been moving around should be gone by now.
+ ASSERT_NONNULL(addr);
+ ASSERT_EQ(size, ZX_PAGE_SIZE);
+ ASSERT_TRUE(vmo_probe::probe_verify_region(addr, size, 0));
+
+ END_TEST;
+}
+
} // namespace
BEGIN_TEST_CASE(vmo_mapper_vmar_manager_tests)
@@ -293,4 +367,5 @@
RUN_NAMED_TEST("vmo_map_root", vmo_map_root_test)
RUN_NAMED_TEST("vmo_map_sub_vmar", vmo_map_sub_vmar_test)
RUN_NAMED_TEST("vmo_map_sub_sub_vmar", vmo_map_sub_sub_vmar_test)
+RUN_NAMED_TEST("vmo_mapper_move_test", vmo_mapper_move_test)
END_TEST_CASE(vmo_mapper_vmar_manager_tests)