# include <sys/resource.h>
#endif
+#ifdef WIN32
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+#endif
+
#include "viralloc.h"
#include "virhostmem.h"
-#include "physmem.h"
#include "virerror.h"
#include "virarch.h"
#include "virfile.h"
}
+#ifdef WIN32
+/* MEMORYSTATUSEX is missing from older windows headers, so define
+ a local replacement. */
+typedef struct
+{
+ DWORD dwLength;
+ DWORD dwMemoryLoad;
+ DWORDLONG ullTotalPhys;
+ DWORDLONG ullAvailPhys;
+ DWORDLONG ullTotalPageFile;
+ DWORDLONG ullAvailPageFile;
+ DWORDLONG ullTotalVirtual;
+ DWORDLONG ullAvailVirtual;
+ DWORDLONG ullAvailExtendedVirtual;
+} lMEMORYSTATUSEX;
+typedef WINBOOL(WINAPI *PFN_MS_EX) (lMEMORYSTATUSEX*);
+#endif /* !WIN32 */
+
+static unsigned long long
+virHostMemGetTotal(void)
+{
+#if defined HAVE_SYSCTLBYNAME
+ /* This works on freebsd & macOS. */
+ unsigned long long physmem = 0;
+ size_t len = sizeof(physmem);
+
+ if (sysctlbyname("hw.physmem", &physmem, &len, NULL, 0) < 0) {
+ virReportSystemError(errno, "%s",
+ _("Unable to query memory total"));
+ return 0;
+ }
+
+ return physmem;
+#elif defined _SC_PHYS_PAGES && defined _SC_PAGESIZE
+ /* this works on linux */
+ long long pages;
+ long long pagesize;
+ if ((pages = sysconf(_SC_PHYS_PAGES)) < 0) {
+ virReportSystemError(errno, "%s",
+ _("Unable to query memory total"));
+ return 0;
+ }
+ if ((pagesize = sysconf(_SC_PAGESIZE)) < 0) {
+ virReportSystemError(errno, "%s",
+ _("Unable to query memory page size"));
+ return 0;
+ }
+ return (unsigned long long)pages * (unsigned long long)pagesize;
+#elif defined WIN32
+ PFN_MS_EX pfnex;
+ HMODULE h = GetModuleHandle("kernel32.dll");
+
+ if (!h) {
+ virReportSystemError(errno, "%s",
+ _("Unable to access kernel32.dll"));
+ return 0;
+ }
+
+ /* Use GlobalMemoryStatusEx if available. */
+ if ((pfnex = (PFN_MS_EX) GetProcAddress(h, "GlobalMemoryStatusEx"))) {
+ lMEMORYSTATUSEX lms_ex;
+ lms_ex.dwLength = sizeof(lms_ex);
+ if (!pfnex(&lms_ex)) {
+ virReportSystemError(EIO, "%s",
+ _("Unable to query memory total"));
+ return 0;
+ }
+ return lms_ex.ullTotalPhys;
+ } else {
+ /* Fall back to GlobalMemoryStatus which is always available.
+ but returns wrong results for physical memory > 4GB. */
+ MEMORYSTATUS ms;
+ GlobalMemoryStatus(&ms);
+ return ms.dwTotalPhys;
+ }
+#endif
+}
+
+
+static unsigned long long
+virHostMemGetAvailable(void)
+{
+#if defined HAVE_SYSCTLBYNAME
+ /* This works on freebsd and macOS */
+ unsigned long long usermem = 0;
+ size_t len = sizeof(usermem);
+
+ if (sysctlbyname("hw.usermem", &usermem, &len, NULL, 0) < 0) {
+ virReportSystemError(errno, "%s",
+ _("Unable to query memory available"));
+ return 0;
+ }
+
+ return usermem;
+#elif defined _SC_AVPHYS_PAGES && defined _SC_PAGESIZE
+ /* this works on linux */
+ long long pages;
+ long long pagesize;
+ if ((pages = sysconf(_SC_AVPHYS_PAGES)) < 0) {
+ virReportSystemError(errno, "%s",
+ _("Unable to query memory available"));
+ return 0;
+ }
+ if ((pagesize = sysconf(_SC_PAGESIZE)) < 0) {
+ virReportSystemError(errno, "%s",
+ _("Unable to query memory page size"));
+ return 0;
+ }
+ return (unsigned long long)pages * (unsigned long long)pagesize;
+#elif defined WIN32
+ PFN_MS_EX pfnex;
+ HMODULE h = GetModuleHandle("kernel32.dll");
+
+ if (!h) {
+ virReportSystemError(errno, "%s",
+ _("Unable to access kernel32.dll"));
+ return 0;
+ }
+
+ /* Use GlobalMemoryStatusEx if available. */
+ if ((pfnex = (PFN_MS_EX) GetProcAddress(h, "GlobalMemoryStatusEx"))) {
+ lMEMORYSTATUSEX lms_ex;
+ lms_ex.dwLength = sizeof(lms_ex);
+ if (!pfnex(&lms_ex)) {
+ virReportSystemError(EIO, "%s",
+ _("Unable to query memory available"));
+ return 0;
+ }
+ return lms_ex.ullAvailPhys;
+ } else {
+ /* Fall back to GlobalMemoryStatus which is always available.
+ but returns wrong results for physical memory > 4GB */
+ MEMORYSTATUS ms;
+ GlobalMemoryStatus(&ms);
+ return ms.dwAvailPhys;
+ }
+#endif
+}
+
+
static int
virHostMemGetCellsFreeFake(unsigned long long *freeMems,
int startCell,
int maxCells G_GNUC_UNUSED)
{
- double avail = physmem_available();
-
if (startCell != 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("start cell %d out of range (0-%d)"),
return -1;
}
- freeMems[0] = (unsigned long long)avail;
-
- if (!freeMems[0]) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("Cannot determine free memory"));
+ if ((freeMems[0] = virHostMemGetAvailable()) == 0)
return -1;
- }
return 1;
}
virHostMemGetInfoFake(unsigned long long *mem,
unsigned long long *freeMem)
{
- if (mem) {
- double total = physmem_total();
- if (!total) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("Cannot determine free memory"));
- return -1;
- }
-
- *mem = (unsigned long long) total;
- }
-
- if (freeMem) {
- double avail = physmem_available();
-
- if (!avail) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("Cannot determine free memory"));
- return -1;
- }
+ if (mem &&
+ (*mem = virHostMemGetTotal()) == 0)
+ return -1;
- *freeMem = (unsigned long long) avail;
- }
+ if (freeMem &&
+ (*freeMem = virHostMemGetAvailable()) == 0)
+ return -1;
return 0;
}