mirror of
https://github.com/boostorg/log.git
synced 2026-02-03 09:12:19 +00:00
240 lines
7.9 KiB
C++
240 lines
7.9 KiB
C++
/*
|
|
* Copyright Andrey Semashev 2016.
|
|
* Distributed under the Boost Software License, Version 1.0.
|
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
|
* http://www.boost.org/LICENSE_1_0.txt)
|
|
*/
|
|
/*!
|
|
* \file windows/mapped_shared_memory.cpp
|
|
* \author Andrey Semashev
|
|
* \date 13.02.2016
|
|
*
|
|
* \brief This header is the Boost.Log library implementation, see the library documentation
|
|
* at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
|
|
*/
|
|
|
|
#include <boost/log/detail/config.hpp>
|
|
#include <boost/detail/winapi/basic_types.hpp>
|
|
#include <boost/detail/winapi/handles.hpp>
|
|
#include <boost/detail/winapi/dll.hpp>
|
|
#include <boost/detail/winapi/file_mapping.hpp>
|
|
#include <boost/detail/winapi/page_protection_flags.hpp>
|
|
#include <boost/detail/winapi/get_last_error.hpp>
|
|
#include <windows.h> // for error codes
|
|
#include <cstddef>
|
|
#include <limits>
|
|
#include <string>
|
|
#include <boost/assert.hpp>
|
|
#include <boost/memory_order.hpp>
|
|
#include <boost/atomic/atomic.hpp>
|
|
#include <boost/throw_exception.hpp>
|
|
#include <boost/log/exceptions.hpp>
|
|
#include <boost/log/utility/permissions.hpp>
|
|
#include "windows/mapped_shared_memory.hpp"
|
|
#include <boost/log/detail/header.hpp>
|
|
|
|
namespace boost {
|
|
|
|
BOOST_LOG_OPEN_NAMESPACE
|
|
|
|
namespace ipc {
|
|
|
|
namespace aux {
|
|
|
|
boost::atomic< mapped_shared_memory::nt_query_section_t > mapped_shared_memory::nt_query_section(static_cast< mapped_shared_memory::nt_query_section_t >(NULL));
|
|
|
|
mapped_shared_memory::~mapped_shared_memory()
|
|
{
|
|
if (m_mapped_address)
|
|
unmap();
|
|
|
|
if (m_handle)
|
|
{
|
|
BOOST_VERIFY(boost::detail::winapi::CloseHandle(m_handle) != 0);
|
|
m_handle = NULL;
|
|
}
|
|
}
|
|
|
|
//! Creates a new file mapping for the shared memory segment or opens the existing one
|
|
void mapped_shared_memory::create(const wchar_t* name, std::size_t size, permissions const& perms)
|
|
{
|
|
BOOST_ASSERT(m_handle == NULL);
|
|
|
|
// Unlike other create functions, this function opens the existing mapping, if one already exists
|
|
boost::detail::winapi::HANDLE_ h = boost::detail::winapi::CreateFileMappingW
|
|
(
|
|
boost::detail::winapi::INVALID_HANDLE_VALUE_,
|
|
reinterpret_cast< boost::detail::winapi::SECURITY_ATTRIBUTES_* >(perms.get_native()),
|
|
boost::detail::winapi::PAGE_READWRITE_ | boost::detail::winapi::SEC_COMMIT_,
|
|
static_cast< boost::detail::winapi::DWORD_ >(size >> 32u),
|
|
static_cast< boost::detail::winapi::DWORD_ >(size),
|
|
name
|
|
);
|
|
|
|
boost::detail::winapi::DWORD_ err = boost::detail::winapi::GetLastError();
|
|
if (BOOST_UNLIKELY(h == NULL || err != ERROR_SUCCESS))
|
|
{
|
|
if (h != NULL)
|
|
boost::detail::winapi::CloseHandle(h);
|
|
BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to create a shared memory segment", (err));
|
|
}
|
|
|
|
m_handle = h;
|
|
m_size = size;
|
|
}
|
|
|
|
//! Creates a new file mapping for the shared memory segment or opens the existing one. Returns \c true if the region was created and \c false if an existing one was opened.
|
|
bool mapped_shared_memory::create_or_open(const wchar_t* name, std::size_t size, permissions const& perms)
|
|
{
|
|
BOOST_ASSERT(m_handle == NULL);
|
|
|
|
// Unlike other create functions, this function opens the existing mapping, if one already exists
|
|
boost::detail::winapi::HANDLE_ h = boost::detail::winapi::CreateFileMappingW
|
|
(
|
|
boost::detail::winapi::INVALID_HANDLE_VALUE_,
|
|
reinterpret_cast< boost::detail::winapi::SECURITY_ATTRIBUTES_* >(perms.get_native()),
|
|
boost::detail::winapi::PAGE_READWRITE_ | boost::detail::winapi::SEC_COMMIT_,
|
|
static_cast< boost::detail::winapi::DWORD_ >(size >> 32u),
|
|
static_cast< boost::detail::winapi::DWORD_ >(size),
|
|
name
|
|
);
|
|
|
|
boost::detail::winapi::DWORD_ err = boost::detail::winapi::GetLastError();
|
|
if (BOOST_UNLIKELY(h == NULL))
|
|
BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to create or open a shared memory segment", (err));
|
|
|
|
const bool created = (err != ERROR_ALREADY_EXISTS);
|
|
try
|
|
{
|
|
if (created)
|
|
{
|
|
m_size = size;
|
|
}
|
|
else
|
|
{
|
|
// If an existing segment was opened, determine its size
|
|
m_size = obtain_size(h);
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
boost::detail::winapi::CloseHandle(h);
|
|
throw;
|
|
}
|
|
|
|
m_handle = h;
|
|
|
|
return created;
|
|
}
|
|
|
|
//! Opens the existing file mapping for the shared memory segment
|
|
void mapped_shared_memory::open(const wchar_t* name)
|
|
{
|
|
BOOST_ASSERT(m_handle == NULL);
|
|
|
|
// Note: FILE_MAP_WRITE implies reading permission as well
|
|
boost::detail::winapi::HANDLE_ h = boost::detail::winapi::OpenFileMappingW(boost::detail::winapi::FILE_MAP_WRITE_ | boost::detail::winapi::SECTION_QUERY_, false, name);
|
|
|
|
if (BOOST_UNLIKELY(h == NULL))
|
|
{
|
|
const boost::detail::winapi::DWORD_ err = boost::detail::winapi::GetLastError();
|
|
BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to create a shared memory segment", (err));
|
|
}
|
|
|
|
try
|
|
{
|
|
m_size = obtain_size(h);
|
|
}
|
|
catch (...)
|
|
{
|
|
boost::detail::winapi::CloseHandle(h);
|
|
throw;
|
|
}
|
|
|
|
m_handle = h;
|
|
}
|
|
|
|
//! Maps the file mapping into the current process memory
|
|
void mapped_shared_memory::map()
|
|
{
|
|
BOOST_ASSERT(m_handle != NULL);
|
|
BOOST_ASSERT(m_mapped_address == NULL);
|
|
|
|
// Note: FILE_MAP_WRITE implies reading permission as well
|
|
m_mapped_address = boost::detail::winapi::MapViewOfFile
|
|
(
|
|
m_handle,
|
|
boost::detail::winapi::FILE_MAP_WRITE_ | boost::detail::winapi::SECTION_QUERY_,
|
|
0u,
|
|
0u,
|
|
m_size
|
|
);
|
|
|
|
if (BOOST_UNLIKELY(m_mapped_address == NULL))
|
|
{
|
|
const boost::detail::winapi::DWORD_ err = boost::detail::winapi::GetLastError();
|
|
BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to map the shared memory segment into the process address space", (err));
|
|
}
|
|
}
|
|
|
|
//! Unmaps the file mapping
|
|
void mapped_shared_memory::unmap()
|
|
{
|
|
BOOST_ASSERT(m_mapped_address != NULL);
|
|
|
|
BOOST_VERIFY(boost::detail::winapi::UnmapViewOfFile(m_mapped_address) != 0);
|
|
m_mapped_address = NULL;
|
|
}
|
|
|
|
//! Returns the size of the file mapping identified by the handle
|
|
std::size_t mapped_shared_memory::obtain_size(boost::detail::winapi::HANDLE_ h)
|
|
{
|
|
nt_query_section_t query_section = nt_query_section.load(boost::memory_order_acquire);
|
|
|
|
if (BOOST_UNLIKELY(query_section == NULL))
|
|
{
|
|
// Check if ntdll.dll provides NtQuerySection, see: http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FNT%20Objects%2FSection%2FNtQuerySection.html
|
|
boost::detail::winapi::HMODULE_ ntdll = boost::detail::winapi::GetModuleHandleW(L"ntdll.dll");
|
|
if (BOOST_UNLIKELY(ntdll == NULL))
|
|
{
|
|
const boost::detail::winapi::DWORD_ err = boost::detail::winapi::GetLastError();
|
|
BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to obtain a handle to ntdll.dll", (err));
|
|
}
|
|
|
|
query_section = (nt_query_section_t)boost::detail::winapi::get_proc_address(ntdll, "NtQuerySection");
|
|
if (BOOST_UNLIKELY(query_section == NULL))
|
|
{
|
|
const boost::detail::winapi::DWORD_ err = boost::detail::winapi::GetLastError();
|
|
BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to obtain the NtQuerySection function", (err));
|
|
}
|
|
|
|
nt_query_section.store(query_section, boost::memory_order_release);
|
|
}
|
|
|
|
section_basic_information info = {};
|
|
NTSTATUS_ err = query_section
|
|
(
|
|
h,
|
|
0u, // SectionBasicInformation
|
|
&info,
|
|
sizeof(info),
|
|
NULL
|
|
);
|
|
if (BOOST_UNLIKELY(err != 0u))
|
|
{
|
|
BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to test obtain size of the shared memory segment", (ERROR_INVALID_HANDLE));
|
|
}
|
|
|
|
return info.section_size.QuadPart;
|
|
}
|
|
|
|
} // namespace aux
|
|
|
|
} // namespace ipc
|
|
|
|
BOOST_LOG_CLOSE_NAMESPACE // namespace log
|
|
|
|
} // namespace boost
|
|
|
|
#include <boost/log/detail/footer.hpp>
|