diff --git a/libpurgeablemem/common/include/pm_util.h b/libpurgeablemem/common/include/pm_util.h index 67ca33f..9442325 100644 --- a/libpurgeablemem/common/include/pm_util.h +++ b/libpurgeablemem/common/include/pm_util.h @@ -34,6 +34,9 @@ extern "C" { #define MAP_USEREXPTE 0x08 #define PAGE_SHIFT 12 +#ifdef PAGE_SIZE +#undef PAGE_SIZE +#endif #define PAGE_SIZE (1 << PAGE_SHIFT) /* diff --git a/libpurgeablemem/cpp/src/purgeable_mem.cpp b/libpurgeablemem/cpp/src/purgeable_mem.cpp index c379327..8a75613 100644 --- a/libpurgeablemem/cpp/src/purgeable_mem.cpp +++ b/libpurgeablemem/cpp/src/purgeable_mem.cpp @@ -87,11 +87,9 @@ bool PurgeableMem::BeginRead() bool succ = false; bool ret = false; HILOG_DEBUG(LOG_CORE, "%{public}s %{public}s", __func__, ToString_().c_str()); - IF_NULL_LOG_ACTION(dataPtr_, "dataPtr is nullptr in BeginRead", return false); IF_NULL_LOG_ACTION(pageTable_, "pageTable_ is nullptr in BeginRead", return false); IF_NULL_LOG_ACTION(builder_, "builder_ is nullptr in BeginRead", return false); - pageTable_->GetUxpte((uint64_t)dataPtr_, dataSizeInput_); PMState err = PM_OK; while (true) { @@ -242,9 +240,10 @@ bool PurgeableMem::BuildContent_() inline std::string PurgeableMem::ToString_() const { - return "dataAddr:" + std::to_string((unsigned long long)dataPtr_) + - " dataSizeInput:" + std::to_string(dataSizeInput_) + - " " + pageTable_->ToString(); + std::string dataptrStr = dataPtr_ ? std::to_string((unsigned long long)dataPtr_) : "0"; + std::string pageTableStr = pageTable_ ? pageTable_->ToString() : "0"; + return "dataAddr:" + dataptrStr + " dataSizeInput:" + std::to_string(dataSizeInput_) + + " " + pageTableStr; } } /* namespace PurgeableMem */ } /* namespace OHOS */ diff --git a/libpurgeablemem/cpp/src/ux_page_table.cpp b/libpurgeablemem/cpp/src/ux_page_table.cpp index d3727e4..d58e2b1 100644 --- a/libpurgeablemem/cpp/src/ux_page_table.cpp +++ b/libpurgeablemem/cpp/src/ux_page_table.cpp @@ -71,7 +71,8 @@ bool UxPageTable::CheckPresent(uint64_t addr, size_t len) std::string UxPageTable::ToString() const { - return "uxptAddr: " + std::to_string((unsigned long long)uxpt_); + std::string uxptStr = uxpt_ ? std::to_string((unsigned long long)uxpt_) : "0"; + return "uxptAddr: " + uxptStr; } } /* namespace PurgeableMem */ } /* namespace OHOS */ diff --git a/libpurgeablemem/test/purgeable_cpp_test.cpp b/libpurgeablemem/test/purgeable_cpp_test.cpp index c9f25e2..633893e 100644 --- a/libpurgeablemem/test/purgeable_cpp_test.cpp +++ b/libpurgeablemem/test/purgeable_cpp_test.cpp @@ -43,12 +43,15 @@ public: bool Build(void *data, size_t size) { + if (size <= 0) { + return true; + } char *str = (char *)data; size_t len = 0; for (char ch = start; ch <= end && len < size; ch++) { str[len++] = ch; } - str[len] = 0; + str[size - 1] = 0; std::cout << "rebuild addr("<< (unsigned long long)str <<") " << start << "~" << end << ", data=[" << str << "]" << std::endl; return true; @@ -93,6 +96,36 @@ private: char from, to; }; +class TestBigDataBuilder : public PurgeableMemBuilder { +public: + explicit TestBigDataBuilder(char target) + { + this->target = target; + } + + bool Build(void *data, size_t size) + { + if (size <= 0) { + return true; + } + char *str = (char *)data; + size_t len = 0; + for (char ch = target; len < size;) { + str[len++] = ch; + } + str[size - 1] = 0; + return true; + } + + ~TestBigDataBuilder() + { + std::cout << "~TestBigDataBuilder" << std::endl; + } + +private: + char target; +}; + class PurgeableCppTest : public testing::Test { public: static void SetUpTestCase(); @@ -239,6 +272,183 @@ HWTEST_F(PurgeableCppTest, ReadWriteTest, TestSize.Level1) pobj = nullptr; } +HWTEST_F(PurgeableCppTest, MutiPageReadTest, TestSize.Level1) +{ + char alphabet[4098]; + size_t len = 0; + for (char ch = 'A'; len < 4098;) { + alphabet[len++] = ch; + } + alphabet[4097] = 0; + std::unique_ptr builder = std::make_unique('A'); + PurgeableMem *pobj = new PurgeableMem(4098, std::move(builder)); + + std::thread reclaimThread(LoopReclaimPurgeable, (unsigned int)(-1)); + pthread_t reclaimPid = reclaimThread.native_handle(); + reclaimThread.detach(); + + unsigned int loopCount = 3; + /* loop read content */ + for (unsigned int i = 0; i < loopCount; i++) { + if (!pobj->BeginRead()) { + std::cout << __func__ << ": ERROR! BeginRead failed." << std::endl; + continue; + } + ASSERT_STREQ(alphabet, (char *)(pobj->GetContent())); + pobj->EndRead(); + } + + pthread_cancel(reclaimPid); /* destroy reclaimThread */ + delete pobj; + pobj = nullptr; +} + +HWTEST_F(PurgeableCppTest, MutiPageWriteTest, TestSize.Level1) +{ + char alphabet[4098]; + size_t len = 0; + for (char ch = 'C'; len < 4098;) { + alphabet[len++] = ch; + } + alphabet[4097] = 0; + std::unique_ptr builder = std::make_unique('A'); + PurgeableMem *pobj = new PurgeableMem(4098, std::move(builder)); + + std::thread reclaimThread(LoopReclaimPurgeable, (unsigned int)(-1)); + pthread_t reclaimPid = reclaimThread.native_handle(); + reclaimThread.detach(); + + std::unique_ptr modA2B = std::make_unique('A', 'B'); + std::unique_ptr modB2C = std::make_unique('B', 'C'); + ModifyPurgMemByBuilder(pobj, std::move(modA2B)); + ModifyPurgMemByBuilder(pobj, std::move(modB2C)); + + if (pobj->BeginRead()) { + ASSERT_STREQ(alphabet, (char *)(pobj->GetContent())); + pobj->EndRead(); + } else { + std::cout << __func__ << ": ERROR! BeginRead failed." << std::endl; + } + + pthread_cancel(reclaimPid); /* destroy reclaimThread */ + delete pobj; + pobj = nullptr; + LoopReclaimPurgeable(3); +} + +HWTEST_F(PurgeableCppTest, MutiPageReadWriteTest, TestSize.Level1) +{ + char alphabet[4098]; + size_t len = 0; + for (char ch = 'D'; len < 4098;) { + alphabet[len++] = ch; + } + alphabet[4097] = 0; + std::unique_ptr builder = std::make_unique('A'); + PurgeableMem *pobj = new PurgeableMem(4098, std::move(builder)); + /* loop reclaim thread */ + std::thread reclaimThread(LoopReclaimPurgeable, (unsigned int)(-1)); + pthread_t reclaimPid = reclaimThread.native_handle(); + reclaimThread.detach(); + /* loop read thread */ + std::thread readThread(LoopPrintAlphabet, pobj, (unsigned int)(-1)); + pthread_t readPid = readThread.native_handle(); + readThread.detach(); + + std::unique_ptr modA2B = std::make_unique('A', 'B'); + std::unique_ptr modB2C = std::make_unique('B', 'C'); + std::unique_ptr modC2D = std::make_unique('C', 'D'); + ModifyPurgMemByBuilder(pobj, std::move(modA2B)); + ModifyPurgMemByBuilder(pobj, std::move(modB2C)); + ModifyPurgMemByBuilder(pobj, std::move(modC2D)); + + if (pobj->BeginRead()) { + ASSERT_STREQ(alphabet, (char *)(pobj->GetContent())); + pobj->EndRead(); + } else { + std::cout << __func__ << ": ERROR! BeginRead failed." << std::endl; + } + + pthread_cancel(readPid); /* destroy readThread */ + pthread_cancel(reclaimPid); /* destroy reclaimThread */ + std::this_thread::sleep_for(std::chrono::seconds(2 * PRINT_INTERVAL_SECONDS)); + delete pobj; + pobj = nullptr; +} + +HWTEST_F(PurgeableCppTest, MutiMorePageReadWriteTest, TestSize.Level1) +{ + char alphabet[8194]; + size_t len = 0; + for (char ch = 'D'; len < 8194;) { + alphabet[len++] = ch; + } + alphabet[8193] = 0; + std::unique_ptr builder = std::make_unique('A'); + PurgeableMem *pobj = new PurgeableMem(8194, std::move(builder)); + /* loop reclaim thread */ + std::thread reclaimThread(LoopReclaimPurgeable, (unsigned int)(-1)); + pthread_t reclaimPid = reclaimThread.native_handle(); + reclaimThread.detach(); + /* loop read thread */ + std::thread readThread(LoopPrintAlphabet, pobj, (unsigned int)(-1)); + pthread_t readPid = readThread.native_handle(); + readThread.detach(); + + std::unique_ptr modA2B = std::make_unique('A', 'B'); + std::unique_ptr modB2C = std::make_unique('B', 'C'); + std::unique_ptr modC2D = std::make_unique('C', 'D'); + ModifyPurgMemByBuilder(pobj, std::move(modA2B)); + ModifyPurgMemByBuilder(pobj, std::move(modB2C)); + ModifyPurgMemByBuilder(pobj, std::move(modC2D)); + + if (pobj->BeginRead()) { + ASSERT_STREQ(alphabet, (char *)(pobj->GetContent())); + pobj->EndRead(); + } else { + std::cout << __func__ << ": ERROR! BeginRead failed." << std::endl; + } + + pthread_cancel(readPid); /* destroy readThread */ + pthread_cancel(reclaimPid); /* destroy reclaimThread */ + std::this_thread::sleep_for(std::chrono::seconds(2 * PRINT_INTERVAL_SECONDS)); + delete pobj; + pobj = nullptr; +} + +HWTEST_F(PurgeableCppTest, InvalidInputSizeTest, TestSize.Level1) +{ + std::unique_ptr builder = std::make_unique('A', 'Z'); + PurgeableMem *pobj = new PurgeableMem(0, std::move(builder)); + std::thread reclaimThread(LoopReclaimPurgeable, (unsigned int)(-1)); + pthread_t reclaimPid = reclaimThread.native_handle(); + reclaimThread.detach(); + bool ret = pobj->BeginRead(); + + EXPECT_EQ(ret, false); + + pthread_cancel(reclaimPid); /* destroy reclaimThread */ + delete pobj; + pobj = nullptr; + LoopReclaimPurgeable(3); +} + +HWTEST_F(PurgeableCppTest, InvalidInputBuilderTest, TestSize.Level1) +{ + PurgeableMem *pobj = new PurgeableMem(27, nullptr); + std::thread reclaimThread(LoopReclaimPurgeable, (unsigned int)(-1)); + pthread_t reclaimPid = reclaimThread.native_handle(); + reclaimThread.detach(); + bool ret = pobj->BeginRead(); + + EXPECT_EQ(ret, false); + + pthread_cancel(reclaimPid); /* destroy reclaimThread */ + delete pobj; + pobj = nullptr; + LoopReclaimPurgeable(3); +} + void LoopPrintAlphabet(PurgeableMem *pdata, unsigned int loopCount) { std::cout << "inter " << __func__ << std::endl;