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>2018-06-19 12:00:20 +0300
committerNiall Douglas (s [underscore] sourceforge {at} nedprod [dot] com) <spamtrap@nedprod.com>2018-06-19 12:00:20 +0300
commit5854802f283de2b9c5026ea1a905ffdde1b09034 (patch)
treef4501b74338e20481acf4fa2f2784bf1fe996b53
parent128ff433151efbad5585de55c3e365a982ba1acb (diff)
Add signal guard to map_handle::write()
-rw-r--r--include/afio/revision.hpp6
-rw-r--r--include/afio/v2.0/algorithm/shared_fs_mutex/memory_map.hpp2
-rw-r--r--include/afio/v2.0/config.hpp6
-rw-r--r--include/afio/v2.0/detail/impl/posix/map_handle.ipp80
-rw-r--r--include/afio/v2.0/detail/impl/windows/map_handle.ipp57
-rw-r--r--include/afio/v2.0/map_handle.hpp17
m---------include/afio/v2.0/outcome0
m---------include/afio/v2.0/quickcpplib0
8 files changed, 123 insertions, 45 deletions
diff --git a/include/afio/revision.hpp b/include/afio/revision.hpp
index 976a7951..f8266792 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 f976a6f1277af7a84744f789d1a3f69aed345b68
-#define AFIO_PREVIOUS_COMMIT_DATE "2018-06-08 12:59:43 +00:00"
-#define AFIO_PREVIOUS_COMMIT_UNIQUE f976a6f1
+#define AFIO_PREVIOUS_COMMIT_REF 128ff433151efbad5585de55c3e365a982ba1acb
+#define AFIO_PREVIOUS_COMMIT_DATE "2018-06-18 20:18:55 +00:00"
+#define AFIO_PREVIOUS_COMMIT_UNIQUE 128ff433
diff --git a/include/afio/v2.0/algorithm/shared_fs_mutex/memory_map.hpp b/include/afio/v2.0/algorithm/shared_fs_mutex/memory_map.hpp
index 321f1bff..b71de0b2 100644
--- a/include/afio/v2.0/algorithm/shared_fs_mutex/memory_map.hpp
+++ b/include/afio/v2.0/algorithm/shared_fs_mutex/memory_map.hpp
@@ -29,7 +29,7 @@ Distributed under the Boost Software License, Version 1.0.
#include "base.hpp"
#ifdef __has_include
-#if __has_include("../../../quickcpplib/include/algorithm/hash.hpp")
+#if __has_include("../../quickcpplib/include/algorithm/hash.hpp")
#include "../../quickcpplib/include/algorithm/hash.hpp"
#include "../../quickcpplib/include/algorithm/small_prng.hpp"
#include "../../quickcpplib/include/spinlock.hpp"
diff --git a/include/afio/v2.0/config.hpp b/include/afio/v2.0/config.hpp
index d8046bc3..2e8016fc 100644
--- a/include/afio/v2.0/config.hpp
+++ b/include/afio/v2.0/config.hpp
@@ -441,7 +441,7 @@ public:
~error_domain() = default;
protected:
- virtual inline string_ref _message(const SYSTEM_ERROR2_NAMESPACE::status_code<void> &code) const noexcept override final;
+ virtual inline string_ref _do_message(const SYSTEM_ERROR2_NAMESPACE::status_code<void> &code) const noexcept override final;
};
#else
template <class BaseStatusCodeDomain> using error_domain = BaseStatusCodeDomain;
@@ -1045,11 +1045,11 @@ namespace detail
#if AFIO_EXPERIMENTAL_STATUS_CODE
#ifndef AFIO_DISABLE_PATHS_IN_FAILURE_INFO
-template <class BaseStatusCodeDomain> inline typename error_domain<BaseStatusCodeDomain>::string_ref error_domain<BaseStatusCodeDomain>::_message(const SYSTEM_ERROR2_NAMESPACE::status_code<void> &code) const noexcept // NOLINT
+template <class BaseStatusCodeDomain> inline typename error_domain<BaseStatusCodeDomain>::string_ref error_domain<BaseStatusCodeDomain>::_do_message(const SYSTEM_ERROR2_NAMESPACE::status_code<void> &code) const noexcept // NOLINT
{
assert(code.domain() == *this);
const auto &v = static_cast<const SYSTEM_ERROR2_NAMESPACE::status_code<error_domain> &>(code); // NOLINT
- std::string ret = _base::_message(code).c_str();
+ std::string ret = _base::_do_message(code).c_str();
detail::append_path_info(v.value(), ret);
char *p = (char *) malloc(ret.size() + 1);
if(p == nullptr)
diff --git a/include/afio/v2.0/detail/impl/posix/map_handle.ipp b/include/afio/v2.0/detail/impl/posix/map_handle.ipp
index 4742b6b1..44860dcf 100644
--- a/include/afio/v2.0/detail/impl/posix/map_handle.ipp
+++ b/include/afio/v2.0/detail/impl/posix/map_handle.ipp
@@ -25,6 +25,8 @@ Distributed under the Boost Software License, Version 1.0.
#include "../../../map_handle.hpp"
#include "../../../utils.hpp"
+#include "../../../quickcpplib/include/signal_guard.hpp"
+
#include <sys/mman.h>
AFIO_V2_NAMESPACE_BEGIN
@@ -544,23 +546,67 @@ map_handle::io_result<map_handle::const_buffers_type> map_handle::write(io_reque
AFIO_LOG_FUNCTION_CALL(this);
byte *addr = _addr + reqs.offset;
size_type togo = reqs.offset < _length ? static_cast<size_type>(_length - reqs.offset) : 0;
- for(const_buffer_type &req : reqs.buffers)
- {
- if(togo != 0u)
- {
- if(req.len > togo)
- {
- req.len = togo;
- }
- memcpy(addr, req.data, req.len);
- req.data = addr;
- addr += req.len;
- togo -= req.len;
- }
- else
- {
- req.len = 0;
- }
+ if(QUICKCPPLIB_NAMESPACE::signal_guard::signal_guard(QUICKCPPLIB_NAMESPACE::signal_guard::signalc::undefined_memory_access,
+ [&] {
+ for(const_buffer_type &req : reqs.buffers)
+ {
+ if(togo != 0u)
+ {
+ if(req.len > togo)
+ {
+ req.len = togo;
+ }
+ memcpy(addr, req.data, req.len);
+ req.data = addr;
+ addr += req.len;
+ togo -= req.len;
+ }
+ else
+ {
+ req.len = 0;
+ }
+ }
+ return false;
+ },
+ [&](QUICKCPPLIB_NAMESPACE::signal_guard::signalc /* unused */, const void *_info, const void *_context) {
+ assert(signo == QUICKCPPLIB_NAMESPACE::signal_guard::signalc::undefined_memory_access);
+ const auto *info = (const siginfo_t *) _info;
+ assert(info->si_signo == SIGBUS);
+ auto *causingaddr = (byte *) info->si_addr;
+ if(causingaddr < _addr || causingaddr >= (_addr + _length))
+ {
+ // Not caused by this map
+ struct sigaction sa;
+ sigaction(SIGBUS, nullptr, &sa);
+ if(sa.sa_flags & SA_SIGINFO)
+ {
+ sa.sa_sigaction(SIGBUS, (siginfo_t *) info, (void *) _context);
+ }
+ else if(sa.sa_handler != SIG_IGN)
+ {
+ if(sa.sa_handler != SIG_DFL)
+ {
+ sa.sa_handler(SIGBUS);
+ }
+ // Painful ...
+ struct sigaction myformer, def;
+ memset(&def, 0, sizeof(def));
+ def.sa_handler = SIG_DFL;
+ sigaction(SIGBUS, &def, &myformer);
+ sigset_t myformer2;
+ sigset_t def2;
+ sigemptyset(&def2);
+ sigaddset(&def2, SIGBUS);
+ pthread_sigmask(SIG_UNBLOCK, &def2, &myformer2);
+ pthread_kill(pthread_self(), SIGBUS);
+ sigaction(SIGBUS, &myformer, nullptr);
+ }
+ abort();
+ }
+ return true;
+ }))
+ {
+ return errc::no_space_on_device;
}
return reqs.buffers;
}
diff --git a/include/afio/v2.0/detail/impl/windows/map_handle.ipp b/include/afio/v2.0/detail/impl/windows/map_handle.ipp
index 50b0e6d0..1331fb01 100644
--- a/include/afio/v2.0/detail/impl/windows/map_handle.ipp
+++ b/include/afio/v2.0/detail/impl/windows/map_handle.ipp
@@ -27,6 +27,7 @@ Distributed under the Boost Software License, Version 1.0.
#include "import.hpp"
#include "../../../quickcpplib/include/algorithm/hash.hpp"
+#include "../../../quickcpplib/include/signal_guard.hpp"
AFIO_V2_NAMESPACE_BEGIN
@@ -812,23 +813,45 @@ map_handle::io_result<map_handle::const_buffers_type> map_handle::write(io_reque
AFIO_LOG_FUNCTION_CALL(this);
byte *addr = _addr + reqs.offset;
size_type togo = reqs.offset < _length ? static_cast<size_type>(_length - reqs.offset) : 0;
- for(const_buffer_type &req : reqs.buffers)
- {
- if(togo != 0u)
- {
- if(req.len > togo)
- {
- req.len = togo;
- }
- memcpy(addr, req.data, req.len);
- req.data = addr;
- addr += req.len;
- togo -= req.len;
- }
- else
- {
- req.len = 0;
- }
+ if(QUICKCPPLIB_NAMESPACE::signal_guard::signal_guard(QUICKCPPLIB_NAMESPACE::signal_guard::signalc::undefined_memory_access,
+ [&] {
+ for(const_buffer_type &req : reqs.buffers)
+ {
+ if(togo != 0u)
+ {
+ if(req.len > togo)
+ {
+ req.len = togo;
+ }
+ memcpy(addr, req.data, req.len);
+ req.data = addr;
+ addr += req.len;
+ togo -= req.len;
+ }
+ else
+ {
+ req.len = 0;
+ }
+ }
+ return false;
+ },
+ [&](QUICKCPPLIB_NAMESPACE::signal_guard::signalc signo, const void *_info, const void * /*unused*/) {
+ assert(signo == QUICKCPPLIB_NAMESPACE::signal_guard::signalc::undefined_memory_access);
+ const auto *info = (const _EXCEPTION_RECORD *) _info;
+ assert(info->ExceptionCode == EXCEPTION_IN_PAGE_ERROR);
+ // info->ExceptionInformation[0] = 0=read 1=write 8=DEP
+ // info->ExceptionInformation[1] = causing address
+ // info->ExceptionInformation[2] = NTSTATUS causing exception
+ auto *causingaddr = (byte *) info->ExceptionInformation[1];
+ if(causingaddr < _addr || causingaddr >= (_addr + _length))
+ {
+ // Not caused by this map
+ RaiseException(info->ExceptionCode, info->ExceptionFlags, info->NumberParameters, info->ExceptionInformation);
+ }
+ return true;
+ }))
+ {
+ return errc::no_space_on_device;
}
return reqs.buffers;
}
diff --git a/include/afio/v2.0/map_handle.hpp b/include/afio/v2.0/map_handle.hpp
index 567c7c5c..8c66450a 100644
--- a/include/afio/v2.0/map_handle.hpp
+++ b/include/afio/v2.0/map_handle.hpp
@@ -504,9 +504,11 @@ public:
/*! \brief Read data from the mapped view.
- \note Because this implementation never copies memory, you can pass in buffers with a null address.
+ \note Because this implementation never copies memory, you can pass in buffers with a null address. As this
+ function never reads any memory, no attempt to trap signal raises can be made, this falls onto the user of
+ this function. See `QUICKCPPLIB_NAMESPACE::signal_guard` for a helper function.
- \return The buffers read, which will never be the buffers input because they will point into the mapped view.
+ \return The buffers read, which will never be the buffers input, because they will point into the mapped view.
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.
\param d Ignored.
@@ -519,12 +521,19 @@ public:
/*! \brief Write data to the mapped view.
+ \note This call traps signals and structured exception throws using `QUICKCPPLIB_NAMESPACE::signal_guard`.
+ Instantiating a `QUICKCPPLIB_NAMESPACE::signal_guard_install` somewhere much higher up in the call stack
+ will improve performance enormously. The signal guard may cost less than 100 CPU cycles depending on how
+ you configure it. If you don't want the guard, you can write memory directly using `address()`.
+
\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.
\param reqs A scatter-gather and offset request.
\param d Ignored.
- \errors None, though the various signals and structured exception throws common to using memory maps may occur.
- \mallocs None.
+ \errors If during the attempt to write the buffers to the map a `SIGBUS` or `EXCEPTION_IN_PAGE_ERROR` is raised,
+ an error code comparing equal to `errc::no_space_on_device` will be returned. This may not always be the cause
+ of the raised signal, but it is by far the most likely.
+ \mallocs None if a `QUICKCPPLIB_NAMESPACE::signal_guard_install` is already instanced.
*/
AFIO_MAKE_FREE_FUNCTION
AFIO_HEADERS_ONLY_VIRTUAL_SPEC io_result<const_buffers_type> write(io_request<const_buffers_type> reqs, deadline d = deadline()) noexcept override;
diff --git a/include/afio/v2.0/outcome b/include/afio/v2.0/outcome
-Subproject 95e0a2210dc9fe22f78117be79550197840c4ab
+Subproject 4eb1466c77a0f8c3573f7cb1cb613b977c9758c
diff --git a/include/afio/v2.0/quickcpplib b/include/afio/v2.0/quickcpplib
-Subproject 4f428d18e58c4edd3f8eaf4da36e3d6b717b11a
+Subproject 20df7f8420f1d8f71fe504b84609a9d9863495c