vma-iter, get-rusage-as: Add OpenBSD support.
authorBruno Haible <bruno@clisp.org>
Thu, 27 Jan 2011 10:42:45 +0000 (11:42 +0100)
committerBruno Haible <bruno@clisp.org>
Thu, 27 Jan 2011 10:42:45 +0000 (11:42 +0100)
* modules/vma-iter (configure.ac): Test for mquery.
* lib/vma-iter.h (VMA_ITERATE_SUPPORTED): Define also on OpenBSD.
* lib/vma-iter.c: Include <sys/mman.h>.
(vma_iterate): Add an implementation based on mquery().
* lib/resource-ext.h (get_rusage_as): Update comments.
* lib/get-rusage-as.c: Likewise.
* lib/get-rusage-data.c: Likewise.

ChangeLog
lib/get-rusage-as.c
lib/get-rusage-data.c
lib/resource-ext.h
lib/vma-iter.c
lib/vma-iter.h
modules/vma-iter

index 611dda217604369881d3e467da8168881e950823..34aa13427e644b6811c733258418570ec5326fe6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2011-01-27  Bruno Haible  <bruno@clisp.org>
+
+       vma-iter, get-rusage-as: Add OpenBSD support.
+       * modules/vma-iter (configure.ac): Test for mquery.
+       * lib/vma-iter.h (VMA_ITERATE_SUPPORTED): Define also on OpenBSD.
+       * lib/vma-iter.c: Include <sys/mman.h>.
+       (vma_iterate): Add an implementation based on mquery().
+       * lib/resource-ext.h (get_rusage_as): Update comments.
+       * lib/get-rusage-as.c: Likewise.
+       * lib/get-rusage-data.c: Likewise.
+
 2011-01-26  Karl Berry  <karl@gnu.org>
 
        * doc/Makefile (lang_env, makeinfo_prog, manual_opts): new
index 46f1f212c270b0b5087fd0cdbb23938db7c40876..5567f95703061a1fd0f17e6bcca9f2e7d3dd1dd0 100644 (file)
@@ -66,7 +66,7 @@
 
    OpenBSD:
      a) setrlimit exists, but RLIMIT_AS is not defined.
-     b) No VMA iteration API exists.
+     b) mquery() can be used to find out about the virtual memory areas.
 
    AIX:
      a) setrlimit with RLIMIT_AS succeeds but does not really work: The OS
index 20c49ce19db3ed68d30484802f3c849224530f48..1b9214b5cc0e0182cd08d63aefac93c8c48d9fd2 100644 (file)
@@ -69,7 +69,9 @@
 
    OpenBSD:
      a) setrlimit with RLIMIT_DATA works.
-     b) No VMA iteration API exists.
+     b) mquery() can be used to find out about the virtual memory areas.
+     get_rusage_data_via_setrlimit() works much better than
+     get_rusage_data_via_iterator().
      Note that malloc() appears to use mmap() for both large and small
      allocations.
 
index 6e43e70d33443a9e19da0a7a85dd23e241c9eba9..145ce252c97ba3999e7a06bfa1dcd66ddd502390 100644 (file)
@@ -28,7 +28,7 @@ extern "C" {
 /* Returns the amount of address space currently in use by the current
    process, or zero if unknown.
    This is the quantity which is limited by setrlimit(RLIMIT_AS,...).
-   Note: This function always returns zero on OpenBSD and AIX.  */
+   Note: This function always returns zero on AIX.  */
 extern uintptr_t get_rusage_as (void);
 
 /* Returns the size of the data segment, or zero if unknown.
index 46c021297a51b7de172bb3a0d525b9e59b747341..1de69d803ebd90f1718beb22a70d63ac21e3ae18 100644 (file)
 # include <OS.h>
 #endif
 
+#if HAVE_MQUERY /* OpenBSD */
+# include <sys/types.h>
+# include <sys/mman.h> /* mquery */
+#endif
+
 
 /* Support for reading text files in the /proc file system.  */
 
@@ -490,6 +495,99 @@ vma_iterate (vma_iterate_callback_fn callback, void *data)
         break;
     }
 
