1010#include " xenia/base/memory.h"
1111
1212#include < fcntl.h>
13+ #include < semaphore.h>
1314#include < sys/mman.h>
1415#include < unistd.h>
1516#include < cstddef>
17+ #include < mutex>
1618
1719#include " xenia/base/math.h"
1820#include " xenia/base/platform.h"
@@ -81,12 +83,34 @@ uint32_t ToPosixProtectFlags(PageAccess access) {
8183
8284bool IsWritableExecutableMemorySupported () { return true ; }
8385
86+ struct MappedFileRange {
87+ size_t region_begin;
88+ size_t region_end;
89+ };
90+
91+ std::vector<struct MappedFileRange > mapped_file_ranges;
92+ std::mutex g_mapped_file_ranges_mutex;
93+
8494void * AllocFixed (void * base_address, size_t length,
8595 AllocationType allocation_type, PageAccess access) {
8696 // mmap does not support reserve / commit, so ignore allocation_type.
8797 uint32_t prot = ToPosixProtectFlags (access);
88- void * result = mmap (base_address, length, prot,
89- MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1 , 0 );
98+ int flags = MAP_PRIVATE | MAP_ANONYMOUS;
99+
100+ if (base_address != nullptr ) {
101+ bool should_protect = allocation_type == AllocationType::kCommit ;
102+ if (should_protect) {
103+ if (Protect (base_address, length, access)){
104+ return base_address;
105+ } else {
106+ return nullptr ;
107+ }
108+ }
109+ flags |= MAP_FIXED_NOREPLACE;
110+ }
111+
112+ void * result = mmap (base_address, length, prot, flags, -1 , 0 );
113+
90114 if (result == MAP_FAILED) {
91115 return nullptr ;
92116 } else {
@@ -96,7 +120,34 @@ void* AllocFixed(void* base_address, size_t length,
96120
97121bool DeallocFixed (void * base_address, size_t length,
98122 DeallocationType deallocation_type) {
99- return munmap (base_address, length) == 0 ;
123+ const size_t region_begin = (size_t )base_address;
124+ const size_t region_end = (size_t )base_address + length;
125+
126+ std::lock_guard<std::mutex> guard (g_mapped_file_ranges_mutex);
127+ for (const auto & mapped_range : mapped_file_ranges) {
128+ if (region_begin >= mapped_range.region_begin &&
129+ region_end <= mapped_range.region_end ) {
130+
131+ switch (deallocation_type) {
132+ case DeallocationType::kDecommit :
133+ return Protect (base_address, length, PageAccess::kNoAccess );
134+ case DeallocationType::kRelease :
135+ assert_always (" Error: Tried to release mapped memory!" );
136+ default :
137+ assert_unhandled_case (deallocation_type);
138+ }
139+
140+ }
141+ }
142+
143+ switch (deallocation_type) {
144+ case DeallocationType::kDecommit :
145+ return Protect (base_address, length, PageAccess::kNoAccess );
146+ case DeallocationType::kRelease :
147+ return munmap (base_address, length) == 0 ;
148+ default :
149+ assert_unhandled_case (deallocation_type);
150+ }
100151}
101152
102153bool Protect (void * base_address, size_t length, PageAccess access,
@@ -178,12 +229,39 @@ void CloseFileMappingHandle(FileMappingHandle handle,
178229void * MapFileView (FileMappingHandle handle, void * base_address, size_t length,
179230 PageAccess access, size_t file_offset) {
180231 uint32_t prot = ToPosixProtectFlags (access);
181- return mmap64 (base_address, length, prot, MAP_PRIVATE | MAP_ANONYMOUS, handle,
232+
233+ int flags = MAP_SHARED;
234+ if (base_address != nullptr ) {
235+ flags |= MAP_FIXED_NOREPLACE;
236+ }
237+
238+ void * result = mmap (base_address, length, prot, flags, handle,
182239 file_offset);
240+
241+ if (result == MAP_FAILED) {
242+ return nullptr ;
243+ } else {
244+ std::lock_guard<std::mutex> guard (g_mapped_file_ranges_mutex);
245+ mapped_file_ranges.push_back ({(size_t )result, (size_t )result + length});
246+ return result;
247+ }
183248}
184249
185250bool UnmapFileView (FileMappingHandle handle, void * base_address,
186251 size_t length) {
252+ std::lock_guard<std::mutex> guard (g_mapped_file_ranges_mutex);
253+ for (auto mapped_range = mapped_file_ranges.begin ();
254+ mapped_range != mapped_file_ranges.end ();) {
255+ if (mapped_range->region_begin == (size_t )base_address &&
256+ mapped_range->region_end == (size_t )base_address + length) {
257+ mapped_file_ranges.erase (mapped_range);
258+ return munmap (base_address, length) == 0 ;
259+ } else {
260+ mapped_range++;
261+ }
262+ }
263+ // TODO: Implement partial file unmapping.
264+ assert_always (" Error: Partial unmapping of files not yet supported." );
187265 return munmap (base_address, length) == 0 ;
188266}
189267
0 commit comments