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:
-rw-r--r--include/llfio/v2.0/detail/impl/io_multiplexer.ipp30
-rw-r--r--include/llfio/v2.0/detail/impl/windows/io_multiplexer.ipp111
-rw-r--r--include/llfio/v2.0/directory_handle.hpp1
-rw-r--r--include/llfio/v2.0/file_handle.hpp1
-rw-r--r--include/llfio/v2.0/io_handle.hpp44
-rw-r--r--include/llfio/v2.0/io_multiplexer.hpp26
-rw-r--r--include/llfio/v2.0/mapped_file_handle.hpp1
-rw-r--r--include/llfio/v2.0/native_handle_type.hpp6
-rw-r--r--include/llfio/v2.0/path_handle.hpp4
-rw-r--r--include/llfio/v2.0/pipe_handle.hpp2
-rw-r--r--include/llfio/v2.0/symlink_handle.hpp1
11 files changed, 201 insertions, 26 deletions
diff --git a/include/llfio/v2.0/detail/impl/io_multiplexer.ipp b/include/llfio/v2.0/detail/impl/io_multiplexer.ipp
index 88d193f7..04f1e888 100644
--- a/include/llfio/v2.0/detail/impl/io_multiplexer.ipp
+++ b/include/llfio/v2.0/detail/impl/io_multiplexer.ipp
@@ -24,16 +24,38 @@ Distributed under the Boost Software License, Version 1.0.
#include "../../io_multiplexer.hpp"
+#include <mutex>
+
LLFIO_V2_NAMESPACE_BEGIN
namespace this_thread
{
static LLFIO_THREAD_LOCAL io_multiplexer *_thread_multiplexer;
- LLFIO_HEADERS_ONLY_FUNC_SPEC io_multiplexer *multiplexer() noexcept
- {
- return _thread_multiplexer;
- }
+ LLFIO_HEADERS_ONLY_FUNC_SPEC io_multiplexer *multiplexer() noexcept { return _thread_multiplexer; }
LLFIO_HEADERS_ONLY_FUNC_SPEC void set_multiplexer(io_multiplexer *ctx) noexcept { _thread_multiplexer = ctx; }
} // namespace this_thread
+template <bool is_threadsafe> struct io_multiplexer_impl : io_multiplexer
+{
+ struct _lock_impl_type
+ {
+ void lock() {}
+ void unlock() {}
+ };
+ _lock_impl_type _lock;
+ using _lock_guard = std::unique_lock<_lock_impl_type>;
+};
+template <> struct io_multiplexer_impl<true> : io_multiplexer
+{
+ using _lock_impl_type = std::mutex;
+ _lock_impl_type _lock;
+ using _lock_guard = std::unique_lock<_lock_impl_type>;
+};
+
LLFIO_V2_NAMESPACE_END
+
+#if defined(_WIN32)
+#include "windows/io_multiplexer.ipp"
+#else
+//#include "posix/io_multiplexer.ipp"
+#endif
diff --git a/include/llfio/v2.0/detail/impl/windows/io_multiplexer.ipp b/include/llfio/v2.0/detail/impl/windows/io_multiplexer.ipp
new file mode 100644
index 00000000..b4b971f2
--- /dev/null
+++ b/include/llfio/v2.0/detail/impl/windows/io_multiplexer.ipp
@@ -0,0 +1,111 @@
+/* Multiplex file i/o
+(C) 2019 Niall Douglas <http://www.nedproductions.biz/> (9 commits)
+File Created: Nov 2019
+
+
+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 "../../../io_multiplexer.hpp"
+
+#ifndef _WIN32
+#error This implementation file is for Microsoft Windows only
+#endif
+
+#include "import.hpp"
+
+LLFIO_V2_NAMESPACE_BEGIN
+
+template <bool is_threadsafe> struct win_iocp_multiplexer final : io_multiplexer_impl<is_threadsafe>
+{
+ using _base = io_multiplexer_impl<is_threadsafe>;
+ using _lock_guard = typename _base::_lock_guard;
+
+ explicit win_iocp_multiplexer(size_t threads) { (void) threads; }
+ virtual ~win_iocp_multiplexer()
+ {
+ if(_v)
+ {
+ (void) win_iocp_multiplexer::close();
+ }
+ }
+ // LLFIO_HEADERS_ONLY_VIRTUAL_SPEC result<path_type> current_path() const noexcept override;
+ LLFIO_HEADERS_ONLY_VIRTUAL_SPEC result<void> close() noexcept override { return _base::close(); }
+ LLFIO_HEADERS_ONLY_VIRTUAL_SPEC native_handle_type release() noexcept override { return _base::release(); }
+
+ LLFIO_HEADERS_ONLY_VIRTUAL_SPEC result<uint8_t> do_io_handle_register(io_handle *h) noexcept override {
+ windows_nt_kernel::init();
+ using namespace windows_nt_kernel;
+ LLFIO_LOG_FUNCTION_CALL(this);
+ IO_STATUS_BLOCK isb = make_iostatus();
+ FILE_COMPLETION_INFORMATION fci{};
+ memset(&fci, 0, sizeof(fci));
+ fci.Port = this->_v.h;
+ fci.Key = nullptr;
+ NTSTATUS ntstat = NtSetInformationFile(h->native_handle().h, &isb, &fci, sizeof(fci), FileCompletionInformation);
+ if(STATUS_PENDING == ntstat)
+ {
+ ntstat = ntwait(h->native_handle().h, isb, deadline());
+ }
+ if(ntstat < 0)
+ {
+ return ntkernel_error(ntstat);
+ }
+ // If this works, we can avoid IOCP entirely for immediately completing i/o
+ return (uint8_t) !SetFileCompletionNotificationModes(h->native_handle().h, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS | FILE_SKIP_SET_EVENT_ON_HANDLE);
+ }
+ LLFIO_HEADERS_ONLY_VIRTUAL_SPEC result<void> do_io_handle_deregister(io_handle *h) noexcept override {
+ windows_nt_kernel::init();
+ using namespace windows_nt_kernel;
+ LLFIO_LOG_FUNCTION_CALL(this);
+ IO_STATUS_BLOCK isb = make_iostatus();
+ FILE_COMPLETION_INFORMATION fci{};
+ memset(&fci, 0, sizeof(fci));
+ fci.Port = nullptr;
+ fci.Key = nullptr;
+ NTSTATUS ntstat = NtSetInformationFile(h->native_handle().h, &isb, &fci, sizeof(fci), FileReplaceCompletionInformation);
+ if(STATUS_PENDING == ntstat)
+ {
+ ntstat = ntwait(h->native_handle().h, isb, deadline());
+ }
+ if(ntstat < 0)
+ {
+ return ntkernel_error(ntstat);
+ }
+ return success();
+ }
+ //LLFIO_HEADERS_ONLY_VIRTUAL_SPEC size_t do_io_handle_max_buffers(const io_handle *h) const noexcept override {}
+ //LLFIO_HEADERS_ONLY_VIRTUAL_SPEC result<registered_buffer_type> do_io_handle_allocate_registered_buffer(io_handle *h, size_t &bytes) noexcept override {}
+ //LLFIO_HEADERS_ONLY_VIRTUAL_SPEC io_result<buffers_type> do_io_handle_read(io_handle *h, io_request<buffers_type> reqs, deadline d) noexcept override {}
+ //LLFIO_HEADERS_ONLY_VIRTUAL_SPEC io_result<buffers_type> do_io_handle_read(io_handle *h, registered_buffer_type base, io_request<buffers_type> reqs, deadline d) noexcept override {}
+ //LLFIO_HEADERS_ONLY_VIRTUAL_SPEC io_result<const_buffers_type> do_io_handle_write(io_handle *h, io_request<const_buffers_type> reqs, deadline d) noexcept override {}
+ //LLFIO_HEADERS_ONLY_VIRTUAL_SPEC io_result<const_buffers_type> do_io_handle_write(io_handle *h, registered_buffer_type base, io_request<const_buffers_type> reqs, deadline d) noexcept override {}
+ //LLFIO_HEADERS_ONLY_VIRTUAL_SPEC io_result<const_buffers_type> do_io_handle_barrier(io_handle *h, io_request<const_buffers_type> reqs, barrier_kind kind, deadline d) noexcept override {}
+};
+
+LLFIO_HEADERS_ONLY_FUNC_SPEC result<io_multiplexer_ptr> multiplexer_win_iocp(size_t threads) noexcept
+{
+ if(1 == threads)
+ {
+ return std::make_unique<win_iocp_multiplexer<false>>(1);
+ }
+ return std::make_unique<win_iocp_multiplexer<true>>(threads);
+}
+
+LLFIO_V2_NAMESPACE_END
diff --git a/include/llfio/v2.0/directory_handle.hpp b/include/llfio/v2.0/directory_handle.hpp
index ebd4ad46..0e5c47e1 100644
--- a/include/llfio/v2.0/directory_handle.hpp
+++ b/include/llfio/v2.0/directory_handle.hpp
@@ -285,6 +285,7 @@ public:
trying to open the path returned. Thus many allocations may occur.
*/
LLFIO_HEADERS_ONLY_VIRTUAL_SPEC result<directory_handle> reopen(mode mode_ = mode::unchanged, caching caching_ = caching::unchanged, deadline d = std::chrono::seconds(30)) const noexcept;
+ LLFIO_DEADLINE_TRY_FOR_UNTIL(reopen)
/*! Return a copy of this directory handle, but as a path handle.
diff --git a/include/llfio/v2.0/file_handle.hpp b/include/llfio/v2.0/file_handle.hpp
index dfe4bb14..2c968ee6 100644
--- a/include/llfio/v2.0/file_handle.hpp
+++ b/include/llfio/v2.0/file_handle.hpp
@@ -254,7 +254,6 @@ public:
trying to open the path returned. Thus many allocations may occur.
*/
LLFIO_HEADERS_ONLY_MEMFUNC_SPEC result<file_handle> reopen(mode mode_ = mode::unchanged, caching caching_ = caching::unchanged, deadline d = std::chrono::seconds(30)) const noexcept;
-
LLFIO_DEADLINE_TRY_FOR_UNTIL(reopen)
/*! Return the current maximum permitted extent of the file.
diff --git a/include/llfio/v2.0/io_handle.hpp b/include/llfio/v2.0/io_handle.hpp
index 5fef2669..0370d750 100644
--- a/include/llfio/v2.0/io_handle.hpp
+++ b/include/llfio/v2.0/io_handle.hpp
@@ -41,6 +41,8 @@ LLFIO_V2_NAMESPACE_EXPORT_BEGIN
*/
class LLFIO_DECL io_handle : public handle
{
+ friend class io_multiplexer;
+
public:
using path_type = handle::path_type;
using extent_type = handle::extent_type;
@@ -119,13 +121,21 @@ public:
}
if(_ctx != nullptr)
{
- OUTCOME_TRY(_ctx->_deregister_io_handle(this));
+ OUTCOME_TRY(_ctx->do_io_handle_deregister(this));
_ctx = nullptr;
}
if(c != nullptr)
{
- OUTCOME_TRY(type, c->_register_io_handle(this));
- (void) type;
+ OUTCOME_TRY(state, c->do_io_handle_register(this));
+ _v.behaviour = (_v.behaviour & ~(native_handle_type::disposition::_multiplexer_state_bit0 | native_handle_type::disposition::_multiplexer_state_bit1));
+ if((state & 1) != 0)
+ {
+ _v.behaviour |= native_handle_type::disposition::_multiplexer_state_bit0;
+ }
+ if((state & 2) != 0)
+ {
+ _v.behaviour |= native_handle_type::disposition::_multiplexer_state_bit1;
+ }
}
_ctx = c;
return success();
@@ -374,6 +384,34 @@ public:
};
static_assert((sizeof(void *) == 4 && sizeof(io_handle) == 20) || (sizeof(void *) == 8 && sizeof(io_handle) == 32), "io_handle is not 20 or 32 bytes in size!");
+inline size_t io_multiplexer::do_io_handle_max_buffers(const io_handle *h) const noexcept
+{
+ return h->_do_max_buffers();
+}
+inline result<io_multiplexer::registered_buffer_type> io_multiplexer::do_io_handle_allocate_registered_buffer(io_handle *h, size_t &bytes) noexcept
+{
+ return h->_do_allocate_registered_buffer(bytes);
+}
+inline io_multiplexer::io_result<io_multiplexer::buffers_type> io_multiplexer::do_io_handle_read(io_handle *h, io_multiplexer::io_request<io_multiplexer::buffers_type> reqs, deadline d) noexcept
+{
+ return h->_do_read(reqs, d);
+}
+inline io_multiplexer::io_result<io_multiplexer::buffers_type> io_multiplexer::do_io_handle_read(io_handle *h, io_multiplexer::registered_buffer_type base, io_multiplexer::io_request<io_multiplexer::buffers_type> reqs, deadline d) noexcept
+{
+ return h->_do_read(std::move(base), reqs, d);
+}
+inline io_multiplexer::io_result<io_multiplexer::const_buffers_type> io_multiplexer::do_io_handle_write(io_handle *h, io_multiplexer::io_request<io_multiplexer::const_buffers_type> reqs, deadline d) noexcept
+{
+ return h->_do_write(reqs, d);
+}
+inline io_multiplexer::io_result<io_multiplexer::const_buffers_type> io_multiplexer::do_io_handle_write(io_handle *h, io_multiplexer::registered_buffer_type base, io_multiplexer::io_request<io_multiplexer::const_buffers_type> reqs, deadline d) noexcept
+{
+ return h->_do_write(std::move(base), reqs, d);
+}
+inline io_multiplexer::io_result<io_multiplexer::const_buffers_type> io_multiplexer::do_io_handle_barrier(io_handle *h, io_multiplexer::io_request<io_multiplexer::const_buffers_type> reqs, io_multiplexer::barrier_kind kind, deadline d) noexcept
+{
+ return h->_do_barrier(reqs, kind, d);
+}
// BEGIN make_free_functions.py
/*! \brief Read data from the open handle.
diff --git a/include/llfio/v2.0/io_multiplexer.hpp b/include/llfio/v2.0/io_multiplexer.hpp
index c130356b..8ae75af8 100644
--- a/include/llfio/v2.0/io_multiplexer.hpp
+++ b/include/llfio/v2.0/io_multiplexer.hpp
@@ -73,11 +73,6 @@ you really need non-infinite deadline i/o.
*/
class LLFIO_DECL io_multiplexer : public handle
{
- friend class io_handle;
-
- LLFIO_HEADERS_ONLY_VIRTUAL_SPEC result<int> _register_io_handle(io_handle *h) noexcept = 0;
- LLFIO_HEADERS_ONLY_VIRTUAL_SPEC result<void> _deregister_io_handle(io_handle *h) noexcept = 0;
-
public:
using path_type = handle::path_type;
using extent_type = handle::extent_type;
@@ -361,20 +356,24 @@ public:
~io_multiplexer() = default;
public:
+ //! Implements `io_handle` registration. The bottom two bits of the returned value are set into `_v.behaviour`'s `_multiplexer_state_bit0` and `_multiplexer_state_bit`
+ LLFIO_HEADERS_ONLY_VIRTUAL_SPEC result<uint8_t> do_io_handle_register(io_handle *h) noexcept = 0;
+ //! Implements `io_handle` deregistration
+ LLFIO_HEADERS_ONLY_VIRTUAL_SPEC result<void> do_io_handle_deregister(io_handle *h) noexcept = 0;
//! Implements `io_handle::max_buffers()`
- LLFIO_HEADERS_ONLY_VIRTUAL_SPEC size_t do_io_handle_max_buffers(const io_handle *h) const noexcept = 0;
+ LLFIO_HEADERS_ONLY_VIRTUAL_SPEC size_t do_io_handle_max_buffers(const io_handle *h) const noexcept;
//! Implements `io_handle::allocate_registered_buffer()`
- LLFIO_HEADERS_ONLY_VIRTUAL_SPEC result<registered_buffer_type> do_io_handle_allocate_registered_buffer(io_handle *h, size_t &bytes) noexcept = 0;
+ LLFIO_HEADERS_ONLY_VIRTUAL_SPEC result<registered_buffer_type> do_io_handle_allocate_registered_buffer(io_handle *h, size_t &bytes) noexcept;
//! Implements `io_handle::read()`
- LLFIO_HEADERS_ONLY_VIRTUAL_SPEC io_result<buffers_type> do_io_handle_read(io_handle *h, io_request<buffers_type> reqs, deadline d) noexcept = 0;
+ LLFIO_HEADERS_ONLY_VIRTUAL_SPEC io_result<buffers_type> do_io_handle_read(io_handle *h, io_request<buffers_type> reqs, deadline d) noexcept;
//! Implements `io_handle::read()`
- LLFIO_HEADERS_ONLY_VIRTUAL_SPEC io_result<buffers_type> do_io_handle_read(io_handle *h, registered_buffer_type base, io_request<buffers_type> reqs, deadline d) noexcept = 0;
+ LLFIO_HEADERS_ONLY_VIRTUAL_SPEC io_result<buffers_type> do_io_handle_read(io_handle *h, registered_buffer_type base, io_request<buffers_type> reqs, deadline d) noexcept;
//! Implements `io_handle::write()`
- LLFIO_HEADERS_ONLY_VIRTUAL_SPEC io_result<const_buffers_type> do_io_handle_write(io_handle *h, io_request<const_buffers_type> reqs, deadline d) noexcept = 0;
+ LLFIO_HEADERS_ONLY_VIRTUAL_SPEC io_result<const_buffers_type> do_io_handle_write(io_handle *h, io_request<const_buffers_type> reqs, deadline d) noexcept;
//! Implements `io_handle::write()`
- LLFIO_HEADERS_ONLY_VIRTUAL_SPEC io_result<const_buffers_type> do_io_handle_write(io_handle *h, registered_buffer_type base, io_request<const_buffers_type> reqs, deadline d) noexcept = 0;
+ LLFIO_HEADERS_ONLY_VIRTUAL_SPEC io_result<const_buffers_type> do_io_handle_write(io_handle *h, registered_buffer_type base, io_request<const_buffers_type> reqs, deadline d) noexcept;
//! Implements `io_handle::barrier()`
- LLFIO_HEADERS_ONLY_VIRTUAL_SPEC io_result<const_buffers_type> do_io_handle_barrier(io_handle *h, io_request<const_buffers_type> reqs, barrier_kind kind, deadline d) noexcept = 0;
+ LLFIO_HEADERS_ONLY_VIRTUAL_SPEC io_result<const_buffers_type> do_io_handle_barrier(io_handle *h, io_request<const_buffers_type> reqs, barrier_kind kind, deadline d) noexcept;
};
//! A unique ptr to an i/o multiplexer implementation.
using io_multiplexer_ptr = std::unique_ptr<io_multiplexer>;
@@ -389,7 +388,8 @@ using io_multiplexer_ptr = std::unique_ptr<io_multiplexer>;
// LLFIO_HEADERS_ONLY_FUNC_SPEC result<io_multiplexer_ptr> multiplexer_bsd_kqueue(size_t threads) noexcept;
#endif
#if defined(_WIN32) || DOXYGEN_IS_IN_THE_HOUSE
-// LLFIO_HEADERS_ONLY_FUNC_SPEC result<io_multiplexer_ptr> multiplexer_win_iocp(size_t threads) noexcept;
+//! \brief Return an i/o multiplexer implemented using Microsoft Windows IOCPW
+LLFIO_HEADERS_ONLY_FUNC_SPEC result<io_multiplexer_ptr> multiplexer_win_iocp(size_t threads) noexcept;
#endif
//! \brief Thread local settings
diff --git a/include/llfio/v2.0/mapped_file_handle.hpp b/include/llfio/v2.0/mapped_file_handle.hpp
index c1d9d878..b560af83 100644
--- a/include/llfio/v2.0/mapped_file_handle.hpp
+++ b/include/llfio/v2.0/mapped_file_handle.hpp
@@ -410,6 +410,7 @@ public:
OUTCOME_TRY(fh, file_handle::reopen(mode_, caching_, d));
return mapped_file_handle(std::move(fh), reservation, _sh.section_flags());
}
+ LLFIO_DEADLINE_TRY_FOR_UNTIL(reopen)
LLFIO_HEADERS_ONLY_VIRTUAL_SPEC result<void> set_multiplexer(io_multiplexer *c = this_thread::multiplexer()) noexcept override
{
OUTCOME_TRY(file_handle::set_multiplexer(c));
diff --git a/include/llfio/v2.0/native_handle_type.hpp b/include/llfio/v2.0/native_handle_type.hpp
index 5d9c2cfc..ff375e85 100644
--- a/include/llfio/v2.0/native_handle_type.hpp
+++ b/include/llfio/v2.0/native_handle_type.hpp
@@ -69,8 +69,10 @@ struct native_handle_type // NOLINT
cache_writes = 1U << 23U, //!< Is writing back from kernel cache rather than writing through
cache_temporary = 1U << 24U, //!< Writes are not flushed to storage quickly
- _is_connected = 1U << 28U, // used by pipe_handle on Windows to store connectedness
- _child_close_executed = 1U << 30U // used to trap when vptr has become corrupted
+ _is_connected = 1U << 28U, // used by pipe_handle on Windows to store connectedness
+ _multiplexer_state_bit0 = 1U << 29U, // per-handle state bits used by an i/o multiplexer
+ _multiplexer_state_bit1 = 1U << 30U, // per-handle state bits used by an i/o multiplexer
+ _child_close_executed = 1U << 31U // used to trap when vptr has become corrupted
} QUICKCPPLIB_BITFIELD_END(disposition)
union {
diff --git a/include/llfio/v2.0/path_handle.hpp b/include/llfio/v2.0/path_handle.hpp
index 23c6221c..8e2ee7e2 100644
--- a/include/llfio/v2.0/path_handle.hpp
+++ b/include/llfio/v2.0/path_handle.hpp
@@ -96,8 +96,8 @@ public:
o = std::move(temp);
}
- //! Replaces `handle::clone()` with a `path_handle returning edition`
- result<path_handle> clone() const noexcept
+ //! A `path_handle` returning edition of `handle::clone()`
+ result<path_handle> clone_to_path_handle() const noexcept
{
OUTCOME_TRY(newh, handle::clone());
return path_handle(std::move(newh));
diff --git a/include/llfio/v2.0/pipe_handle.hpp b/include/llfio/v2.0/pipe_handle.hpp
index 5d929051..99036e98 100644
--- a/include/llfio/v2.0/pipe_handle.hpp
+++ b/include/llfio/v2.0/pipe_handle.hpp
@@ -267,7 +267,7 @@ public:
LLFIO_HEADERS_ONLY_VIRTUAL_SPEC result<path_handle> parent_path_handle(deadline /*unused*/ = std::chrono::seconds(30)) const noexcept override
{
// Pipes parent handle is always the NT kernel namespace for pipes
- return path_discovery::temporary_named_pipes_directory().clone();
+ return path_discovery::temporary_named_pipes_directory().clone_to_path_handle();
}
protected:
diff --git a/include/llfio/v2.0/symlink_handle.hpp b/include/llfio/v2.0/symlink_handle.hpp
index 99b74a29..8f7e7bb8 100644
--- a/include/llfio/v2.0/symlink_handle.hpp
+++ b/include/llfio/v2.0/symlink_handle.hpp
@@ -386,6 +386,7 @@ public:
trying to open the path returned. Thus many allocations may occur.
*/
LLFIO_HEADERS_ONLY_VIRTUAL_SPEC result<symlink_handle> reopen(mode mode_ = mode::unchanged, deadline d = std::chrono::seconds(30)) const noexcept;
+ LLFIO_DEADLINE_TRY_FOR_UNTIL(reopen)
#if LLFIO_SYMLINK_HANDLE_IS_FAKED
LLFIO_HEADERS_ONLY_VIRTUAL_SPEC result<path_type> current_path() const noexcept override;