RFC: GlobalMemoryStatus NT bug FIXME patch
Robert Reif
reif at earthlink.net
Wed Aug 4 21:13:02 CDT 2004
This patch uses GlobalMemoryStatusEx in GlobalMemoryStatus
rather than the other way around. GlobalMemoryStatusEx is used
to calculate properly for over 4 G of memory. GlobalMemoryStatus
uses the proper values from GlobalMemoryStatusEx and fixes them
up according to os version.
The numbers returned for my 1 G machine look right but I have no
way to test the 2-4 G case and the greater than 4 G case. Could
someone double check that what I did is correct or better yet, test
it on machines with more than 2 G of memory?
-------------- next part --------------
Index: dlls/kernel/heap.c
===================================================================
RCS file: /home/wine/wine/dlls/kernel/heap.c,v
retrieving revision 1.9
diff -u -r1.9 heap.c
--- dlls/kernel/heap.c 24 Jun 2004 04:08:33 -0000 1.9
+++ dlls/kernel/heap.c 5 Aug 2004 01:59:56 -0000
@@ -1027,17 +1027,15 @@
}
/***********************************************************************
- * GlobalMemoryStatus (KERNEL32.@)
- * Provides information about the status of the memory, so apps can tell
- * roughly how much they are able to allocate
+ * GlobalMemoryStatusEx (KERNEL32.@)
+ * A version of GlobalMemoryStatus that can deal with memory over 4GB
*
* RETURNS
- * None
+ * TRUE
*/
-VOID WINAPI GlobalMemoryStatus(
- LPMEMORYSTATUS lpmem
-) {
- static MEMORYSTATUS cached_memstatus;
+BOOL WINAPI GlobalMemoryStatusEx( LPMEMORYSTATUSEX lpmemex )
+{
+ static MEMORYSTATUSEX cached_memstatus;
static int cache_lastchecked = 0;
SYSTEM_INFO si;
#ifdef linux
@@ -1049,16 +1047,17 @@
int mib[2] = { CTL_HW };
#endif
if (time(NULL)==cache_lastchecked) {
- memcpy(lpmem,&cached_memstatus,sizeof(MEMORYSTATUS));
- return;
+ memcpy(lpmemex,&cached_memstatus,sizeof(*lpmemex));
+ return TRUE;
}
cache_lastchecked = time(NULL);
- lpmem->dwMemoryLoad = 0;
- lpmem->dwTotalPhys = 16*1024*1024;
- lpmem->dwAvailPhys = 16*1024*1024;
- lpmem->dwTotalPageFile = 16*1024*1024;
- lpmem->dwAvailPageFile = 16*1024*1024;
+ lpmemex->dwLength = sizeof(*lpmemex);
+ lpmemex->dwMemoryLoad = 0;
+ lpmemex->ullTotalPhys = 16*1024*1024;
+ lpmemex->ullAvailPhys = 16*1024*1024;
+ lpmemex->ullTotalPageFile = 16*1024*1024;
+ lpmemex->ullAvailPageFile = 16*1024*1024;
#ifdef linux
f = fopen( "/proc/meminfo", "r" );
@@ -1067,44 +1066,43 @@
char buffer[256];
int total, used, free, shared, buffers, cached;
- lpmem->dwLength = sizeof(MEMORYSTATUS);
- lpmem->dwTotalPhys = lpmem->dwAvailPhys = 0;
- lpmem->dwTotalPageFile = lpmem->dwAvailPageFile = 0;
+ lpmemex->ullTotalPhys = lpmemex->ullAvailPhys = 0;
+ lpmemex->ullTotalPageFile = lpmemex->ullAvailPageFile = 0;
while (fgets( buffer, sizeof(buffer), f ))
{
/* old style /proc/meminfo ... */
if (sscanf( buffer, "Mem: %d %d %d %d %d %d", &total, &used, &free, &shared, &buffers, &cached ))
{
- lpmem->dwTotalPhys += total;
- lpmem->dwAvailPhys += free + buffers + cached;
+ lpmemex->ullTotalPhys += total;
+ lpmemex->ullAvailPhys += free + buffers + cached;
}
if (sscanf( buffer, "Swap: %d %d %d", &total, &used, &free ))
{
- lpmem->dwTotalPageFile += total;
- lpmem->dwAvailPageFile += free;
+ lpmemex->ullTotalPageFile += total;
+ lpmemex->ullAvailPageFile += free;
}
/* new style /proc/meminfo ... */
if (sscanf(buffer, "MemTotal: %d", &total))
- lpmem->dwTotalPhys = total*1024;
+ lpmemex->ullTotalPhys = total*1024;
if (sscanf(buffer, "MemFree: %d", &free))
- lpmem->dwAvailPhys = free*1024;
+ lpmemex->ullAvailPhys = free*1024;
if (sscanf(buffer, "SwapTotal: %d", &total))
- lpmem->dwTotalPageFile = total*1024;
+ lpmemex->ullTotalPageFile = total*1024;
if (sscanf(buffer, "SwapFree: %d", &free))
- lpmem->dwAvailPageFile = free*1024;
+ lpmemex->ullAvailPageFile = free*1024;
if (sscanf(buffer, "Buffers: %d", &buffers))
- lpmem->dwAvailPhys += buffers*1024;
+ lpmemex->ullAvailPhys += buffers*1024;
if (sscanf(buffer, "Cached: %d", &cached))
- lpmem->dwAvailPhys += cached*1024;
+ lpmemex->ullAvailPhys += cached*1024;
}
fclose( f );
- if (lpmem->dwTotalPhys)
+ if (lpmemex->ullTotalPhys)
{
- DWORD TotalPhysical = lpmem->dwTotalPhys+lpmem->dwTotalPageFile;
- DWORD AvailPhysical = lpmem->dwAvailPhys+lpmem->dwAvailPageFile;
- lpmem->dwMemoryLoad = (TotalPhysical-AvailPhysical)
+ DWORDLONG TotalPhysical = lpmemex->ullTotalPhys+lpmemex->ullTotalPageFile;
+ DWORDLONG AvailPhysical = lpmemex->ullAvailPhys+lpmemex->ullAvailPageFile;
+ lpmemex->dwMemoryLoad = (TotalPhysical-AvailPhysical)
/ (TotalPhysical / 100);
}
}
@@ -1115,7 +1113,7 @@
sysctl(mib, 2, tmp, &size_sys, NULL, 0);
if (tmp && *tmp)
{
- lpmem->dwTotalPhys = *tmp;
+ lpmemex->ullTotalPhys = *tmp;
free(tmp);
mib[1] = HW_USERMEM;
sysctl(mib, 2, NULL, &size_sys, NULL, 0);
@@ -1123,83 +1121,111 @@
sysctl(mib, 2, tmp, &size_sys, NULL, 0);
if (tmp && *tmp)
{
- lpmem->dwAvailPhys = *tmp;
- lpmem->dwTotalPageFile = *tmp;
- lpmem->dwAvailPageFile = *tmp;
- lpmem->dwMemoryLoad = lpmem->dwTotalPhys - lpmem->dwAvailPhys;
+ lpmemex->ullAvailPhys = *tmp;
+ lpmemex->ullTotalPageFile = *tmp;
+ lpmemex->ullAvailPageFile = *tmp;
+ lpmemex->ullMemoryLoad = lpmemex->ullTotalPhys - lpmemex->ullAvailPhys;
} else
{
- lpmem->dwAvailPhys = lpmem->dwTotalPhys;
- lpmem->dwTotalPageFile = lpmem->dwTotalPhys;
- lpmem->dwAvailPageFile = lpmem->dwTotalPhys;
- lpmem->dwMemoryLoad = 0;
+ lpmemex->ullAvailPhys = lpmemex->ullTotalPhys;
+ lpmemex->ullTotalPageFile = lpmemex->ullTotalPhys;
+ lpmemex->ullAvailPageFile = lpmemex->ullTotalPhys;
+ lpmemex->ullMemoryLoad = 0;
}
free(tmp);
}
#endif
- /* Some applications (e.g. QuickTime 6) crash if we tell them there
- * is more than 2GB of physical memory.
- */
- if (lpmem->dwTotalPhys >= 2U*1024*1024*1024)
- {
- lpmem->dwTotalPhys=2U*1024*1024*1024 - 1;
- lpmem->dwAvailPhys=2U*1024*1024*1024 - 1;
- }
-
- /* work around for broken photoshop 4 installer */
- if (lpmem->dwAvailPhys + lpmem->dwAvailPageFile >= 2U*1024*1024*1024)
- lpmem->dwAvailPageFile = 2U*1024*1024*1024 - lpmem->dwAvailPhys - 1;
/* FIXME: should do something for other systems */
GetSystemInfo(&si);
- lpmem->dwTotalVirtual = (char*)si.lpMaximumApplicationAddress-(char*)si.lpMinimumApplicationAddress;
+ lpmemex->ullTotalVirtual = (char*)si.lpMaximumApplicationAddress-(char*)si.lpMinimumApplicationAddress;
/* FIXME: we should track down all the already allocated VM pages and substract them, for now arbitrarily remove 64KB so that it matches NT */
- lpmem->dwAvailVirtual = lpmem->dwTotalVirtual-64*1024;
- memcpy(&cached_memstatus,lpmem,sizeof(MEMORYSTATUS));
+ lpmemex->ullAvailVirtual = lpmemex->ullTotalVirtual-64*1024;
+ memcpy(&cached_memstatus,lpmemex,sizeof(*lpmemex));
/* it appears some memory display programs want to divide by these values */
- if(lpmem->dwTotalPageFile==0)
- lpmem->dwTotalPageFile++;
+ if(lpmemex->ullTotalPageFile==0)
+ lpmemex->ullTotalPageFile++;
+
+ if(lpmemex->ullAvailPageFile==0)
+ lpmemex->ullAvailPageFile++;
- if(lpmem->dwAvailPageFile==0)
- lpmem->dwAvailPageFile++;
+ /* MSDN says about AvailExtendedVirtual: Size of unreserved and uncommitted
+ memory in the extended portion of the virtual address space of the calling
+ process, in bytes.
+ However, I don't know what this means, so set it to zero :(
+ */
+ lpmemex->ullAvailExtendedVirtual = 0;
+
+ TRACE("<-- LPMEMORYSTATUSEX: dwLength %ld, dwMemoryLoad %ld, ullTotalPhys %lld, ullAvailPhys %lld,"
+ " ullTotalPageFile %lld, ullAvailPageFile %lld, ullTotalVirtual %lld, ullAvailVirtual %lld\n",
+ lpmemex->dwLength, lpmemex->dwMemoryLoad, lpmemex->ullTotalPhys, lpmemex->ullAvailPhys,
+ lpmemex->ullTotalPageFile, lpmemex->ullAvailPageFile, lpmemex->ullTotalVirtual,
+ lpmemex->ullAvailVirtual);
- TRACE("<-- LPMEMORYSTATUS: dwLength %ld, dwMemoryLoad %ld, dwTotalPhys %ld, dwAvailPhys %ld,"
- " dwTotalPageFile %ld, dwAvailPageFile %ld, dwTotalVirtual %ld, dwAvailVirtual %ld\n",
- lpmem->dwLength, lpmem->dwMemoryLoad, lpmem->dwTotalPhys, lpmem->dwAvailPhys,
- lpmem->dwTotalPageFile, lpmem->dwAvailPageFile, lpmem->dwTotalVirtual,
- lpmem->dwAvailVirtual);
+ return TRUE;
}
/***********************************************************************
- * GlobalMemoryStatusEx (KERNEL32.@)
- * A version of GlobalMemoryStatus that can deal with memory over 4GB
+ * GlobalMemoryStatus (KERNEL32.@)
+ * Provides information about the status of the memory, so apps can tell
+ * roughly how much they are able to allocate
*
* RETURNS
* None
*/
-BOOL WINAPI GlobalMemoryStatusEx( LPMEMORYSTATUSEX lpBuffer )
+VOID WINAPI GlobalMemoryStatus( LPMEMORYSTATUS lpBuffer )
{
- MEMORYSTATUS memstatus;
+ MEMORYSTATUSEX memstatus;
+ OSVERSIONINFOA osver;
+
+ /* Because GlobalMemoryStatus is identical to GlobalMemoryStatusEX save
+ for one extra field in the struct, and the lack of a bug, we simply
+ call GlobalMemoryStatusEx and copy the values across. */
+ GlobalMemoryStatusEx(&memstatus);
+
+ lpBuffer->dwLength = sizeof(*lpBuffer);
+ lpBuffer->dwMemoryLoad = memstatus.dwMemoryLoad;
+
+ /* Windows 2000 and later report -1 when values are greater than 4 Gb.
+ * NT reports values modulo 4 Gb.
+ * Values between 2 Gb and 4 Gb are rounded down to 2 Gb.
+ */
+ GetVersionExA(&osver);
- /* Because GlobalMemoryStatusEx is identical to GlobalMemoryStatus save
- for one extra field in the struct, and the lack of a bug, we simply
- call GlobalMemoryStatus and copy the values across. */
- FIXME("we should emulate the 4GB bug here, as per MSDN\n");
- GlobalMemoryStatus(&memstatus);
- lpBuffer->dwMemoryLoad = memstatus.dwMemoryLoad;
- lpBuffer->ullTotalPhys = memstatus.dwTotalPhys;
- lpBuffer->ullAvailPhys = memstatus.dwAvailPhys;
- lpBuffer->ullTotalPageFile = memstatus.dwTotalPageFile;
- lpBuffer->ullAvailPageFile = memstatus.dwAvailPageFile;
- lpBuffer->ullTotalVirtual = memstatus.dwTotalVirtual;
- lpBuffer->ullAvailVirtual = memstatus.dwAvailVirtual;
- /* MSDN says about AvailExtendedVirtual: Size of unreserved and uncommitted
- memory in the extended portion of the virtual address space of the calling
- process, in bytes.
- However, I don't know what this means, so set it to zero :(
- */
- lpBuffer->ullAvailExtendedVirtual = 0;
- return 1;
+ if ( osver.dwMajorVersion >= 5 )
+ {
+ lpBuffer->dwTotalPhys = (memstatus.ullTotalPhys > 0xffffffffLL) ? -1 :
+ (memstatus.ullTotalPhys > 0x7fffffff) ? 0x7fffffff : memstatus.ullTotalPhys;
+ lpBuffer->dwAvailPhys = (memstatus.ullAvailPhys > 0xffffffffLL) ? -1 :
+ (memstatus.ullAvailPhys > 0x7fffffff) ? 0x7fffffff : memstatus.ullAvailPhys;
+ lpBuffer->dwTotalPageFile = (memstatus.ullTotalPageFile > 0xffffffffLL) ? -1 :
+ (memstatus.ullTotalPageFile > 0x7fffffff) ? 0x7fffffff : memstatus.ullTotalPageFile;
+ lpBuffer->dwAvailPageFile = (memstatus.ullAvailPageFile > 0xffffffffLL) ? -1 :
+ (memstatus.ullAvailPageFile > 0x7fffffff) ? 0x7fffffff : memstatus.ullAvailPageFile;
+ lpBuffer->dwTotalVirtual = (memstatus.ullTotalVirtual > 0xffffffffLL) ? -1 :
+ (memstatus.ullTotalVirtual > 0x7fffffff) ? 0x7fffffff : memstatus.ullTotalVirtual;
+ lpBuffer->dwAvailVirtual = (memstatus.ullAvailVirtual > 0xffffffffLL) ? -1 :
+ (memstatus.ullAvailVirtual > 0x7fffffff) ? 0x7fffffff : memstatus.ullAvailVirtual;
+ }
+ else /* duplicate NT bug */
+ {
+ lpBuffer->dwTotalPhys = (memstatus.ullTotalPhys > 0xffffffffLL) ? memstatus.ullTotalPhys :
+ (memstatus.ullTotalPhys > 0x7fffffff) ? 0x7fffffff : memstatus.ullTotalPhys;
+ lpBuffer->dwAvailPhys = (memstatus.ullAvailPhys > 0xffffffffLL) ? memstatus.ullAvailPhys :
+ (memstatus.ullAvailPhys > 0x7fffffff) ? 0x7fffffff : memstatus.ullAvailPhys;
+ lpBuffer->dwTotalPageFile = (memstatus.ullTotalPageFile > 0xffffffffLL) ? memstatus.ullTotalPageFile :
+ (memstatus.ullTotalPageFile > 0x7fffffff) ? 0x7fffffff : memstatus.ullTotalPageFile;
+ lpBuffer->dwAvailPageFile = (memstatus.ullAvailPageFile > 0xffffffffLL) ? memstatus.ullAvailPageFile :
+ (memstatus.ullAvailPageFile > 0x7fffffff) ? 0x7fffffff : memstatus.ullAvailPageFile;
+ lpBuffer->dwTotalVirtual = (memstatus.ullTotalVirtual > 0xffffffffLL) ? memstatus.ullTotalVirtual :
+ (memstatus.ullTotalVirtual > 0x7fffffff) ? 0x7fffffff : memstatus.ullTotalVirtual;
+ lpBuffer->dwAvailVirtual = (memstatus.ullAvailVirtual > 0xffffffffLL) ? memstatus.ullAvailVirtual :
+ (memstatus.ullAvailVirtual > 0x7fffffff) ? 0x7fffffff : memstatus.ullAvailVirtual;
+ }
+
+ /* work around for broken photoshop 4 installer */
+ if ( lpBuffer->dwAvailPhys + lpBuffer->dwAvailPageFile >= 2U*1024*1024*1024)
+ lpBuffer->dwAvailPageFile = 2U*1024*1024*1024 - lpBuffer->dwAvailPhys - 1;
}
Index: include/winbase.h
===================================================================
RCS file: /home/wine/wine/include/winbase.h,v
retrieving revision 1.211
diff -u -r1.211 winbase.h
--- include/winbase.h 14 Jun 2004 19:40:44 -0000 1.211
+++ include/winbase.h 5 Aug 2004 02:00:04 -0000
@@ -1489,6 +1489,7 @@
BOOL WINAPI GetVolumePathNamesForVolumeNameW(LPCWSTR,LPWSTR,DWORD,PDWORD);
#define GetVolumePathNamesForVolumeName WINELIB_NAME_AW(GetVolumePathNamesForVolumeName)
VOID WINAPI GlobalMemoryStatus(LPMEMORYSTATUS);
+BOOL WINAPI GlobalMemoryStatusEx(LPMEMORYSTATUSEX);
LPVOID WINAPI HeapAlloc(HANDLE,DWORD,SIZE_T);
SIZE_T WINAPI HeapCompact(HANDLE,DWORD);
HANDLE WINAPI HeapCreate(DWORD,SIZE_T,SIZE_T);
More information about the wine-patches
mailing list