+#elif HAVE_MQUERY /* OpenBSD */
+
+  uintptr_t pagesize;
+  uintptr_t address;
+  int /*bool*/ address_known_mapped;
+
+  pagesize = getpagesize ();
+  /* Avoid calling mquery with a NULL first argument, because this argument
+     value has a specific meaning.  We know the NULL page is unmapped.  */
+  address = pagesize;
+  address_known_mapped = 0;
+  for (;;)
+    {
+      /* Test whether the page at address is mapped.  */
+      if (address_known_mapped
+          || mquery ((void *) address, pagesize, 0, MAP_FIXED, -1, 0)
+             == (void *) -1)
+        {
+          /* The page at address is mapped.
+             This is the start of an interval.  */
+          uintptr_t start = address;
+          uintptr_t end;
+
+          /* Find the end of the interval.  */
+          end = (uintptr_t) mquery ((void *) address, pagesize, 0, 0, -1, 0);
+          if (end == (uintptr_t) (void *) -1)
+            end = 0; /* wrap around */
+          address = end;
+
+          /* It's too complicated to find out about the flags.  Just pass 0.  */
+          if (callback (data, start, end, 0))
+            break;
+
+          if (address < pagesize) /* wrap around? */
+            break;
+        }
+      /* Here we know that the page at address is unmapped.  */
+      {
+        uintptr_t query_size = pagesize;
+
+        address += pagesize;
+
+        /* Query larger and larger blocks, to get through the unmapped address
+           range with few mquery() calls.  */
+        for (;;)
+          {
+            if (2 * query_size > query_size)
+              query_size = 2 * query_size;
+            if (address + query_size - 1 < query_size) /* wrap around? */
+              {
+                address_known_mapped = 0;
+                break;
+              }
+            if (mquery ((void *) address, query_size, 0, MAP_FIXED, -1, 0)
+                == (void *) -1)
+              {
+                /* Not all the interval [address .. address + query_size - 1]
+                   is unmapped.  */
+                address_known_mapped = (query_size == pagesize);
+                break;
+              }
+            /* The interval [address .. address + query_size - 1] is
+               unmapped.  */
+            address += query_size;
+          }
+        /* Reduce the query size again, to determine the precise size of the
+           unmapped interval that starts at address.  */
+        while (query_size > pagesize)
+          {
+            query_size = query_size / 2;
+            if (address + query_size - 1 >= query_size)
+              {
+                if (mquery ((void *) address, query_size, 0, MAP_FIXED, -1, 0)
+                    != (void *) -1)
+                  {
+                    /* The interval [address .. address + query_size - 1] is
+                       unmapped.  */
+                    address += query_size;
+                    address_known_mapped = 0;
+                  }
+                else
+                  address_known_mapped = (query_size == pagesize);
+              }
+          }
+        /* Here again query_size = pagesize, and
+           either address + pagesize - 1 < pagesize, or
+           mquery ((void *) address, pagesize, 0, MAP_FIXED, -1, 0) fails.
+           So, the unmapped area ends at address.  */
+      }
+      if (address + pagesize - 1 < pagesize) /* wrap around? */
+        break;
+    }
+
 #endif
 }
 
index c3bc9cfb1079f24e9edeecc7d0a9124ecdce1970..e24de65c067591bb6d5ba7b5cfc8d9e045fc50e9 100644 (file)
@@ -51,7 +51,7 @@ extern void vma_iterate (vma_iterate_callback_fn callback, void *data);
    this platform.
    Note that even when this macro is defined, vma_iterate() may still fail to
    find any virtual memory area, for example if /proc is not mounted.  */
-#if defined __linux__ || defined __FreeBSD__ || defined __NetBSD__ || defined __sgi || defined __osf__ || (defined __APPLE__ && defined __MACH__) || (defined _WIN32 || defined __WIN32__) || defined __CYGWIN__ || defined __BEOS__ || defined __HAIKU__
+#if defined __linux__ || defined __FreeBSD__ || defined __NetBSD__ || defined __sgi || defined __osf__ || (defined __APPLE__ && defined __MACH__) || (defined _WIN32 || defined __WIN32__) || defined __CYGWIN__ || defined __BEOS__ || defined __HAIKU__ || HAVE_MQUERY
 # define VMA_ITERATE_SUPPORTED 1
 #endif
 
index 262e41f31ce7a38be277ee2fd42a1afcf891b6d4..e0a480bd3047989f1030873e5420238aabe8ec4a 100644 (file)
@@ -14,6 +14,7 @@ getpagesize
 
 configure.ac:
 gl_FUNC_MMAP_ANON
+AC_CHECK_FUNCS_ONCE([mquery])
 
 Makefile.am:
 lib_SOURCES += vma-iter.c