Index: xz/src/common/tuklib_physmem.c |
=================================================================== |
--- xz/src/common/tuklib_physmem.c (revision 0) |
+++ xz/src/common/tuklib_physmem.c (revision 0) |
@@ -0,0 +1,196 @@ |
+/////////////////////////////////////////////////////////////////////////////// |
+// |
+/// \file tuklib_physmem.c |
+/// \brief Get the amount of physical memory |
+// |
+// Author: Lasse Collin |
+// |
+// This file has been put into the public domain. |
+// You can do whatever you want with this file. |
+// |
+/////////////////////////////////////////////////////////////////////////////// |
+ |
+#include "tuklib_physmem.h" |
+ |
+// We want to use Windows-specific code on Cygwin, which also has memory |
+// information available via sysconf(), but on Cygwin 1.5 and older it |
+// gives wrong results (from our point of view). |
+#if defined(_WIN32) || defined(__CYGWIN__) |
+# ifndef _WIN32_WINNT |
+# define _WIN32_WINNT 0x0500 |
+# endif |
+# include <windows.h> |
+ |
+#elif defined(__OS2__) |
+# define INCL_DOSMISC |
+# include <os2.h> |
+ |
+#elif defined(__DJGPP__) |
+# include <dpmi.h> |
+ |
+#elif defined(__VMS) |
+# include <lib$routines.h> |
+# include <syidef.h> |
+# include <ssdef.h> |
+ |
+// AIX |
+#elif defined(TUKLIB_PHYSMEM_AIX) |
+# include <sys/systemcfg.h> |
+ |
+#elif defined(TUKLIB_PHYSMEM_SYSCONF) |
+# include <unistd.h> |
+ |
+#elif defined(TUKLIB_PHYSMEM_SYSCTL) |
+# ifdef HAVE_SYS_PARAM_H |
+# include <sys/param.h> |
+# endif |
+# include <sys/sysctl.h> |
+ |
+// Tru64 |
+#elif defined(TUKLIB_PHYSMEM_GETSYSINFO) |
+# include <sys/sysinfo.h> |
+# include <machine/hal_sysinfo.h> |
+ |
+// HP-UX |
+#elif defined(TUKLIB_PHYSMEM_PSTAT_GETSTATIC) |
+# include <sys/param.h> |
+# include <sys/pstat.h> |
+ |
+// IRIX |
+#elif defined(TUKLIB_PHYSMEM_GETINVENT_R) |
+# include <invent.h> |
+ |
+// This sysinfo() is Linux-specific. |
+#elif defined(TUKLIB_PHYSMEM_SYSINFO) |
+# include <sys/sysinfo.h> |
+#endif |
+ |
+ |
+extern uint64_t |
+tuklib_physmem(void) |
+{ |
+ uint64_t ret = 0; |
+ |
+#if defined(_WIN32) || defined(__CYGWIN__) |
+ if ((GetVersion() & 0xFF) >= 5) { |
+ // Windows 2000 and later have GlobalMemoryStatusEx() which |
+ // supports reporting values greater than 4 GiB. To keep the |
+ // code working also on older Windows versions, use |
+ // GlobalMemoryStatusEx() conditionally. |
+ HMODULE kernel32 = GetModuleHandle("kernel32.dll"); |
+ if (kernel32 != NULL) { |
+ BOOL (WINAPI *gmse)(LPMEMORYSTATUSEX) = GetProcAddress( |
+ kernel32, "GlobalMemoryStatusEx"); |
+ if (gmse != NULL) { |
+ MEMORYSTATUSEX meminfo; |
+ meminfo.dwLength = sizeof(meminfo); |
+ if (gmse(&meminfo)) |
+ ret = meminfo.ullTotalPhys; |
+ } |
+ } |
+ } |
+ |
+ if (ret == 0) { |
+ // GlobalMemoryStatus() is supported by Windows 95 and later, |
+ // so it is fine to link against it unconditionally. Note that |
+ // GlobalMemoryStatus() has no return value. |
+ MEMORYSTATUS meminfo; |
+ meminfo.dwLength = sizeof(meminfo); |
+ GlobalMemoryStatus(&meminfo); |
+ ret = meminfo.dwTotalPhys; |
+ } |
+ |
+#elif defined(__OS2__) |
+ unsigned long mem; |
+ if (DosQuerySysInfo(QSV_TOTPHYSMEM, QSV_TOTPHYSMEM, |
+ &mem, sizeof(mem)) == 0) |
+ ret = mem; |
+ |
+#elif defined(__DJGPP__) |
+ __dpmi_free_mem_info meminfo; |
+ if (__dpmi_get_free_memory_information(&meminfo) == 0 |
+ && meminfo.total_number_of_physical_pages |
+ != (unsigned long)-1) |
+ ret = (uint64_t)meminfo.total_number_of_physical_pages * 4096; |
+ |
+#elif defined(__VMS) |
+ int vms_mem; |
+ int val = SYI$_MEMSIZE; |
+ if (LIB$GETSYI(&val, &vms_mem, 0, 0, 0, 0) == SS$_NORMAL) |
+ ret = (uint64_t)vms_mem * 8192; |
+ |
+#elif defined(TUKLIB_PHYSMEM_AIX) |
+ ret = _system_configuration.physmem; |
+ |
+#elif defined(TUKLIB_PHYSMEM_SYSCONF) |
+ const long pagesize = sysconf(_SC_PAGESIZE); |
+ const long pages = sysconf(_SC_PHYS_PAGES); |
+ if (pagesize != -1 && pages != -1) |
+ // According to docs, pagesize * pages can overflow. |
+ // Simple case is 32-bit box with 4 GiB or more RAM, |
+ // which may report exactly 4 GiB of RAM, and "long" |
+ // being 32-bit will overflow. Casting to uint64_t |
+ // hopefully avoids overflows in the near future. |
+ ret = (uint64_t)pagesize * (uint64_t)pages; |
+ |
+#elif defined(TUKLIB_PHYSMEM_SYSCTL) |
+ int name[2] = { |
+ CTL_HW, |
+#ifdef HW_PHYSMEM64 |
+ HW_PHYSMEM64 |
+#else |
+ HW_PHYSMEM |
+#endif |
+ }; |
+ union { |
+ uint32_t u32; |
+ uint64_t u64; |
+ } mem; |
+ size_t mem_ptr_size = sizeof(mem.u64); |
+ if (sysctl(name, 2, &mem.u64, &mem_ptr_size, NULL, 0) != -1) { |
+ // IIRC, 64-bit "return value" is possible on some 64-bit |
+ // BSD systems even with HW_PHYSMEM (instead of HW_PHYSMEM64), |
+ // so support both. |
+ if (mem_ptr_size == sizeof(mem.u64)) |
+ ret = mem.u64; |
+ else if (mem_ptr_size == sizeof(mem.u32)) |
+ ret = mem.u32; |
+ } |
+ |
+#elif defined(TUKLIB_PHYSMEM_GETSYSINFO) |
+ // Docs are unclear if "start" is needed, but it doesn't hurt |
+ // much to have it. |
+ int memkb; |
+ int start = 0; |
+ if (getsysinfo(GSI_PHYSMEM, (caddr_t)&memkb, sizeof(memkb), &start) |
+ != -1) |
+ ret = (uint64_t)memkb * 1024; |
+ |
+#elif defined(TUKLIB_PHYSMEM_PSTAT_GETSTATIC) |
+ struct pst_static pst; |
+ if (pstat_getstatic(&pst, sizeof(pst), 1, 0) != -1) |
+ ret = (uint64_t)pst.physical_memory * (uint64_t)pst.page_size; |
+ |
+#elif defined(TUKLIB_PHYSMEM_GETINVENT_R) |
+ inv_state_t *st = NULL; |
+ if (setinvent_r(&st) != -1) { |
+ inventory_t *i; |
+ while ((i = getinvent_r(st)) != NULL) { |
+ if (i->inv_class == INV_MEMORY |
+ && i->inv_type == INV_MAIN_MB) { |
+ ret = (uint64_t)i->inv_state << 20; |
+ break; |
+ } |
+ } |
+ |
+ endinvent_r(st); |
+ } |
+ |
+#elif defined(TUKLIB_PHYSMEM_SYSINFO) |
+ struct sysinfo si; |
+ if (sysinfo(&si) == 0) |
+ ret = (uint64_t)si.totalram * si.mem_unit; |
+#endif |
+ |
+ return ret; |
+} |
Property changes on: xz/src/common/tuklib_physmem.c |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |