[PATCH v2 0/1] MR11742: krnl386: Don't free DISCARDABLE resources in FreeResource16.
If a resource is marked DISCARDABLE, it is not actually freed when its refcount reaches 0. In theory the resource's memory is freed when the system is low on memory, but its global handle remains valid to allow the resource to be resurrected with the same handle later. In practice, 16-bit programs can't run out of memory on modern hardware, and the game Tetris Jr. depends on its discardable resources never being discarded. See https://devblogs.microsoft.com/oldnewthing/20040202-00/?p=40783 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=23364 -- v2: krnl386: Don't free DISCARDABLE resources in FreeResource16. https://gitlab.winehq.org/wine/wine/-/merge_requests/11742
From: Alex Henrie <alexhenrie24@gmail.com> If a resource is marked DISCARDABLE, it is not actually freed when its refcount reaches 0. In theory the resource's memory is freed when the system is low on memory, but its global handle remains valid to allow the resource to be resurrected with the same handle later. In practice, 16-bit programs can't run out of memory on modern hardware, and the game Tetris Jr. depends on its discardable resources never being discarded. See https://devblogs.microsoft.com/oldnewthing/20040202-00/?p=40783 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=23364 --- dlls/krnl386.exe16/resource.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/dlls/krnl386.exe16/resource.c b/dlls/krnl386.exe16/resource.c index bcdb01a3b30..ec536c9007a 100644 --- a/dlls/krnl386.exe16/resource.c +++ b/dlls/krnl386.exe16/resource.c @@ -1023,6 +1023,8 @@ HGLOBAL16 WINAPI LoadResource16( HMODULE16 hModule, HRSRC16 hRsrc ) if (pNameInfo->handle && !(GlobalFlags16(pNameInfo->handle) & GMEM_DISCARDED)) { pNameInfo->usage++; + GlobalReAlloc16( pNameInfo->handle, GlobalSize16( pNameInfo->handle ), + GlobalFlags16( pNameInfo->handle ) & ~GMEM_DISCARDABLE ); TRACE(" Already loaded, new count=%d\n", pNameInfo->usage ); } else @@ -1127,9 +1129,17 @@ BOOL16 WINAPI FreeResource16( HGLOBAL16 handle ) if (pNameInfo->usage > 0) pNameInfo->usage--; if (pNameInfo->usage == 0) { - GlobalFree16( pNameInfo->handle ); - pNameInfo->handle = 0; - pNameInfo->flags &= ~NE_SEGFLAGS_LOADED; + if (pNameInfo->flags & NE_SEGFLAGS_DISCARDABLE) + { + GlobalReAlloc16( pNameInfo->handle, GlobalSize16( pNameInfo->handle ), + GlobalFlags16( pNameInfo->handle ) | GMEM_DISCARDABLE ); + } + else + { + GlobalFree16( pNameInfo->handle ); + pNameInfo->handle = 0; + pNameInfo->flags &= ~NE_SEGFLAGS_LOADED; + } } return FALSE; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11742
https://devblogs.microsoft.com/oldnewthing/20040202-00/?p=40783 says you're supposed to mark the segment discardable, not ignore the request entirely.
OK, I've amended the commit to set and clear the GMEM_DISCARDABLE flag, just in case any program is looking for that.
16-bit programs can't run out of memory on modern hardware
Are you sure? That 16-bit programs can utilize all memory of modern hardware?
16-bit programs are limited to 4 GiB of address space. They will run out of address space before they can use up all of the computer's memory. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11742#note_149682
Jinoh Kang (@iamahuman) commented about dlls/krnl386.exe16/resource.c:
{ if (pNameInfo->usage > 0) pNameInfo->usage--; if (pNameInfo->usage == 0) + { + if (pNameInfo->flags & NE_SEGFLAGS_DISCARDABLE) + { + GlobalReAlloc16( pNameInfo->handle, GlobalSize16( pNameInfo->handle ), + GlobalFlags16( pNameInfo->handle ) | GMEM_DISCARDABLE );
```suggestion:-1+0 GlobalReAlloc16( pNameInfo->handle, 0, GlobalFlags16( pNameInfo->handle ) | GMEM_DISCARDABLE | GMEM_MODIFY ); ``` -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11742#note_149684
16-bit programs are limited to 4 GiB of address space. They will run out of address space before they can use up all of the computer's memory.
I meant that the DISCARDABLE mechanism (if ever implemented) is needed exactly for that: when the application runs out of (segmented) address space and no new segments can be allocated. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11742#note_149685
participants (3)
-
Alex Henrie -
Alex Henrie (@alexhenrie) -
Jinoh Kang (@iamahuman)