2 * Copyright Andrey Semashev 2016.
3 * Distributed under the Boost Software License, Version 1.0.
4 * (See accompanying file LICENSE_1_0.txt or copy at
5 * http://www.boost.org/LICENSE_1_0.txt)
8 * \file windows/mapped_shared_memory.cpp
9 * \author Andrey Semashev
12 * \brief This header is the Boost.Log library implementation, see the library documentation
13 * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
16 #include <boost/log/detail/config.hpp>
17 #include <boost/winapi/basic_types.hpp>
18 #include <boost/winapi/handles.hpp>
19 #include <boost/winapi/dll.hpp>
20 #include <boost/winapi/file_mapping.hpp>
21 #include <boost/winapi/page_protection_flags.hpp>
22 #include <boost/winapi/get_last_error.hpp>
23 #include <windows.h> // for error codes
28 #include <boost/assert.hpp>
29 #include <boost/cstdint.hpp>
30 #include <boost/memory_order.hpp>
31 #include <boost/atomic/atomic.hpp>
32 #include <boost/throw_exception.hpp>
33 #include <boost/log/exceptions.hpp>
34 #include <boost/log/utility/permissions.hpp>
35 #include "windows/mapped_shared_memory.hpp"
36 #include <boost/log/detail/header.hpp>
40 BOOST_LOG_OPEN_NAMESPACE
46 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
));
48 mapped_shared_memory::~mapped_shared_memory()
55 BOOST_VERIFY(boost::winapi::CloseHandle(m_handle
) != 0);
60 //! Creates a new file mapping for the shared memory segment or opens the existing one
61 void mapped_shared_memory::create(const wchar_t* name
, std::size_t size
, permissions
const& perms
)
63 BOOST_ASSERT(m_handle
== NULL
);
65 const uint64_t size64
= static_cast< uint64_t >(size
);
67 // Unlike other create functions, this function opens the existing mapping, if one already exists
68 boost::winapi::HANDLE_ h
= boost::winapi::CreateFileMappingW
70 boost::winapi::INVALID_HANDLE_VALUE_
,
71 reinterpret_cast< boost::winapi::SECURITY_ATTRIBUTES_
* >(perms
.get_native()),
72 boost::winapi::PAGE_READWRITE_
| boost::winapi::SEC_COMMIT_
,
73 static_cast< boost::winapi::DWORD_
>(size64
>> 32u),
74 static_cast< boost::winapi::DWORD_
>(size64
),
78 boost::winapi::DWORD_ err
= boost::winapi::GetLastError();
79 if (BOOST_UNLIKELY(h
== NULL
|| err
!= ERROR_SUCCESS
))
82 boost::winapi::CloseHandle(h
);
83 std::ostringstream strm
;
84 strm
<< "Failed to create a shared memory segment of " << size
<< " bytes";
85 BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error
, strm
.str(), (err
));
92 //! 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.
93 bool mapped_shared_memory::create_or_open(const wchar_t* name
, std::size_t size
, permissions
const& perms
)
95 BOOST_ASSERT(m_handle
== NULL
);
97 const uint64_t size64
= static_cast< uint64_t >(size
);
99 // Unlike other create functions, this function opens the existing mapping, if one already exists
100 boost::winapi::HANDLE_ h
= boost::winapi::CreateFileMappingW
102 boost::winapi::INVALID_HANDLE_VALUE_
,
103 reinterpret_cast< boost::winapi::SECURITY_ATTRIBUTES_
* >(perms
.get_native()),
104 boost::winapi::PAGE_READWRITE_
| boost::winapi::SEC_COMMIT_
,
105 static_cast< boost::winapi::DWORD_
>(size64
>> 32u),
106 static_cast< boost::winapi::DWORD_
>(size64
),
110 boost::winapi::DWORD_ err
= boost::winapi::GetLastError();
111 if (BOOST_UNLIKELY(h
== NULL
))
113 std::ostringstream strm
;
114 strm
<< "Failed to create or open a shared memory segment of " << size
<< " bytes";
115 BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error
, strm
.str(), (err
));
118 const bool created
= (err
!= ERROR_ALREADY_EXISTS
);
127 // If an existing segment was opened, determine its size
128 m_size
= obtain_size(h
);
133 boost::winapi::CloseHandle(h
);
142 //! Opens the existing file mapping for the shared memory segment
143 void mapped_shared_memory::open(const wchar_t* name
)
145 BOOST_ASSERT(m_handle
== NULL
);
147 // Note: FILE_MAP_WRITE implies reading permission as well
148 boost::winapi::HANDLE_ h
= boost::winapi::OpenFileMappingW(boost::winapi::FILE_MAP_WRITE_
| boost::winapi::SECTION_QUERY_
, false, name
);
150 if (BOOST_UNLIKELY(h
== NULL
))
152 const boost::winapi::DWORD_ err
= boost::winapi::GetLastError();
153 BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error
, "Failed to create a shared memory segment", (err
));
158 m_size
= obtain_size(h
);
162 boost::winapi::CloseHandle(h
);
169 //! Maps the file mapping into the current process memory
170 void mapped_shared_memory::map()
172 BOOST_ASSERT(m_handle
!= NULL
);
173 BOOST_ASSERT(m_mapped_address
== NULL
);
175 // Note: FILE_MAP_WRITE implies reading permission as well
176 m_mapped_address
= boost::winapi::MapViewOfFile
179 boost::winapi::FILE_MAP_WRITE_
| boost::winapi::SECTION_QUERY_
,
185 if (BOOST_UNLIKELY(m_mapped_address
== NULL
))
187 const boost::winapi::DWORD_ err
= boost::winapi::GetLastError();
188 BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error
, "Failed to map the shared memory segment into the process address space", (err
));
192 //! Unmaps the file mapping
193 void mapped_shared_memory::unmap()
195 BOOST_ASSERT(m_mapped_address
!= NULL
);
197 BOOST_VERIFY(boost::winapi::UnmapViewOfFile(m_mapped_address
) != 0);
198 m_mapped_address
= NULL
;
201 //! Returns the size of the file mapping identified by the handle
202 std::size_t mapped_shared_memory::obtain_size(boost::winapi::HANDLE_ h
)
204 nt_query_section_t query_section
= nt_query_section
.load(boost::memory_order_acquire
);
206 if (BOOST_UNLIKELY(query_section
== NULL
))
208 // Check if ntdll.dll provides NtQuerySection, see: http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FNT%20Objects%2FSection%2FNtQuerySection.html
209 boost::winapi::HMODULE_ ntdll
= boost::winapi::GetModuleHandleW(L
"ntdll.dll");
210 if (BOOST_UNLIKELY(ntdll
== NULL
))
212 const boost::winapi::DWORD_ err
= boost::winapi::GetLastError();
213 BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error
, "Failed to obtain a handle to ntdll.dll", (err
));
216 query_section
= (nt_query_section_t
)boost::winapi::get_proc_address(ntdll
, "NtQuerySection");
217 if (BOOST_UNLIKELY(query_section
== NULL
))
219 const boost::winapi::DWORD_ err
= boost::winapi::GetLastError();
220 BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error
, "Failed to obtain the NtQuerySection function", (err
));
223 nt_query_section
.store(query_section
, boost::memory_order_release
);
226 section_basic_information info
= {};
227 boost::winapi::NTSTATUS_ err
= query_section
230 0u, // SectionBasicInformation
235 if (BOOST_UNLIKELY(err
!= 0u))
237 BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error
, "Failed to test obtain size of the shared memory segment", (ERROR_INVALID_HANDLE
));
240 return static_cast< std::size_t >(info
.section_size
.QuadPart
);
247 BOOST_LOG_CLOSE_NAMESPACE
// namespace log
251 #include <boost/log/detail/footer.hpp>