4343#ifndef MIO_PAGE_HPP
4444#define MIO_PAGE_HPP
4545
46+ #include < errno.h>
47+ #include < stddef.h>
48+ #include < system_error> // std::error_code
4649#ifdef _WIN32
50+ // !! NOTE DO NOT Reverse the include order of these two windows api files
51+ // build errors could trigger !!
4752#include < windows.h>
53+ #include < memoryapi.h> // PrefetchVirtualMemory
4854#else
4955#include < unistd.h>
56+ #include < sys/mman.h> // madvise
5057#endif
5158
5259namespace mio {
@@ -61,12 +68,96 @@ enum class access_mode
6168 write
6269};
6370
71+ /* *
72+ * This is used by madvice to determine Memory access pattern hints
73+ */
74+ enum class advice
75+ {
76+ will_need,
77+ dont_need,
78+ sequential,
79+ random
80+ };
81+
82+ /* *
83+ * This is a cross platform Wrapper around linux madvice function mainly for
84+ * windows users, which under the hood uses PrefetchVirtualMemory() from WinAPI
85+ * @note Windows does not have a direct equivalent to all madvise() behaviors
86+ * only advice::will_need is implemented, for other arguments we will
87+ * simply throw an invalid argument error code, fo unix platforms (Linux, MacOS)
88+ * all option are mapped nativlly to unix madvice internal flags
89+ * given this limitation, the performance will be heavily impacted by Windows memory
90+ * manager
91+ */
92+ std::error_code advise (void * addr, std::size_t len, advice hint);
93+
6494/* *
6595 * Determines the operating system's page allocation granularity.
6696 * On the first call to this function, it invokes the operating system specific syscall
6797 * to determine the page size, caches the value, and returns it. Any subsequent call to
6898 * this function serves the cached value, so no further syscalls are made.
6999 */
100+ inline size_t page_size ();
101+
102+ /* *
103+ * Alligns `offset` to the operating's system page size such that it subtracts the
104+ * difference until the nearest page boundary before `offset`, or does nothing if
105+ * `offset` is already page aligned.
106+ */
107+ inline size_t make_offset_page_aligned (size_t offset) noexcept ;
108+
109+ // --------------------------------------------------------------------------
110+
111+ std::error_code advise (void * addr, std::size_t len, advice hint) {
112+ if (addr == nullptr ) {
113+ return std::make_error_code (std::errc::invalid_argument);
114+ }
115+
116+ if (len == 0 ) {
117+ return {};
118+ }
119+
120+ #ifdef _WIN32
121+
122+ switch (hint) {
123+ case advice::will_need: {
124+ WIN32_MEMORY_RANGE_ENTRY range{};
125+ range.VirtualAddress = addr;
126+ range.NumberOfBytes = len;
127+
128+ if (!PrefetchVirtualMemory (GetCurrentProcess (), 1 , &range, 0 )) {
129+ return std::error_code (static_cast <int >(GetLastError ()), std::system_category ());
130+ }
131+
132+ return {};
133+ }
134+ case advice::dont_need:
135+ case advice::sequential:
136+ case advice::random: return {};
137+ }
138+ return std::make_error_code (std::errc::invalid_argument);
139+
140+ #else // UNIX
141+
142+ int madvise_flag;
143+
144+ switch (hint) {
145+ case advice::will_need: madvise_flag = MADV_WILLNEED ; break ;
146+ case advice::dont_need: madvise_flag = MADV_DONTNEED ; break ;
147+ case advice::sequential: madvise_flag = MADV_SEQUENTIAL ; break ;
148+ case advice::random: madvise_flag = MADV_RANDOM ; break ;
149+ default : return std::make_error_code (std::errc::invalid_argument);
150+ }
151+
152+ if (madvise (addr, len, madvise_flag) != 0 ) {
153+ return std::error_code (errno, std::generic_category ());
154+ }
155+
156+ return {};
157+ #endif // _WIN32
158+ }
159+
160+ // --------------------------------------------------------------------------
70161inline size_t page_size () {
71162 static const size_t page_size = [] {
72163#ifdef _WIN32
@@ -80,11 +171,7 @@ inline size_t page_size() {
80171 return page_size;
81172}
82173
83- /* *
84- * Alligns `offset` to the operating's system page size such that it subtracts the
85- * difference until the nearest page boundary before `offset`, or does nothing if
86- * `offset` is already page aligned.
87- */
174+ // --------------------------------------------------------------------------
88175inline size_t make_offset_page_aligned (size_t offset) noexcept {
89176 const size_t page_size_ = page_size ();
90177 // Use integer division to round down to the nearest page alignment.
0 commit comments