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>2017-09-13 17:00:26 +0300
committerNiall Douglas (s [underscore] sourceforge {at} nedprod [dot] com) <spamtrap@nedprod.com>2017-09-13 17:00:26 +0300
commit17ada3fb9c18873e438bad66e5bce5efc415d4ff (patch)
tree6a352128b37bd11f8d6b337d210e673119fbcca9
parent138a4cebf654500e8ac6595384f7de831777ad97 (diff)
Reworked Coroutines TS support so i/o is initiated immediately, not on co_await.
Refreshed the free functions.
-rw-r--r--include/afio/revision.hpp6
-rw-r--r--include/afio/v2.0/async_file_handle.hpp128
-rw-r--r--include/afio/v2.0/directory_handle.hpp9
-rw-r--r--include/afio/v2.0/file_handle.hpp12
-rw-r--r--include/afio/v2.0/fs_handle.hpp2
-rw-r--r--include/afio/v2.0/io_handle.hpp6
-rw-r--r--include/afio/v2.0/map_handle.hpp21
-rw-r--r--include/afio/v2.0/mapped_file_handle.hpp76
-rw-r--r--release_notes.md1
-rw-r--r--scripts/make_free_functions.py4
-rw-r--r--test/tests/coroutines.cpp4
11 files changed, 206 insertions, 63 deletions
diff --git a/include/afio/revision.hpp b/include/afio/revision.hpp
index 4627486b..637895d2 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 910d87af02fc1f92d21d35a187e26e359ea83af2
-#define AFIO_PREVIOUS_COMMIT_DATE "2017-09-12 00:14:14 +00:00"
-#define AFIO_PREVIOUS_COMMIT_UNIQUE 910d87af
+#define AFIO_PREVIOUS_COMMIT_REF 138a4cebf654500e8ac6595384f7de831777ad97
+#define AFIO_PREVIOUS_COMMIT_DATE "2017-09-13 02:23:28 +00:00"
+#define AFIO_PREVIOUS_COMMIT_UNIQUE 138a4ceb
diff --git a/include/afio/v2.0/async_file_handle.hpp b/include/afio/v2.0/async_file_handle.hpp
index b50ae4c5..45a4ee6f 100644
--- a/include/afio/v2.0/async_file_handle.hpp
+++ b/include/afio/v2.0/async_file_handle.hpp
@@ -349,49 +349,50 @@ public:
#if defined(__cpp_coroutines) || defined(DOXYGEN_IS_IN_THE_HOUSE)
private:
- template <class CompletionRoutine> result<io_state_ptr<CompletionRoutine, const_buffers_type>> _call_read_write(io_request<const_buffers_type> reqs, CompletionRoutine &&completion) noexcept { return async_write(reqs, std::forward<CompletionRoutine>(completion)); }
- template <class CompletionRoutine> result<io_state_ptr<CompletionRoutine, buffers_type>> _call_read_write(io_request<buffers_type> reqs, CompletionRoutine &&completion) noexcept { return async_read(reqs, std::forward<CompletionRoutine>(completion)); }
- //! Type sugar to tell `co_await` what to do
- template <class BuffersType> class awaitable
+ template <class BuffersType> class awaitable_state
{
friend class async_file_handle;
- async_file_handle *_parent;
- io_request<BuffersType> _reqs;
- erased_io_state_ptr _state;
+ optional<coroutine_handle<>> _suspended;
optional<io_result<BuffersType>> _result;
- constexpr awaitable(async_file_handle *parent, io_request<BuffersType> reqs)
- : _parent(parent)
- , _reqs(reqs)
+ // Called on completion of the i/o
+ void operator()(async_file_handle * /*unused*/, io_result<BuffersType> &result)
{
+ // store the result and resume the coroutine
+ _result = std::move(result);
+ if(_suspended)
+ {
+ _suspended->resume();
+ }
}
+ };
- public:
- bool await_ready() { return false; }
- void await_suspend(coroutine_handle<> co)
+public:
+ //! Type sugar to tell `co_await` what to do
+ template <class BuffersType> class awaitable
+ {
+ friend class async_file_handle;
+ io_state_ptr<awaitable_state<BuffersType>, BuffersType> _state;
+
+ awaitable(io_state_ptr<awaitable_state<BuffersType>, BuffersType> state)
+ : _state(std::move(state))
{
- auto r = _parent->_call_read_write(_reqs, [this, co](async_file_handle * /*unused*/, io_result<BuffersType> &result) {
- // store the result and resume the coroutine
- _result = std::move(result);
- co.resume();
- });
- if(r)
- {
- _state = erase(std::move(r).value());
- }
- else
- {
- _result = {r.error()};
- co.resume();
- }
}
- io_result<BuffersType> await_resume() { return std::move(*_result); }
+
+ public:
+ //! Called by `co_await` to determine whether to suspend the coroutine.
+ bool await_ready() { return _state->completion._result.has_value(); }
+ //! Called by `co_await` to suspend the coroutine.
+ void await_suspend(coroutine_handle<> co) { _state->completion._suspended = co; }
+ //! Called by `co_await` after resuming the coroutine to return a value.
+ io_result<BuffersType> await_resume() { return std::move(*_state->completion._result); }
};
public:
- /*! \brief Suspend this coroutine to perform a read, resuming on completion.
+ /*! \brief Schedule a read to occur asynchronously.
- \return An awaitable, which when `co_await`ed upon, returns the buffers read, which may
+ \return An awaitable, which when `co_await`ed upon, suspends execution of the coroutine
+ until the operation has completed, resuming with the buffers read, which may
not be the buffers input. The size of each scatter-gather buffer is updated with the number
of bytes of that buffer transferred, and the pointer to the data may be \em completely
different to what was submitted (e.g. it may point into a memory map).
@@ -400,11 +401,16 @@ public:
\mallocs One calloc, one free.
*/
AFIO_MAKE_FREE_FUNCTION
- awaitable<buffers_type> co_read(io_request<buffers_type> reqs) noexcept { return {this, reqs}; }
+ result<awaitable<buffers_type>> co_read(io_request<buffers_type> reqs) noexcept
+ {
+ OUTCOME_TRY(r, async_read(reqs, awaitable_state<buffers_type>()));
+ return awaitable<buffers_type>(std::move(r));
+ }
- /*! \brief Suspend this coroutine to perform a write, resuming on completion.
+ /*! \brief Schedule a write to occur asynchronously
- \return An awaitable, which when `co_await`ed upon, returns the buffers written, which
+ \return An awaitable, which when `co_await`ed upon, suspends execution of the coroutine
+ until the operation has completed, resuming with the buffers written, which
may not be the buffers input. The size of each scatter-gather buffer is updated with
the number of bytes of that buffer transferred.
\param reqs A scatter-gather and offset request.
@@ -412,7 +418,11 @@ public:
\mallocs One calloc, one free.
*/
AFIO_MAKE_FREE_FUNCTION
- awaitable<const_buffers_type> co_write(io_request<const_buffers_type> reqs) noexcept { return {this, reqs}; }
+ result<awaitable<const_buffers_type>> co_write(io_request<const_buffers_type> reqs) noexcept
+ {
+ OUTCOME_TRY(r, async_write(reqs, awaitable_state<const_buffers_type>()));
+ return awaitable<const_buffers_type>(std::move(r));
+ }
#endif
};
@@ -424,24 +434,29 @@ inline void swap(async_file_handle &self, async_file_handle &o) noexcept
}
/*! Create an async file handle opening access to a file on path
using the given io_service.
+\param service The `io_service` to use.
+\param base Handle to a base location on the filing system. Pass `{}` to indicate that path will be absolute.
+\param _path The path relative to base to open.
+\param _mode How to open the file.
+\param _creation How to create the file.
+\param _caching How to ask the kernel to cache the file.
+\param flags Any additional custom behaviours.
\errors Any of the values POSIX open() or CreateFile() can return.
*/
inline result<async_file_handle> async_file(io_service &service, const path_handle &base, async_file_handle::path_view_type _path, async_file_handle::mode _mode = async_file_handle::mode::read, async_file_handle::creation _creation = async_file_handle::creation::open_existing,
- async_file_handle::caching _caching = async_file_handle::caching::all, async_file_handle::flag flags = async_file_handle::flag::none) noexcept
+ async_file_handle::caching _caching = async_file_handle::caching::only_metadata, async_file_handle::flag flags = async_file_handle::flag::none) noexcept
{
return async_file_handle::async_file(std::forward<decltype(service)>(service), std::forward<decltype(base)>(base), std::forward<decltype(_path)>(_path), std::forward<decltype(_mode)>(_mode), std::forward<decltype(_creation)>(_creation), std::forward<decltype(_caching)>(_caching),
std::forward<decltype(flags)>(flags));
}
/*! Create an async file handle creating a randomly named file on a path.
The file is opened exclusively with `creation::only_if_not_exist` so it
-will never collide with nor overwrite any existing file. Note also
-that caching defaults to temporary which hints to the OS to only
-flush changes to physical storage as lately as possible.
+will never collide with nor overwrite any existing file.
\errors Any of the values POSIX open() or CreateFile() can return.
*/
-inline result<async_file_handle> async_random_file(io_service &service, const path_handle &dirpath, async_file_handle::mode _mode = async_file_handle::mode::write, async_file_handle::caching _caching = async_file_handle::caching::temporary, async_file_handle::flag flags = async_file_handle::flag::none) noexcept
+inline result<async_file_handle> async_random_file(io_service &service, const path_handle &dirpath, async_file_handle::mode _mode = async_file_handle::mode::write, async_file_handle::caching _caching = async_file_handle::caching::only_metadata, async_file_handle::flag flags = async_file_handle::flag::none) noexcept
{
return async_file_handle::async_random_file(std::forward<decltype(service)>(service), std::forward<decltype(dirpath)>(dirpath), std::forward<decltype(_mode)>(_mode), std::forward<decltype(_caching)>(_caching), std::forward<decltype(flags)>(flags));
}
@@ -461,7 +476,7 @@ to use. Use `temp_inode()` instead, it is far more secure.
\errors Any of the values POSIX open() or CreateFile() can return.
*/
inline result<async_file_handle> async_temp_file(io_service &service, async_file_handle::path_view_type name = async_file_handle::path_view_type(), async_file_handle::mode _mode = async_file_handle::mode::write, async_file_handle::creation _creation = async_file_handle::creation::if_needed,
- async_file_handle::caching _caching = async_file_handle::caching::temporary, async_file_handle::flag flags = async_file_handle::flag::unlink_on_close) noexcept
+ async_file_handle::caching _caching = async_file_handle::caching::only_metadata, async_file_handle::flag flags = async_file_handle::flag::unlink_on_close) noexcept
{
return async_file_handle::async_temp_file(std::forward<decltype(service)>(service), std::forward<decltype(name)>(name), std::forward<decltype(_mode)>(_mode), std::forward<decltype(_creation)>(_creation), std::forward<decltype(_caching)>(_caching), std::forward<decltype(flags)>(flags));
}
@@ -514,6 +529,39 @@ 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));
}
+#if defined(__cpp_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
+until the operation has completed, resuming with the buffers read, which may
+not be the buffers input. The size of each scatter-gather buffer is updated with the number
+of bytes of that buffer transferred, and the pointer to the data may be \em completely
+different to what was submitted (e.g. it may point into a memory map).
+\param self The object whose member function to call.
+\param reqs A scatter-gather and offset request.
+\errors As for read(), plus ENOMEM.
+\mallocs One calloc, one free.
+*/
+inline result<async_file_handle::awaitable<async_file_handle::buffers_type>> co_read(async_file_handle &self, async_file_handle::io_request<async_file_handle::buffers_type> reqs) noexcept
+{
+ return self.co_read(std::forward<decltype(reqs)>(reqs));
+}
+/*! \brief Schedule a write to occur asynchronously
+
+\return An awaitable, which when `co_await`ed upon, suspends execution of the coroutine
+until the operation has completed, resuming with the buffers written, which
+may not be the buffers input. The size of each scatter-gather buffer is updated with
+the number of bytes of that buffer transferred.
+\param self The object whose member function to call.
+\param reqs A scatter-gather and offset request.
+\errors As for write(), plus ENOMEM.
+\mallocs One calloc, one free.
+*/
+inline result<async_file_handle::awaitable<async_file_handle::const_buffers_type>> co_write(async_file_handle &self, async_file_handle::io_request<async_file_handle::const_buffers_type> reqs) noexcept
+{
+ return self.co_write(std::forward<decltype(reqs)>(reqs));
+}
+#endif
// END make_free_functions.py
AFIO_V2_NAMESPACE_END
diff --git a/include/afio/v2.0/directory_handle.hpp b/include/afio/v2.0/directory_handle.hpp
index b8e7620e..f6e90e8e 100644
--- a/include/afio/v2.0/directory_handle.hpp
+++ b/include/afio/v2.0/directory_handle.hpp
@@ -263,8 +263,7 @@ inline void swap(directory_handle &self, directory_handle &o) noexcept
\errors Any of the values POSIX open() or CreateFile() can return.
*/
-inline result<directory_handle> directory(const path_handle &base, directory_handle::path_view_type _path, directory_handle::mode _mode = directory_handle::mode::read, directory_handle::creation _creation = directory_handle::creation::open_existing, directory_handle::caching _caching = directory_handle::caching::all,
- directory_handle::flag flags = directory_handle::flag::none) noexcept
+inline result<directory_handle> directory(const path_handle &base, directory_handle::path_view_type _path, directory_handle::mode _mode = directory_handle::mode::read, directory_handle::creation _creation = directory_handle::creation::open_existing, directory_handle::caching _caching = directory_handle::caching::all, directory_handle::flag flags = directory_handle::flag::none) noexcept
{
return directory_handle::directory(std::forward<decltype(base)>(base), std::forward<decltype(_path)>(_path), std::forward<decltype(_mode)>(_mode), std::forward<decltype(_creation)>(_creation), std::forward<decltype(_caching)>(_caching), std::forward<decltype(flags)>(flags));
}
@@ -286,8 +285,7 @@ parameter is ignored.
\errors Any of the values POSIX open() or CreateFile() can return.
*/
-inline result<directory_handle> temp_directory(directory_handle::path_view_type name = directory_handle::path_view_type(), directory_handle::mode _mode = directory_handle::mode::write, directory_handle::creation _creation = directory_handle::creation::if_needed,
- directory_handle::caching _caching = directory_handle::caching::all, directory_handle::flag flags = directory_handle::flag::none) noexcept
+inline result<directory_handle> temp_directory(directory_handle::path_view_type name = directory_handle::path_view_type(), directory_handle::mode _mode = directory_handle::mode::write, directory_handle::creation _creation = directory_handle::creation::if_needed, directory_handle::caching _caching = directory_handle::caching::all, directory_handle::flag flags = directory_handle::flag::none) noexcept
{
return directory_handle::temp_directory(std::forward<decltype(name)>(name), std::forward<decltype(_mode)>(_mode), std::forward<decltype(_creation)>(_creation), std::forward<decltype(_caching)>(_caching), std::forward<decltype(flags)>(flags));
}
@@ -306,8 +304,7 @@ is no longer using any items within (leafnames are views onto the original kerne
\mallocs If the `kernelbuffer` parameter is set on entry, no memory allocations.
If unset, at least one memory allocation, possibly more is performed.
*/
-inline result<directory_handle::enumerate_info> enumerate(const directory_handle &self, directory_handle::buffers_type &&tofill, directory_handle::path_view_type glob = directory_handle::path_view_type(), directory_handle::filter filtering = directory_handle::filter::fastdeleted,
- span<char> kernelbuffer = span<char>()) noexcept
+inline result<directory_handle::enumerate_info> enumerate(const directory_handle &self, directory_handle::buffers_type &&tofill, directory_handle::path_view_type glob = directory_handle::path_view_type(), directory_handle::filter filtering = directory_handle::filter::fastdeleted, span<char> kernelbuffer = span<char>()) noexcept
{
return self.enumerate(std::forward<decltype(tofill)>(tofill), std::forward<decltype(glob)>(glob), std::forward<decltype(filtering)>(filtering), std::forward<decltype(kernelbuffer)>(kernelbuffer));
}
diff --git a/include/afio/v2.0/file_handle.hpp b/include/afio/v2.0/file_handle.hpp
index 02f35d1f..738c7472 100644
--- a/include/afio/v2.0/file_handle.hpp
+++ b/include/afio/v2.0/file_handle.hpp
@@ -277,11 +277,16 @@ inline void swap(file_handle &self, file_handle &o) noexcept
return self.swap(std::forward<decltype(o)>(o));
}
/*! Create a file handle opening access to a file on path
+\param base Handle to a base location on the filing system. Pass `{}` to indicate that path will be absolute.
+\param _path The path relative to base to open.
+\param _mode How to open the file.
+\param _creation How to create the file.
+\param _caching How to ask the kernel to cache the file.
+\param flags Any additional custom behaviours.
\errors Any of the values POSIX open() or CreateFile() can return.
*/
-inline result<file_handle> file(const path_handle &base, file_handle::path_view_type _path, file_handle::mode _mode = file_handle::mode::read, file_handle::creation _creation = file_handle::creation::open_existing, file_handle::caching _caching = file_handle::caching::all,
- file_handle::flag flags = file_handle::flag::none) noexcept
+inline result<file_handle> file(const path_handle &base, file_handle::path_view_type _path, file_handle::mode _mode = file_handle::mode::read, file_handle::creation _creation = file_handle::creation::open_existing, file_handle::caching _caching = file_handle::caching::all, file_handle::flag flags = file_handle::flag::none) noexcept
{
return file_handle::file(std::forward<decltype(base)>(base), std::forward<decltype(_path)>(_path), std::forward<decltype(_mode)>(_mode), std::forward<decltype(_creation)>(_creation), std::forward<decltype(_caching)>(_caching), std::forward<decltype(flags)>(flags));
}
@@ -312,8 +317,7 @@ to use. Use `temp_inode()` instead, it is far more secure.
\errors Any of the values POSIX open() or CreateFile() can return.
*/
-inline result<file_handle> temp_file(file_handle::path_view_type name = file_handle::path_view_type(), file_handle::mode _mode = file_handle::mode::write, file_handle::creation _creation = file_handle::creation::if_needed, file_handle::caching _caching = file_handle::caching::temporary,
- file_handle::flag flags = file_handle::flag::unlink_on_close) noexcept
+inline result<file_handle> temp_file(file_handle::path_view_type name = file_handle::path_view_type(), file_handle::mode _mode = file_handle::mode::write, file_handle::creation _creation = file_handle::creation::if_needed, file_handle::caching _caching = file_handle::caching::temporary, file_handle::flag flags = file_handle::flag::unlink_on_close) noexcept
{
return file_handle::temp_file(std::forward<decltype(name)>(name), std::forward<decltype(_mode)>(_mode), std::forward<decltype(_creation)>(_creation), std::forward<decltype(_caching)>(_caching), std::forward<decltype(flags)>(flags));
}
diff --git a/include/afio/v2.0/fs_handle.hpp b/include/afio/v2.0/fs_handle.hpp
index 62ec52d0..986131cf 100644
--- a/include/afio/v2.0/fs_handle.hpp
+++ b/include/afio/v2.0/fs_handle.hpp
@@ -204,6 +204,8 @@ inline result<void> relink(fs_handle &self, const path_handle &base, fs_handle::
/*! Unlinks the current path of this open handle, causing its entry to immediately disappear from the filing system.
On Windows unless `flag::win_disable_unlink_emulation` is set, this behaviour is
simulated by renaming the file to something random and setting its delete-on-last-close flag.
+Note that Windows may prevent the renaming of a file in use by another process, if so it will
+NOT be renamed.
After the next handle to that file closes, it will become permanently unopenable by anyone
else until the last handle is closed, whereupon the entry will be eventually removed by the
operating system.
diff --git a/include/afio/v2.0/io_handle.hpp b/include/afio/v2.0/io_handle.hpp
index 8124b2bf..bd012204 100644
--- a/include/afio/v2.0/io_handle.hpp
+++ b/include/afio/v2.0/io_handle.hpp
@@ -472,7 +472,9 @@ inline io_handle::io_result<io_handle::buffers_type> read(io_handle &self, io_ha
the some buffers at the end of the returned buffers may return with zero bytes written.
For example, with a zeroed deadline, some backends may only consume as many buffers as the system has available write slots
for, thus for those backends this call is "non-blocking" in the sense that it will return immediately even if it
-could not schedule a single buffer write.
+could not schedule a single buffer write. Another example is that some implementations will not
+auto-extend the length of a file when a write exceeds the maximum extent, you will need to issue
+a `truncate(newsize)` first.
\return The buffers written, which may not be the buffers input. The size of each scatter-gather
buffer is updated with the number of bytes of that buffer transferred.
@@ -501,7 +503,7 @@ Filing system can and do use different algorithms to give much better performanc
some (e.g. ZFS) spectacularly better.
\warning Let me repeat again: consider this call to be a **hint** to poke the kernel with a stick to
-go start to do some work sooner rather than later. It may be ignored entirely.
+go start to do some work sooner rather than later. **It may be ignored entirely**.
\warning For portability, you can only assume that barriers write order for a single handle
instance. You cannot assume that barriers write order across multiple handles to the same inode, or
diff --git a/include/afio/v2.0/map_handle.hpp b/include/afio/v2.0/map_handle.hpp
index e2f44685..c6d43790 100644
--- a/include/afio/v2.0/map_handle.hpp
+++ b/include/afio/v2.0/map_handle.hpp
@@ -390,7 +390,8 @@ inline void swap(section_handle &self, section_handle &o) noexcept
}
/*! \brief Create a memory section.
\param backing The handle to use as backing storage. An invalid handle means to use the system page file as the backing storage.
-\param maximum_size The maximum size this section can ever be. Zero means to use backing.length().
+\param maximum_size The maximum size this section can ever be. Zero means to use `backing.length()`. This cannot exceed the size
+of any backing file used.
\param _flag How to create the section.
\errors Any of the values POSIX dup() or NtCreateSection() can return.
@@ -409,11 +410,19 @@ inline result<section_handle> section(section_handle::extent_type maximum_size)
{
return section_handle::section(std::forward<decltype(maximum_size)>(maximum_size));
}
+//! Return the current maximum permitted extent of the memory section.
+inline result<section_handle::extent_type> length(const section_handle &self) noexcept
+{
+ return self.length();
+}
/*! Resize the current maximum permitted extent of the memory section to the given extent.
+\param self The object whose member function to call.
+\param newsize The new size of the memory section. Specify zero to use `backing.length()`.
+This cannot exceed the size of any backing file used.
\errors Any of the values NtExtendSection() can return. On POSIX this is a no op.
*/
-inline result<section_handle::extent_type> truncate(section_handle &self, section_handle::extent_type newsize) noexcept
+inline result<section_handle::extent_type> truncate(section_handle &self, section_handle::extent_type newsize = 0) noexcept
{
return self.truncate(std::forward<decltype(newsize)>(newsize));
}
@@ -440,9 +449,9 @@ allocated from a paging file backed section instead, create a page file backed s
the other constructor. This makes available all those very useful VM tricks Windows can do with section mapped memory which
VirtualAlloc() memory cannot do.
-\errors Any of the values POSIX mmap() or NtMapViewOfSection() can return.
+\errors Any of the values POSIX mmap() or VirtualAlloc() can return.
*/
-inline result<map_handle> map(map_handle::size_type bytes, section_handle::flag _flag = section_handle::flag::read | section_handle::flag::write) noexcept
+inline result<map_handle> map(map_handle::size_type bytes, section_handle::flag _flag = section_handle::flag::readwrite) noexcept
{
return map_handle::map(std::forward<decltype(bytes)>(bytes), std::forward<decltype(_flag)>(_flag));
}
@@ -454,7 +463,7 @@ inline result<map_handle> map(map_handle::size_type bytes, section_handle::flag
\errors Any of the values POSIX mmap() or NtMapViewOfSection() can return.
*/
-inline result<map_handle> map(section_handle &section, map_handle::size_type bytes = 0, map_handle::extent_type offset = 0, section_handle::flag _flag = section_handle::flag::read | section_handle::flag::write) noexcept
+inline result<map_handle> map(section_handle &section, map_handle::size_type bytes = 0, map_handle::extent_type offset = 0, section_handle::flag _flag = section_handle::flag::readwrite) noexcept
{
return map_handle::map(std::forward<decltype(section)>(section), std::forward<decltype(bytes)>(bytes), std::forward<decltype(offset)>(offset), std::forward<decltype(_flag)>(_flag));
}
@@ -479,7 +488,7 @@ inline map_handle::io_result<map_handle::buffers_type> read(map_handle &self, ma
{
return self.read(std::forward<decltype(reqs)>(reqs), std::forward<decltype(d)>(d));
}
-/*! \brief Write data to the mapped view. Note this will never extend past the current length of the mapped file.
+/*! \brief Write data to the mapped view.
\return The buffers written, which will never be the buffers input because they will point at where the data was copied into the mapped view.
The size of each scatter-gather buffer is updated with the number of bytes of that buffer transferred.
diff --git a/include/afio/v2.0/mapped_file_handle.hpp b/include/afio/v2.0/mapped_file_handle.hpp
index bd858580..ba7ff014 100644
--- a/include/afio/v2.0/mapped_file_handle.hpp
+++ b/include/afio/v2.0/mapped_file_handle.hpp
@@ -426,6 +426,82 @@ public:
AFIO_HEADERS_ONLY_VIRTUAL_SPEC io_result<const_buffers_type> write(io_request<const_buffers_type> reqs, deadline d = deadline()) noexcept override { return _mh.write(std::move(reqs), std::move(d)); }
};
+// BEGIN make_free_functions.py
+//! Swap with another instance
+inline void swap(mapped_file_handle &self, mapped_file_handle &o) noexcept
+{
+ return self.swap(std::forward<decltype(o)>(o));
+}
+/*! Create a memory mapped file handle opening access to a file on path.
+\param reservation The number of bytes to reserve for later expansion when mapping. Zero means reserve only the current file length.
+\param base Handle to a base location on the filing system. Pass `{}` to indicate that path will be absolute.
+\param _path The path relative to base to open.
+\param _mode How to open the file.
+\param _creation How to create the file.
+\param _caching How to ask the kernel to cache the file.
+\param flags Any additional custom behaviours.
+
+Note that if the file is currently zero sized, no mapping occurs now, but
+later when `truncate()` or `update_map()` is called.
+
+\errors Any of the values which the constructors for `file_handle`, `section_handle` and `map_handle` can return.
+*/
+inline result<mapped_file_handle> mapped_file(mapped_file_handle::size_type reservation, const path_handle &base, mapped_file_handle::path_view_type _path, mapped_file_handle::mode _mode = mapped_file_handle::mode::read, mapped_file_handle::creation _creation = mapped_file_handle::creation::open_existing, mapped_file_handle::caching _caching = mapped_file_handle::caching::all, mapped_file_handle::flag flags = mapped_file_handle::flag::none) noexcept
+{
+ return mapped_file_handle::mapped_file(std::forward<decltype(reservation)>(reservation), std::forward<decltype(base)>(base), std::forward<decltype(_path)>(_path), std::forward<decltype(_mode)>(_mode), std::forward<decltype(_creation)>(_creation), std::forward<decltype(_caching)>(_caching), std::forward<decltype(flags)>(flags));
+}
+//! \overload
+inline result<mapped_file_handle> mapped_file(const path_handle &base, mapped_file_handle::path_view_type _path, mapped_file_handle::mode _mode = mapped_file_handle::mode::read, mapped_file_handle::creation _creation = mapped_file_handle::creation::open_existing, mapped_file_handle::caching _caching = mapped_file_handle::caching::all, mapped_file_handle::flag flags = mapped_file_handle::flag::none) noexcept
+{
+ return mapped_file_handle::mapped_file(std::forward<decltype(base)>(base), std::forward<decltype(_path)>(_path), std::forward<decltype(_mode)>(_mode), std::forward<decltype(_creation)>(_creation), std::forward<decltype(_caching)>(_caching), std::forward<decltype(flags)>(flags));
+}
+/*! Create an mapped file handle creating a randomly named file on a path.
+The file is opened exclusively with `creation::only_if_not_exist` so it
+will never collide with nor overwrite any existing file. Note also
+that caching defaults to temporary which hints to the OS to only
+flush changes to physical storage as lately as possible.
+
+\errors Any of the values POSIX open() or CreateFile() can return.
+*/
+inline result<mapped_file_handle> mapped_random_file(mapped_file_handle::size_type reservation, const path_handle &dirpath, mapped_file_handle::mode _mode = mapped_file_handle::mode::write, mapped_file_handle::caching _caching = mapped_file_handle::caching::temporary, mapped_file_handle::flag flags = mapped_file_handle::flag::none) noexcept
+{
+ return mapped_file_handle::mapped_random_file(std::forward<decltype(reservation)>(reservation), std::forward<decltype(dirpath)>(dirpath), std::forward<decltype(_mode)>(_mode), std::forward<decltype(_caching)>(_caching), std::forward<decltype(flags)>(flags));
+}
+/*! Create a mapped file handle creating the named file on some path which
+the OS declares to be suitable for temporary files. Most OSs are
+very lazy about flushing changes made to these temporary files.
+Note the default flags are to have the newly created file deleted
+on first handle close.
+Note also that an empty name is equivalent to calling
+`mapped_random_file(temporary_files_directory())` and the creation
+parameter is ignored.
+
+\note If the temporary file you are creating is not going to have its
+path sent to another process for usage, this is the WRONG function
+to use. Use `temp_inode()` instead, it is far more secure.
+
+\errors Any of the values POSIX open() or CreateFile() can return.
+*/
+inline result<mapped_file_handle> mapped_temp_file(mapped_file_handle::size_type reservation, mapped_file_handle::path_view_type name = mapped_file_handle::path_view_type(), mapped_file_handle::mode _mode = mapped_file_handle::mode::write, mapped_file_handle::creation _creation = mapped_file_handle::creation::if_needed, mapped_file_handle::caching _caching = mapped_file_handle::caching::temporary, mapped_file_handle::flag flags = mapped_file_handle::flag::unlink_on_close) noexcept
+{
+ return mapped_file_handle::mapped_temp_file(std::forward<decltype(reservation)>(reservation), std::forward<decltype(name)>(name), std::forward<decltype(_mode)>(_mode), std::forward<decltype(_creation)>(_creation), std::forward<decltype(_caching)>(_caching), std::forward<decltype(flags)>(flags));
+}
+/*! \em Securely create a mapped file handle creating a temporary anonymous inode in
+the filesystem referred to by \em dirpath. The inode created has
+no name nor accessible path on the filing system and ceases to
+exist as soon as the last handle is closed, making it ideal for use as
+a temporary file where other processes do not need to have access
+to its contents via some path on the filing system (a classic use case
+is for backing shared memory maps).
+
+\errors Any of the values POSIX open() or CreateFile() can return.
+*/
+inline result<mapped_file_handle> mapped_temp_inode(mapped_file_handle::path_view_type dirpath = temporary_files_directory(), mapped_file_handle::mode _mode = mapped_file_handle::mode::write, mapped_file_handle::flag flags = mapped_file_handle::flag::none) noexcept
+{
+ return mapped_file_handle::mapped_temp_inode(std::forward<decltype(dirpath)>(dirpath), std::forward<decltype(_mode)>(_mode), std::forward<decltype(flags)>(flags));
+}
+// END make_free_functions.py
+
AFIO_V2_NAMESPACE_END
#if AFIO_HEADERS_ONLY == 1 && !defined(DOXYGEN_SHOULD_SKIP_THIS)
diff --git a/release_notes.md b/release_notes.md
index 26369a2b..fa3fcfe8 100644
--- a/release_notes.md
+++ b/release_notes.md
@@ -194,6 +194,7 @@ Todo thereafter:
Features possibly to be added after a Boost peer review:
- Directory change monitoring.
+- Permissions support (ACLs).
<table width="100%" border="0" cellpadding="4">
diff --git a/scripts/make_free_functions.py b/scripts/make_free_functions.py
index 68126468..9cb1f38a 100644
--- a/scripts/make_free_functions.py
+++ b/scripts/make_free_functions.py
@@ -76,11 +76,13 @@ for header in glob.glob("../include/afio/*/*.hpp"):
function = replace(function, 'size_type')
function = replace(function, 'buffers_type')
function = replace(function, 'const_buffers_type')
+ function = replace(function, 'enumerate_info')
function = function.replace('path_view_type()', classname+'::path_view_type()')
function = function.replace(' io_result<', ' '+classname+'::io_result<')
function = function.replace(' io_request<', ' '+classname+'::io_request<')
function = function.replace('(io_request<', '('+classname+'::io_request<')
function = function.replace('<io_state_ptr<', '<'+classname+'::io_state_ptr<')
+ function = function.replace('<awaitable<', '<'+classname+'::awaitable<')
function = function.replace(' mode ', ' '+classname+'::mode ')
function = function.replace(' mode::', ' '+classname+'::mode::')
function = function.replace(' creation ', ' '+classname+'::creation ')
@@ -89,6 +91,8 @@ for header in glob.glob("../include/afio/*/*.hpp"):
function = function.replace(' caching::', ' '+classname+'::caching::')
function = function.replace(' flag ', ' '+classname+'::flag ')
function = function.replace(' flag::', ' '+classname+'::flag::')
+ function = function.replace(' filter ', ' '+classname+'::filter ')
+ function = function.replace(' filter::', ' '+classname+'::filter::')
if function[-2] == ';':
function=function[:-2]
elif '}' in function:
diff --git a/test/tests/coroutines.cpp b/test/tests/coroutines.cpp
index 2e1cb8da..480df16c 100644
--- a/test/tests/coroutines.cpp
+++ b/test/tests/coroutines.cpp
@@ -29,8 +29,8 @@ Distributed under the Boost Software License, Version 1.0.
static inline void TestAsyncFileHandleCoroutines()
{
- namespace afio = AFIO_V2_NAMESPACE;
#ifdef __cpp_coroutines
+ namespace afio = AFIO_V2_NAMESPACE;
afio::io_service service;
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();
h.truncate(1024 * 4096);
@@ -41,7 +41,7 @@ static inline void TestAsyncFileHandleCoroutines()
afio::async_file_handle::const_buffer_type bt{buffer};
for(size_t n = 0; n < 128; n++)
{
- auto written = co_await h.co_write({bt, n * 32768 + no * 4096});
+ auto written = co_await h.co_write({bt, n * 32768 + no * 4096}).value();
written.value();
}
};