fix: reliability improvements in WinServer/IPC subsystems

This commit is contained in:
2026-05-14 15:31:28 +02:00
parent eac8feb62c
commit 1561ee1160
3 changed files with 15 additions and 19 deletions
+3 -3
View File
@@ -142,7 +142,7 @@ namespace WinServer {
FillSurfaceLocked(snapshot, w, h, InitialWindowPixel);
uint64_t userVa = 0;
if (Ipc::MapSurfaceForPid(live, ownerPid, ownerPml4, heapNext, userVa) != 0) {
if (Ipc::MapSurfaceForPid(live, ownerPid, ownerPml4, heapNext, userVa, false) != 0) {
Ipc::ReleaseMailbox(mailbox, true, true);
Ipc::ReleaseSurface(snapshot);
Ipc::ReleaseSurface(live);
@@ -242,7 +242,7 @@ namespace WinServer {
if (!slot.used || slot.snapshotSurface == nullptr) return 0;
uint64_t outVa = 0;
if (Ipc::MapSurfaceForPid(slot.snapshotSurface, callerPid, callerPml4, heapNext, outVa) != 0) {
if (Ipc::MapSurfaceForPid(slot.snapshotSurface, callerPid, callerPml4, heapNext, outVa, false) != 0) {
return 0;
}
return outVa;
@@ -294,7 +294,7 @@ namespace WinServer {
Ipc::RetainSurface(newSnapshot);
uint64_t newOwnerVa = 0;
if (Ipc::MapSurfaceForPid(newLive, callerPid, ownerPml4, heapNext, newOwnerVa) != 0) {
if (Ipc::MapSurfaceForPid(newLive, callerPid, ownerPml4, heapNext, newOwnerVa, false) != 0) {
Ipc::ReleaseSurface(newSnapshot);
Ipc::ReleaseSurface(newLive);
return -1;
+10 -15
View File
@@ -1806,7 +1806,8 @@ namespace Ipc {
return 0;
}
int MapSurfaceForPid(Surface* surface, int pid, uint64_t pml4Phys, uint64_t& heapNext, uint64_t& outVa) {
int MapSurfaceForPid(Surface* surface, int pid, uint64_t pml4Phys, uint64_t& heapNext,
uint64_t& outVa, bool reserveGrowthRange) {
if (surface == nullptr) return -1;
int slot = SlotForPid(pid);
@@ -1862,20 +1863,14 @@ namespace Ipc {
g_surfaceMaps[slot][mapIdx].numPages = numPages;
surface->refs++; // inlined RetainRawObject — we already hold surface->lock
// Reserve the full surface address-range cap, not just the currently
// mapped pages. ResizeSurface can grow this surface up to
// MaxSurfacePages, and its grow path extends the existing VA range
// in-place by mapping new pages at baseVa + p*0x1000 for p beyond the
// original size. If we only bumped heapNext by numPages*0x1000, any
// subsequent mapping (another surface, heap allocation, etc.) would
// sit at baseVa + numPages*0x1000 -- and a later grow would silently
// overwrite its PTEs. Reserving MaxSurfacePages*0x1000 (32 MiB) of
// VA per mapping is cheap: 47-bit user VA gives 128 TiB of headroom,
// and at most MaxSurfaceMapsPerProcess (64) mappings per process
// means at most 2 GiB of reserved VA per process. Page tables are
// only populated for pages actually mapped; unused VA in the
// reservation costs nothing beyond the address-space slot.
heapNext += (uint64_t)MaxSurfacePages * 0x1000ULL;
// Generic IPC surfaces can grow in place through ResizeSurface(), so
// their mapping must reserve the maximum VA range that a later grow
// can populate. Window-server surfaces are replaced rather than grown
// in place, so callers can opt out and avoid burning 32 MiB of process
// VA on every window map/remap during a long desktop session.
uint32_t reservedPages = reserveGrowthRange ? MaxSurfacePages : numPages;
if (reservedPages < numPages) reservedPages = numPages;
heapNext += (uint64_t)reservedPages * 0x1000ULL;
outVa = baseVa;
surface->lock.Release();
return 0;
+2 -1
View File
@@ -135,7 +135,8 @@ namespace Ipc {
uint32_t fillPixel);
uint64_t MapSurfaceHandle(int handle);
int ResizeSurfaceHandle(int handle, uint64_t newSize);
int MapSurfaceForPid(Surface* surface, int pid, uint64_t pml4Phys, uint64_t& heapNext, uint64_t& outVa);
int MapSurfaceForPid(Surface* surface, int pid, uint64_t pml4Phys, uint64_t& heapNext,
uint64_t& outVa, bool reserveGrowthRange = true);
int UnmapSurfaceForPid(Surface* surface, int pid, uint64_t pml4Phys);
ProcessObject* GetProcessObject(int pid);