diff options
author | Niall Douglas (s [underscore] sourceforge {at} nedprod [dot] com) <spamtrap@nedprod.com> | 2017-09-23 18:58:16 +0300 |
---|---|---|
committer | Niall Douglas (s [underscore] sourceforge {at} nedprod [dot] com) <spamtrap@nedprod.com> | 2017-09-23 18:58:16 +0300 |
commit | 8ac7c7fa3908ad353594fb4148971f05e643b056 (patch) | |
tree | 3cffed7fe53c6a2cf5d97580117a5b436f63d448 | |
parent | 15b1a6ff306a8a341bd1eb367d84ce1123f424b9 (diff) |
Add docs for io_service and async_file_handle. Thanks to @jamboree for reminding me to do this.
-rw-r--r-- | Doxyfile | 2 | ||||
m--------- | doc/html | 8 | ||||
-rw-r--r-- | include/afio/revision.hpp | 6 | ||||
-rw-r--r-- | include/afio/v2.0/async_file_handle.hpp | 8 | ||||
-rw-r--r-- | include/afio/v2.0/io_service.hpp | 28 | ||||
-rw-r--r-- | test/tests/coroutines.cpp | 17 |
6 files changed, 57 insertions, 12 deletions
@@ -845,7 +845,7 @@ EXCLUDE_SYMBOLS = detail::* *::detail::* # that contain example code fragments that are included (see the \include # command). -EXAMPLE_PATH = +EXAMPLE_PATH = example test/tests # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and diff --git a/doc/html b/doc/html -Subproject 5c22b279126efb4c2a24b08152616dd80ba1902 +Subproject 3a7ffeb387ac3488c3faccbf4c9b2912a76d99f diff --git a/include/afio/revision.hpp b/include/afio/revision.hpp index abf2823b..ed762471 100644 --- a/include/afio/revision.hpp +++ b/include/afio/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 AFIO_PREVIOUS_COMMIT_REF c3d4648760ebaf31208d89ad245c640725c2ce4b -#define AFIO_PREVIOUS_COMMIT_DATE "2017-09-20 17:17:54 +00:00" -#define AFIO_PREVIOUS_COMMIT_UNIQUE c3d46487 +#define AFIO_PREVIOUS_COMMIT_REF 15b1a6ff306a8a341bd1eb367d84ce1123f424b9 +#define AFIO_PREVIOUS_COMMIT_DATE "2017-09-20 23:20:31 +00:00" +#define AFIO_PREVIOUS_COMMIT_UNIQUE 15b1a6ff diff --git a/include/afio/v2.0/async_file_handle.hpp b/include/afio/v2.0/async_file_handle.hpp index 550c182d..5f876db9 100644 --- a/include/afio/v2.0/async_file_handle.hpp +++ b/include/afio/v2.0/async_file_handle.hpp @@ -51,7 +51,7 @@ AFIO_V2_NAMESPACE_END AFIO_V2_NAMESPACE_EXPORT_BEGIN /*! \class async_file_handle -\brief An asynchronous handle to an open something +\brief An asynchronous handle to an open something. \note Unlike the others, `async_file_handle` defaults to `only_metadata` caching as that is the only use case where using async i/o makes sense given the other options below. @@ -63,7 +63,13 @@ only use case where using async i/o makes sense given the other options below. <tr><td>`mapped_file_handle`</td><td>Most</td><td>Least</td><td>None</td><td>Cannot be used with uncached i/o</td></tr> </table> +\warning i/o initiated by this class MUST be on the same kernel thread as which +created the owning `io_service` which MUST also be the same kernel thread as which +runs the i/o service's `run()` function. + \todo Direct use of `calloc()` ought to be replaced with a user supplied STL allocator instance. + +\snippet coroutines.cpp coroutines_example */ class AFIO_DECL async_file_handle : public file_handle { diff --git a/include/afio/v2.0/io_service.hpp b/include/afio/v2.0/io_service.hpp index e9d8ba05..2eff4c7b 100644 --- a/include/afio/v2.0/io_service.hpp +++ b/include/afio/v2.0/io_service.hpp @@ -33,7 +33,7 @@ Distributed under the Boost Software License, Version 1.0. #undef _threadid // windows macro splosh sigh -//! \file io_service.hpp Provides io_service +//! \file io_service.hpp Provides io_service. // Need to decide which kind of POSIX AIO to use #ifndef _WIN32 @@ -96,6 +96,32 @@ class async_file_handle; /*! \class io_service \brief An asynchronous i/o multiplexer service. + +This service is used in conjunction with `async_file_handle` to multiplex +initating i/o and completing it onto a single kernel thread. +Unlike the `io_service` in ASIO or the Networking TS, this `io_service` +is much simpler, in particular it is single threaded per instance only +i.e. you must run a separate `io_service` instance one per kernel thread +if you wish to run i/o processing across multiple threads. AFIO does not +do this for you (and for good reason, unlike socket i/o, it is generally +unwise to distribute file i/o across kernel threads due to the much +more code executable between user space and physical storage i.e. keeping +processing per CPU core hot in cache delivers outsize benefits compared +to socket i/o). + +Furthermore, you cannot use this i/o service in any way from any +thread other than where it was created. You cannot call its `run()` +from any thread other than where it was created. And you cannot +initiate i/o on an `async_file_handle` from any thread other than where +its owning i/o service was created. + +In other words, keep your i/o service and all associated file handles +on their owning thread. The sole function you can call from another +thread is `post()` which lets you execute some callback in the `run()` +of the owning thread. This lets you schedule i/o from other threads +if you really must do that. + +\snippet coroutines.cpp coroutines_example */ class AFIO_DECL io_service { diff --git a/test/tests/coroutines.cpp b/test/tests/coroutines.cpp index 480df16c..fe23cef0 100644 --- a/test/tests/coroutines.cpp +++ b/test/tests/coroutines.cpp @@ -30,10 +30,18 @@ Distributed under the Boost Software License, Version 1.0. static inline void TestAsyncFileHandleCoroutines() { #ifdef __cpp_coroutines + //! [coroutines_example] namespace afio = AFIO_V2_NAMESPACE; + + // Create an i/o service for this thread afio::io_service service; + + // Create an async file i/o handle attached to the i/o service for this thread afio::async_file_handle h = afio::async_file_handle::async_file(service, {}, "temp", afio::file_handle::mode::write, afio::file_handle::creation::if_needed, afio::file_handle::caching::only_metadata, afio::file_handle::flag::unlink_on_close).value(); + + // Truncate to 1Mb 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> { alignas(4096) char buffer[4096]; @@ -41,6 +49,8 @@ static inline void TestAsyncFileHandleCoroutines() afio::async_file_handle::const_buffer_type bt{buffer}; for(size_t n = 0; n < 128; n++) { + // This will initiate the i/o, and suspend the coroutine until completion. + // The caller will thus resume execution with a valid unsignaled future. auto written = co_await h.co_write({bt, n * 32768 + no * 4096}).value(); written.value(); } @@ -48,16 +58,19 @@ static inline void TestAsyncFileHandleCoroutines() std::vector<std::future<void>> coroutines; for(size_t n = 0; n < 8; n++) { + // Construct each coroutine, initiating the i/o, then suspending. coroutines.push_back(coroutine(n)); } - // Pump the i/o, multiplexing the coroutines, until no more work remains + // Pump the i/o, multiplexing the coroutines, until no more work remains. while(service.run().value()) ; - // Make sure nothing went wrong + // 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 alignas(4096) char buffer1[4096], buffer2[4096]; afio::async_file_handle::extent_type offset = 0; |