Skip to content

Commit ac30fdd

Browse files
raphaelthegreatngoquang2708
authored andcommitted
memory: Avoid merging flexible mappings, support multi-unmap
1 parent 98e4dd4 commit ac30fdd

File tree

3 files changed

+28
-18
lines changed

3 files changed

+28
-18
lines changed

src/core/address_space.cpp

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -170,20 +170,13 @@ struct AddressSpace::Impl {
170170
}
171171

172172
void Unmap(VAddr virtual_addr, size_t size, bool has_backing) {
173-
bool ret;
174-
if (has_backing) {
175-
ret = UnmapViewOfFile2(process, reinterpret_cast<PVOID>(virtual_addr),
176-
MEM_PRESERVE_PLACEHOLDER);
177-
} else {
178-
ret = VirtualFreeEx(process, reinterpret_cast<PVOID>(virtual_addr), size,
179-
MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER);
173+
// A requested unmap region might contain multiple distinct placeholder mappings
174+
const VAddr virtual_end = virtual_addr + size;
175+
VAddr base = virtual_addr;
176+
while (base < virtual_end) {
177+
base = UnmapOneRegion(base, size, has_backing);
180178
}
181-
ASSERT_MSG(ret, "Unmap operation on virtual_addr={:#X} failed: {}", virtual_addr,
182-
Common::GetLastErrorMsg());
183-
184-
// The unmap call will create a new placeholder region. We need to see if we can coalesce it
185-
// with neighbors.
186-
JoinRegionsAfterUnmap(virtual_addr, size);
179+
ASSERT_MSG(base == virtual_end && size == 0, "Invalid state after unmap");
187180
}
188181

189182
// The following code is inspired from Dolphin's MemArena
@@ -261,18 +254,32 @@ struct AddressSpace::Impl {
261254
}
262255
}
263256

264-
void JoinRegionsAfterUnmap(VAddr address, size_t size) {
265-
// There should be a mapping that matches the request exactly, find it
257+
VAddr UnmapOneRegion(VAddr address, size_t& size, bool has_backing) {
258+
// There should be a mapping that is contained by the request, find it
266259
auto it = regions.find(address);
267-
ASSERT_MSG(it != regions.end() && it->second.size == size,
260+
ASSERT_MSG(it != regions.end() && it->second.size <= size,
268261
"Invalid address/size given to unmap.");
269262
auto& [base, region] = *it;
263+
264+
const VAddr region_end = region.base + region.size;
270265
region.is_mapped = false;
266+
size -= region.size;
267+
268+
bool ret;
269+
if (has_backing) {
270+
ret = UnmapViewOfFile2(process, reinterpret_cast<PVOID>(address),
271+
MEM_PRESERVE_PLACEHOLDER);
272+
} else {
273+
ret = VirtualFreeEx(process, reinterpret_cast<PVOID>(address), region.size,
274+
MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER);
275+
}
276+
ASSERT_MSG(ret, "Unmap operation on virtual_addr={:#X} failed: {}", address,
277+
Common::GetLastErrorMsg());
271278

272279
// Check if a placeholder exists right before us.
273280
auto it_prev = it != regions.begin() ? std::prev(it) : regions.end();
274281
if (it_prev != regions.end() && !it_prev->second.is_mapped) {
275-
const size_t total_size = it_prev->second.size + size;
282+
const size_t total_size = it_prev->second.size + region.size;
276283
if (!VirtualFreeEx(process, LPVOID(it_prev->first), total_size,
277284
MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS)) {
278285
UNREACHABLE_MSG("Region coalescing failed: {}", Common::GetLastErrorMsg());
@@ -295,6 +302,8 @@ struct AddressSpace::Impl {
295302
it->second.size = total_size;
296303
regions.erase(it_next);
297304
}
305+
306+
return region_end;
298307
}
299308

300309
void Protect(VAddr virtual_addr, size_t size, bool read, bool write, bool execute) {

src/core/libraries/kernel/threads/pthread.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#pragma once
55

6+
#include <atomic>
67
#include <forward_list>
78
#include <list>
89
#include <atomic>

src/core/memory.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ struct VirtualMemoryArea {
108108
if (base + size != next.base) {
109109
return false;
110110
}
111-
if (type == VMAType::Direct && phys_base + size != next.phys_base) {
111+
if (type != VMAType::Direct || phys_base + size != next.phys_base) {
112112
return false;
113113
}
114114
if (prot != next.prot || type != next.type) {

0 commit comments

Comments
 (0)