/* Integration test kernel for map_handle create and close (C) 2016-2017 Niall Douglas (8 commits) File Created: Aug 2016 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License in the accompanying file Licence.txt or at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Distributed under the Boost Software License, Version 1.0. (See accompanying file Licence.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #include "kernel_map_handle.cpp.hpp" template inline void map_handle_create_close_(U &&f) { using namespace KERNELTEST_V1_NAMESPACE; using LLFIO_V2_NAMESPACE::result; using LLFIO_V2_NAMESPACE::file_handle; using LLFIO_V2_NAMESPACE::section_handle; using LLFIO_V2_NAMESPACE::map_handle; // Create a temporary file and put some text into it file_handle temph; auto boundf = [&](auto... pars) { return f(temph, pars...); }; // clang-format off static const auto permuter(st_permute_parameters< result, parameters< typename map_handle::size_type, typename section_handle::flag >, precondition::filesystem_setup_parameters, postcondition::custom_parameters >( { { success(),{ 4096, section_handle::flag::none },{ "_" },{ false } }, { success(),{ 4096, section_handle::flag::read },{ "_" },{ false } }, { success(),{ 4096, section_handle::flag::write },{ "_" },{ false } }, { success(),{ 4096, section_handle::flag::cow },{ "_" },{ false } }, //{ success(),{ 4096, section_handle::flag::execute },{ "_" },{ false } }, { success(),{ 4096, section_handle::flag::write|section_handle::flag::nocommit },{ "_" },{ false } }, { success(),{ 4096, section_handle::flag::write|section_handle::flag::prefault },{ "_" },{ false } }, //{ success(),{ 4096, section_handle::flag::write|section_handle::flag::executable },{ "_" },{ false } }, { success(),{ 0, section_handle::flag::none },{ "_" },{ true } }, { success(),{ 0, section_handle::flag::read },{ "_" },{ true } }, { success(),{ 0, section_handle::flag::write },{ "_" },{ true } }, { success(),{ 0, section_handle::flag::cow },{ "_" },{ true } }, //{ success(),{ 0, section_handle::flag::execute },{ "_" },{ true } }, { success(),{ 0, section_handle::flag::write | section_handle::flag::nocommit },{ "_" },{ true } }, { success(),{ 0, section_handle::flag::write | section_handle::flag::prefault },{ "_" },{ true } }, //{ success(),{ 0, section_handle::flag::write|section_handle::flag::executable },{ "_" },{ true } }, }, precondition::filesystem_setup(), postcondition::custom( [&](auto &permuter, auto &testreturn, size_t idx, int use_file_backing) { if (use_file_backing) { // Create a temporary backing file temph = file_handle::file({}, "tempfile", file_handle::mode::write, file_handle::creation::if_needed).value(); temph.write(0, { {reinterpret_cast("I am some file data"), 19} }).value(); } else { // Use the page file temph = file_handle(); } return std::make_tuple(std::ref(permuter), std::ref(testreturn), idx, use_file_backing); }, [&](auto tuplestate) { auto &permuter = std::get<0>(tuplestate); auto &testreturn = *std::get<1>(tuplestate); size_t idx = std::get<2>(tuplestate); int use_file_backing = std::get<3>(tuplestate); map_handle maph; if (testreturn) { maph = std::move(testreturn.value()); } // Need to close the map and any backing file as otherwise filesystem_setup won't be able to clear up the working dir on Windows auto onexit = LLFIO_V2_NAMESPACE::undoer([&]{ (void) maph.close(); (void) temph.close(); }); //#undef KERNELTEST_CHECK //#define KERNELTEST_CHECK(a, ...) BOOST_CHECK(__VA_ARGS__) if (testreturn) { LLFIO_V2_NAMESPACE::byte *addr = maph.address(); section_handle::flag flags = std::get<1>(std::get<1>(permuter[idx])); KERNELTEST_CHECK(testreturn, maph.length() > 0); KERNELTEST_CHECK(testreturn, addr != nullptr); if (!(flags & section_handle::flag::nocommit) && addr != nullptr) { LLFIO_V2_NAMESPACE::byte buffer[64]; // Make sure the backing file is appearing in the map if (use_file_backing && maph.is_readable()) { KERNELTEST_CHECK(testreturn, !memcmp(addr, "I am some file data", 19)); } // Make sure maph's read() does what it is supposed to if (use_file_backing) { map_handle::buffer_type req{ nullptr, 20 }; auto b = maph.read({ req, 0 }).value(); KERNELTEST_CHECK(testreturn, b[0].data() == addr); KERNELTEST_CHECK(testreturn, b[0].size() == 19); // reads do not read more than the backing length } else { map_handle::buffer_type req{ nullptr, 5000 }; auto b = maph.read({ req, 5 }).value(); KERNELTEST_CHECK(testreturn, b[0].data() == addr+5); // NOLINT KERNELTEST_CHECK(testreturn, b[0].size() == 4091); } // If we are writable, write straight into the map if (maph.is_writable() && addr) { memcpy(addr, "NIALL was here", 14); // Make sure maph's write() works maph.write(1, { {reinterpret_cast("iall"), 4} }); // Make sure data written to the map turns up in the file if (use_file_backing) { temph.read(0, { {buffer, 64} }); // NOLINT if (flags & section_handle::flag::cow) { KERNELTEST_CHECK(testreturn, !memcmp(buffer, "I am some file data", 19)); // NOLINT } else { KERNELTEST_CHECK(testreturn, !memcmp(buffer, "Niall was here data", 19)); // NOLINT } } } // The OS should not auto expand storage to 4Kb if (use_file_backing) { KERNELTEST_CHECK(testreturn, temph.maximum_extent().value() == 19); } } } }, "check mmap") )); // clang-format on auto results = permuter(boundf); check_results_with_boost_test(permuter, results); } KERNELTEST_TEST_KERNEL(unit, llfio, map_handle_create_close, map_handle, "Tests that llfio::map_handle's creation parameters work as expected", map_handle_create_close_(map_handle_create_close::test_kernel_map_handle))