Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/windirstat/llfio.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiall Douglas (s [underscore] sourceforge {at} nedprod [dot] com) <spamtrap@nedprod.com>2019-10-04 20:34:02 +0300
committerNiall Douglas (s [underscore] sourceforge {at} nedprod [dot] com) <spamtrap@nedprod.com>2019-10-04 20:34:02 +0300
commitdbf76606c10d325eee673b82173ec0897e0db3ff (patch)
tree1a22996563a4929707d4e468a7c70a20bfc6945d
parent1849f4e63413ea6f79ad50f18fba4c91bf7b28dd (diff)
A watershed: LLFIO finally works with clang coroutines! All unit tests pass.
-rw-r--r--CMakeLists.txt71
-rw-r--r--include/llfio/revision.hpp6
-rw-r--r--include/llfio/v2.0/async_file_handle.hpp4
-rw-r--r--include/llfio/v2.0/detail/impl/posix/directory_handle.ipp2
-rw-r--r--include/llfio/v2.0/io_service.hpp28
-rw-r--r--include/llfio/v2.0/status_code.hpp26
-rw-r--r--test/tests/coroutines.cpp39
7 files changed, 120 insertions, 56 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2757afd5..8f36ac09 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -51,6 +51,8 @@ if(WIN32)
add_subdirectory("include/llfio/ntkernel-error-category" EXCLUDE_FROM_ALL)
endif()
+set(UNIT_TESTS_CXX_VERSION "latest" CACHE STRING "The version of C++ to use in the header-only unit tests")
+
# Make the standard static and shared libraries, and if supported by this compiler, C++ modules
# for both static and shared libraries as well. For the non-C++ module variants, makes the
# interface headers into precompiled headers. Only builds all of them if this is the topmost
@@ -148,12 +150,32 @@ endif()
# Set the library dependencies this library has
all_link_libraries(PUBLIC quickcpplib::hl outcome::hl Threads::Threads)
# Set the system dependencies this library has
+set(USING_LIBCXX_ON_LINUX 0)
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
find_library(libstdcxx_stdcxxfs stdc++fs)
if(libstdcxx_stdcxxfs MATCHES "NOTFOUND")
set(libstdcxx_stdcxxfs -lstdc++fs)
endif()
- all_link_libraries(PUBLIC ${libstdcxx_stdcxxfs} rt)
+ get_target_property(val llfio_dl USING_LIBCXX_ON_LINUX)
+ if(val MATCHES "NOTFOUND")
+ all_link_libraries(PUBLIC ${libstdcxx_stdcxxfs} rt)
+ else()
+ set(USING_LIBCXX_ON_LINUX 1)
+ # We had to use libc++ to get coroutines on Linux, so don't link the filesystem TS
+ target_link_libraries(${PROJECT_NAME}_hl INTERFACE ${libstdcxx_stdcxxfs} rt)
+ target_link_libraries(${PROJECT_NAME}_sl PUBLIC ${libstdcxx_stdcxxfs} rt)
+ foreach(special ${SPECIAL_BUILDS})
+ target_link_libraries(${PROJECT_NAME}_sl-${special} PUBLIC ${libstdcxx_stdcxxfs} rt)
+ endforeach()
+ # Do make libc++ a requirement
+ target_compile_definitions(${PROJECT_NAME}_dl PUBLIC _LIBCPP_NO_EXPERIMENTAL_DEPRECATION_WARNING_FILESYSTEM=1)
+ target_compile_options(${PROJECT_NAME}_dl PUBLIC -stdlib=libc++)
+ target_link_libraries(${PROJECT_NAME}_dl PUBLIC -stdlib=libc++ -lc++abi)
+ foreach(special ${SPECIAL_BUILDS})
+ target_compile_options(${PROJECT_NAME}_dl-${special} PUBLIC -stdlib=libc++)
+ target_link_libraries(${PROJECT_NAME}_dl-${special} PUBLIC -stdlib=libc++ -lc++abi)
+ endforeach()
+ endif()
endif()
if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD" OR APPLE)
find_library(libcxx_cxxexperimental c++experimental)
@@ -207,8 +229,14 @@ if(NOT PROJECT_IS_DEPENDENCY)
)
foreach(test_target ${llfio_TEST_TARGETS})
target_link_libraries(${test_target} PRIVATE kerneltest::hl)
- if(test_target MATCHES "coroutines")
- apply_cxx_coroutines_to(PRIVATE ${test_target})
+ if(test_target MATCHES coroutines)
+ if(USING_LIBCXX_ON_LINUX)
+ if(NOT test_target MATCHES _sl)
+ apply_cxx_coroutines_to(PRIVATE ${test_target})
+ endif()
+ else()
+ apply_cxx_coroutines_to(PRIVATE ${test_target})
+ endif()
endif()
endforeach()
if(MSVC)
@@ -219,6 +247,43 @@ if(NOT PROJECT_IS_DEPENDENCY)
endif()
endforeach()
endif()
+
+ # Turn on latest C++ where possible for the test suite
+ if(UNIT_TESTS_CXX_VERSION STREQUAL "latest")
+ set(LATEST_CXX_FEATURE)
+ foreach(feature ${CMAKE_CXX_COMPILE_FEATURES})
+ if(feature STREQUAL "cxx_std_23")
+ set(LATEST_CXX_FEATURE "cxx_std_23")
+ indented_message(STATUS "NOTE: This compiler claims to support C++ 23, enabling for header-only unit test suite")
+ endif()
+ endforeach()
+ if(NOT LATEST_CXX_FEATURE)
+ foreach(feature ${CMAKE_CXX_COMPILE_FEATURES})
+ if(feature STREQUAL "cxx_std_20")
+ set(LATEST_CXX_FEATURE "cxx_std_20")
+ indented_message(STATUS "NOTE: This compiler claims to support C++ 20, enabling for header-only unit test suite")
+ endif()
+ endforeach()
+ endif()
+ if(NOT LATEST_CXX_FEATURE)
+ foreach(feature ${CMAKE_CXX_COMPILE_FEATURES})
+ if(feature STREQUAL "cxx_std_17")
+ set(LATEST_CXX_FEATURE "cxx_std_17")
+ indented_message(STATUS "NOTE: This compiler claims to support C++ 17, enabling for header-only unit test suite")
+ endif()
+ endforeach()
+ endif()
+ elseif(UNIT_TESTS_CXX_VERSION)
+ set(LATEST_CXX_FEATURE "cxx_std_${UNIT_TESTS_CXX_VERSION}")
+ endif()
+ if(LATEST_CXX_FEATURE)
+ # Turn on latest C++ where possible for the header only test suite
+ foreach(test_target ${llfio_TEST_TARGETS} ${llfio_EXAMPLE_TARGETS})
+ if(test_target MATCHES _hl)
+ target_compile_features(${test_target} PUBLIC ${LATEST_CXX_FEATURE})
+ endif()
+ endforeach()
+ endif()
endif()
# Cache this library's auto scanned sources for later reuse
diff --git a/include/llfio/revision.hpp b/include/llfio/revision.hpp
index 311d81b9..3eece543 100644
--- a/include/llfio/revision.hpp
+++ b/include/llfio/revision.hpp
@@ -1,4 +1,4 @@
// Note the second line of this file must ALWAYS be the git SHA, third line ALWAYS the git SHA update time
-#define LLFIO_PREVIOUS_COMMIT_REF 7b5a2b5fa56cd53959e573a4750e09fe76030284
-#define LLFIO_PREVIOUS_COMMIT_DATE "2019-09-25 17:14:32 +00:00"
-#define LLFIO_PREVIOUS_COMMIT_UNIQUE 7b5a2b5f
+#define LLFIO_PREVIOUS_COMMIT_REF 1849f4e63413ea6f79ad50f18fba4c91bf7b28dd
+#define LLFIO_PREVIOUS_COMMIT_DATE "2019-10-04 14:20:39 +00:00"
+#define LLFIO_PREVIOUS_COMMIT_UNIQUE 1849f4e6
diff --git a/include/llfio/v2.0/async_file_handle.hpp b/include/llfio/v2.0/async_file_handle.hpp
index b7133c61..853afc8e 100644
--- a/include/llfio/v2.0/async_file_handle.hpp
+++ b/include/llfio/v2.0/async_file_handle.hpp
@@ -505,7 +505,7 @@ public:
using file_handle::write;
LLFIO_HEADERS_ONLY_VIRTUAL_SPEC io_result<const_buffers_type> write(io_request<const_buffers_type> reqs, deadline d = deadline()) noexcept override;
-#if LLFIO_HAVE_COROUTINES || defined(DOXYGEN_IS_IN_THE_HOUSE)
+#if defined(LLFIO_ENABLE_COROUTINES) || defined(DOXYGEN_IS_IN_THE_HOUSE)
private:
template <class BuffersType> class awaitable_state
{
@@ -731,7 +731,7 @@ template <class CompletionRoutine> inline result<async_file_handle::io_state_ptr
{
return self.async_write(std::forward<decltype(reqs)>(reqs), std::forward<decltype(completion)>(completion), std::forward<decltype(mem)>(mem));
}
-#if LLFIO_HAVE_COROUTINES || defined(DOXYGEN_IS_IN_THE_HOUSE)
+#if defined(LLFIO_ENABLE_COROUTINES) || defined(DOXYGEN_IS_IN_THE_HOUSE)
/*! \brief Schedule a read to occur asynchronously.
\return An awaitable, which when `co_await`ed upon, suspends execution of the coroutine
diff --git a/include/llfio/v2.0/detail/impl/posix/directory_handle.ipp b/include/llfio/v2.0/detail/impl/posix/directory_handle.ipp
index dfa79a29..e95bbda5 100644
--- a/include/llfio/v2.0/detail/impl/posix/directory_handle.ipp
+++ b/include/llfio/v2.0/detail/impl/posix/directory_handle.ipp
@@ -26,7 +26,7 @@ http://www.boost.org/LICENSE_1_0.txt)
#include "import.hpp"
#ifdef QUICKCPPLIB_ENABLE_VALGRIND
-#include "../valgrind/memcheck.h" // from quickcpplib include directory
+#include "quickcpplib/valgrind/memcheck.h" // from quickcpplib include directory
#define LLFIO_VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(a, b) VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE((a), (b))
#else
#define LLFIO_VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(a, b)
diff --git a/include/llfio/v2.0/io_service.hpp b/include/llfio/v2.0/io_service.hpp
index 1b8f590b..420836d8 100644
--- a/include/llfio/v2.0/io_service.hpp
+++ b/include/llfio/v2.0/io_service.hpp
@@ -31,30 +31,6 @@ Distributed under the Boost Software License, Version 1.0.
#include <deque>
#include <mutex>
-#if defined(__cpp_coroutines) && !defined(LLFIO_HAVE_COROUTINES)
-#define LLFIO_HAVE_COROUTINES 1
-#endif
-
-#if defined(LLFIO_HAVE_COROUTINES)
-// clang-format off
-#if defined(__has_include)
-#if __has_include(<coroutine>)
-#include <coroutine>
-LLFIO_V2_NAMESPACE_EXPORT_BEGIN
-template<class T = void> using coroutine_handle = std::coroutine_handle<T>;
-LLFIO_V2_NAMESPACE_END
-#elif __has_include(<experimental/coroutine>)
-#include <experimental/coroutine>
-LLFIO_V2_NAMESPACE_EXPORT_BEGIN
-template<class T = void> using coroutine_handle = std::experimental::coroutine_handle<T>;
-LLFIO_V2_NAMESPACE_END
-#else
-#error Cannot use C++ Coroutines without the <coroutine> header!
-#endif
-#endif
-// clang-format on
-#endif
-
#undef _threadid // windows macro splosh sigh
//! \file io_service.hpp Provides io_service.
@@ -291,7 +267,7 @@ public:
*/
template <class U> void post(U &&f) { _post(detail::make_function_ptr<void(io_service *)>(std::forward<U>(f))); }
-#if LLFIO_HAVE_COROUTINES || defined(DOXYGEN_IS_IN_THE_HOUSE)
+#if defined(LLFIO_ENABLE_COROUTINES) || defined(DOXYGEN_IS_IN_THE_HOUSE)
/*! An awaitable suspending execution of this coroutine on the current kernel thread,
and resuming execution on the kernel thread running this i/o service. This is a
convenience wrapper for `post()`.
@@ -309,7 +285,7 @@ public:
bool await_ready() { return false; }
void await_suspend(coroutine_handle<> co)
{
- service->post([co = co](io_service * /*unused*/) { co.resume(); });
+ service->post([co = co](io_service * /*unused*/) mutable { co.resume(); });
}
void await_resume() {}
};
diff --git a/include/llfio/v2.0/status_code.hpp b/include/llfio/v2.0/status_code.hpp
index 03c3c4c9..14a691c6 100644
--- a/include/llfio/v2.0/status_code.hpp
+++ b/include/llfio/v2.0/status_code.hpp
@@ -57,6 +57,12 @@ as that (a) enables safe header only LLFIO on Windows (b) produces better codege
// Bring in a result implementation based on status_code
#include "outcome/experimental/status_result.hpp"
#include "outcome/try.hpp"
+#if __cpp_coroutines
+#include "outcome/experimental/coroutine_support.hpp"
+#ifdef OUTCOME_FOUND_COROUTINE_HEADER
+#define LLFIO_ENABLE_COROUTINES 1
+#endif
+#endif
LLFIO_V2_NAMESPACE_BEGIN
@@ -241,6 +247,13 @@ template <class T> using result = OUTCOME_V2_NAMESPACE::experimental::status_res
using OUTCOME_V2_NAMESPACE::failure;
using OUTCOME_V2_NAMESPACE::in_place_type;
using OUTCOME_V2_NAMESPACE::success;
+#if defined(LLFIO_ENABLE_COROUTINES)
+template <class T> using atomic_eager = OUTCOME_V2_NAMESPACE::experimental::awaitables::atomic_eager<T>;
+template <class T> using atomic_lazy = OUTCOME_V2_NAMESPACE::experimental::awaitables::atomic_lazy<T>;
+template <class T> using eager = OUTCOME_V2_NAMESPACE::experimental::awaitables::eager<T>;
+template <class T> using lazy = OUTCOME_V2_NAMESPACE::experimental::awaitables::lazy<T>;
+template <class T = void> using coroutine_handle = OUTCOME_V2_NAMESPACE::experimental::awaitables::coroutine_handle<T>;
+#endif
//! Choose an errc implementation
using SYSTEM_ERROR2_NAMESPACE::errc;
@@ -341,6 +354,12 @@ LLFIO_V2_NAMESPACE_END
#include "outcome/result.hpp"
#include "outcome/try.hpp"
#include "outcome/utils.hpp"
+#if __cpp_coroutines
+#include "outcome/coroutine_support.hpp"
+#ifdef OUTCOME_FOUND_COROUTINE_HEADER
+#define LLFIO_ENABLE_COROUTINES 1
+#endif
+#endif
LLFIO_V2_NAMESPACE_BEGIN
@@ -562,6 +581,13 @@ inline error_info error_from_exception(std::exception_ptr &&ep = std::current_ex
return error_info(OUTCOME_V2_NAMESPACE::error_from_exception(std::move(ep), not_matched));
}
using OUTCOME_V2_NAMESPACE::in_place_type;
+#if defined(LLFIO_ENABLE_COROUTINES)
+template <class T> using atomic_eager = OUTCOME_V2_NAMESPACE::awaitables::atomic_eager<T>;
+template <class T> using atomic_lazy = OUTCOME_V2_NAMESPACE::awaitables::atomic_lazy<T>;
+template <class T> using eager = OUTCOME_V2_NAMESPACE::awaitables::eager<T>;
+template <class T> using lazy = OUTCOME_V2_NAMESPACE::awaitables::lazy<T>;
+template <class T = void> using coroutine_handle = OUTCOME_V2_NAMESPACE::awaitables::coroutine_handle<T>;
+#endif
static_assert(OUTCOME_V2_NAMESPACE::trait::is_error_code_available_v<error_info>, "error_info is not detected to be an error code");
diff --git a/test/tests/coroutines.cpp b/test/tests/coroutines.cpp
index 08727bbc..dd962116 100644
--- a/test/tests/coroutines.cpp
+++ b/test/tests/coroutines.cpp
@@ -28,7 +28,7 @@ Distributed under the Boost Software License, Version 1.0.
static inline void TestAsyncFileHandleCoroutines()
{
-#if LLFIO_HAVE_COROUTINES
+#if defined(LLFIO_ENABLE_COROUTINES)
//! [coroutines_example]
namespace llfio = LLFIO_V2_NAMESPACE;
@@ -39,10 +39,10 @@ static inline void TestAsyncFileHandleCoroutines()
llfio::async_file_handle h = llfio::async_file_handle::async_file(service, {}, "temp", llfio::file_handle::mode::write, llfio::file_handle::creation::if_needed, llfio::file_handle::caching::only_metadata, llfio::file_handle::flag::unlink_on_first_close).value();
// Truncate to 1Mb
- h.truncate(1024 * 4096);
+ (void) h.truncate(1024 * 4096);
// Launch 8 coroutines, each writing 4Kb of chars 0-8 to every 32Kb block
- auto coroutine = [&h](size_t no) -> std::future<void> {
+ auto coroutine = [&h](size_t no) -> llfio::eager<void> {
std::vector<llfio::byte, llfio::utils::page_allocator<llfio::byte>> buffer(4096);
memset(buffer.data(), (int) ('0' + no), 4096);
llfio::async_file_handle::const_buffer_type bt{buffer.data(), buffer.size()};
@@ -54,7 +54,7 @@ static inline void TestAsyncFileHandleCoroutines()
written.value();
}
};
- std::vector<std::future<void>> coroutines;
+ std::vector<llfio::eager<void>> coroutines;
for(size_t n = 0; n < 8; n++)
{
// Construct each coroutine, initiating the i/o, then suspending.
@@ -63,11 +63,6 @@ static inline void TestAsyncFileHandleCoroutines()
// Pump the i/o, multiplexing the coroutines, until no more work remains.
while(service.run().value())
;
- // Make sure nothing went wrong by fetching the futures.
- for(auto &i : coroutines)
- {
- i.get();
- }
//! [coroutines_example]
// Check that the file has the right contents
@@ -88,24 +83,26 @@ static inline void TestAsyncFileHandleCoroutines()
static inline void TestPostSelfToRunCoroutines()
{
-#if LLFIO_HAVE_COROUTINES
+#if defined(LLFIO_ENABLE_COROUTINES)
namespace llfio = LLFIO_V2_NAMESPACE;
llfio::io_service service;
std::atomic<bool> ready(false);
auto runthreadid = QUICKCPPLIB_NAMESPACE::utils::thread::this_thread_id();
+ // Start a coroutine which immediately suspends
+ auto coroutine = [&]() -> llfio::lazy<void> {
+ auto thisthreadid = QUICKCPPLIB_NAMESPACE::utils::thread::this_thread_id();
+ BOOST_CHECK(thisthreadid != runthreadid);
+ ready = true;
+ co_await llfio::io_service::awaitable_post_to_self(service);
+ thisthreadid = QUICKCPPLIB_NAMESPACE::utils::thread::this_thread_id();
+ BOOST_CHECK(thisthreadid == runthreadid);
+ // std::cout << "Coroutine exiting" << std::endl;
+ ready = false;
+ }();
+ // Run the coroutine's body in another thread
auto coroutinethread = [&]() -> void {
- auto coroutine = [&]() -> std::future<void> {
- auto thisthreadid = QUICKCPPLIB_NAMESPACE::utils::thread::this_thread_id();
- BOOST_CHECK(thisthreadid != runthreadid);
- ready = true;
- co_await llfio::io_service::awaitable_post_to_self(service);
- thisthreadid = QUICKCPPLIB_NAMESPACE::utils::thread::this_thread_id();
- BOOST_CHECK(thisthreadid == runthreadid);
- // std::cout << "Coroutine exiting" << std::endl;
- ready = false;
- };
// std::cout << "Thread waiting on coroutine" << std::endl;
- coroutine().get();
+ coroutine.await_suspend({});
// std::cout << "Thread exiting" << std::endl;
};
auto asynch = std::async(std::launch::async, coroutinethread);