X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fget-rusage-as.c;h=5567f95703061a1fd0f17e6bcca9f2e7d3dd1dd0;hb=0576d58775046f35e81c47b29fecad1daf516336;hp=3ca13660084b883f707d851d619f5f14313368d6;hpb=6bd94e92ae44fbb68d228ec023a1c17c2a26fe63;p=gnulib.git diff --git a/lib/get-rusage-as.c b/lib/get-rusage-as.c index 3ca136600..5567f9570 100644 --- a/lib/get-rusage-as.c +++ b/lib/get-rusage-as.c @@ -61,11 +61,12 @@ NetBSD: a) setrlimit with RLIMIT_AS works. - b) No VMA iteration API exists. + b) The /proc/self/maps file contains a list of the virtual memory areas. + Both methods agree, 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 @@ -140,23 +141,7 @@ /* System support for get_rusage_as_via_iterator(). */ -#if defined __sgi || defined __osf__ /* IRIX, OSF/1 */ -# include /* memcpy */ -# include -# include /* PIOC*, prmap_t */ -#endif - -#if defined __APPLE__ && defined __MACH__ /* MacOS X */ -# include -#endif - -#if (defined _WIN32 || defined __WIN32__) || defined __CYGWIN__ /* Windows */ -# include -#endif - -#if defined __BEOS__ /* BeOS */ -# include -#endif +#include "vma-iter.h" #if HAVE_SETRLIMIT && defined RLIMIT_AS && HAVE_SYS_MMAN_H && HAVE_MPROTECT @@ -182,7 +167,7 @@ get_rusage_as_via_setrlimit (void) if (getrlimit (RLIMIT_AS, &orig_limit) < 0) { result = 0; - goto done; + goto done2; } if (orig_limit.rlim_max != RLIM_INFINITY @@ -192,7 +177,7 @@ get_rusage_as_via_setrlimit (void) So bail out. */ { result = 0; - goto done; + goto done2; } { @@ -223,7 +208,7 @@ get_rusage_as_via_setrlimit (void) { /* try_next could not be increased. */ result = low_bound; - goto done; + goto done1; } try_limit.rlim_max = orig_limit.rlim_max; @@ -311,378 +296,60 @@ get_rusage_as_via_setrlimit (void) result = low_bound; } + done1: /* Restore the original rlim_cur value. */ if (setrlimit (RLIMIT_AS, &orig_limit) < 0) abort (); - done: + done2: # if !HAVE_MAP_ANONYMOUS close (fd); # endif return result; } -#endif - - -/* Support for reading text files in the /proc file system. */ - -#if defined __linux__ || defined __FreeBSD__ /* || defined __CYGWIN__ */ - -/* Buffered read-only streams. - We cannot use here, because fopen() calls malloc(), and a malloc() - call may call mmap() and thus pre-allocate available memory. */ +#else -struct rofile - { - int fd; - size_t position; - size_t filled; - int eof_seen; - char buffer[1024]; - }; - -/* Open a read-only file stream. */ -static int -rof_open (struct rofile *rof, const char *filename) +static inline uintptr_t +get_rusage_as_via_setrlimit (void) { - int fd = open (filename, O_RDONLY); - if (fd < 0) - return -1; - rof->fd = fd; - rof->position = 0; - rof->filled = 0; - rof->eof_seen = 0; return 0; } -/* Return the next byte from a read-only file stream without consuming it, - or -1 at EOF. */ -static int -rof_peekchar (struct rofile *rof) -{ - if (rof->position == rof->filled) - { - if (rof->eof_seen) - return -1; - else - for (;;) - { - int n = read (rof->fd, rof->buffer, sizeof (rof->buffer)); -# ifdef EINTR - if (n < 0 && errno == EINTR) - continue; -# endif - if (n <= 0) - { - rof->eof_seen = 1; - return -1; - } - rof->filled = n; - rof->position = 0; - break; - } - } - return (unsigned char) rof->buffer[rof->position]; -} +#endif -/* Return the next byte from a read-only file stream, or -1 at EOF. */ -static int -rof_getchar (struct rofile *rof) -{ - int c = rof_peekchar (rof); - if (c >= 0) - rof->position++; - return c; -} -/* Parse an unsigned hexadecimal number from a read-only file stream. */ +#if VMA_ITERATE_SUPPORTED + static int -rof_scanf_lx (struct rofile *rof, unsigned long *valuep) +vma_iterate_callback (void *data, uintptr_t start, uintptr_t end, + unsigned int flags) { - unsigned long value = 0; - unsigned int numdigits = 0; - for (;;) - { - int c = rof_peekchar (rof); - if (c >= '0' && c <= '9') - value = (value << 4) + (c - '0'); - else if (c >= 'A' && c <= 'F') - value = (value << 4) + (c - 'A' + 10); - else if (c >= 'a' && c <= 'f') - value = (value << 4) + (c - 'a' + 10); - else - break; - rof_getchar (rof); - numdigits++; - } - if (numdigits == 0) - return -1; - *valuep = value; - return 0; -} + uintptr_t *totalp = (uintptr_t *) data; -/* Close a read-only file stream. */ -static void -rof_close (struct rofile *rof) -{ - close (rof->fd); + *totalp += end - start; + return 0; } -#endif - - static inline uintptr_t get_rusage_as_via_iterator (void) { -#if defined __linux__ /* || defined __CYGWIN__ */ - - struct rofile rof; - int c; - unsigned long total; - - /* Open the current process' maps file. It describes one VMA per line. */ - if (rof_open (&rof, "/proc/self/maps") < 0) - return 0; - - total = 0; - for (;;) - { - unsigned long start, end; - - if (!(rof_scanf_lx (&rof, &start) >= 0 - && rof_getchar (&rof) == '-' - && rof_scanf_lx (&rof, &end) >= 0)) - break; - while (c = rof_getchar (&rof), c != -1 && c != '\n') - ; - total += end - start; - } - rof_close (&rof); - return total; - -#elif defined __FreeBSD__ - - struct rofile rof; - int c; - unsigned long total; - - /* Open the current process' maps file. It describes one VMA per line. */ - if (rof_open (&rof, "/proc/curproc/map") < 0) - return 0; - - total = 0; - for (;;) - { - unsigned long start, end; - - if (!(rof_getchar (&rof) == '0' - && rof_getchar (&rof) == 'x' - && rof_scanf_lx (&rof, &start) >= 0)) - break; - while (c = rof_peekchar (&rof), c == ' ' || c == '\t') - rof_getchar (&rof); - if (!(rof_getchar (&rof) == '0' - && rof_getchar (&rof) == 'x' - && rof_scanf_lx (&rof, &end) >= 0)) - break; - while (c = rof_getchar (&rof), c != -1 && c != '\n') - continue; - total += end - start; - } - rof_close (&rof); - return total; - -#elif defined __sgi || defined __osf__ /* IRIX, OSF/1 */ - - size_t pagesize; - char fnamebuf[6+10+1]; - char *fname; - int fd; - int nmaps; - size_t memneed; -# if HAVE_MAP_ANONYMOUS -# define zero_fd -1 -# define map_flags MAP_ANONYMOUS -# else - int zero_fd; -# define map_flags 0 -# endif - void *auxmap; - unsigned long auxmap_start; - unsigned long auxmap_end; - prmap_t* maps; - prmap_t* mp; - unsigned long total; - - pagesize = getpagesize (); - - /* Construct fname = sprintf (fnamebuf+i, "/proc/%u", getpid ()). */ - fname = fnamebuf + sizeof (fnamebuf) - 1; - *fname = '\0'; - { - unsigned int value = getpid (); - do - *--fname = (value % 10) + '0'; - while ((value = value / 10) > 0); - } - fname -= 6; - memcpy (fname, "/proc/", 6); - - fd = open (fname, O_RDONLY); - if (fd < 0) - return 0; - - if (ioctl (fd, PIOCNMAP, &nmaps) < 0) - goto fail2; - - memneed = (nmaps + 10) * sizeof (prmap_t); - /* Allocate memneed bytes of memory. - We cannot use alloca here, because not much stack space is guaranteed. - We also cannot use malloc here, because a malloc() call may call mmap() - and thus pre-allocate available memory. - So use mmap(), and ignore the resulting VMA. */ - memneed = ((memneed - 1) / pagesize + 1) * pagesize; -# if !HAVE_MAP_ANONYMOUS - zero_fd = open ("/dev/zero", O_RDONLY, 0644); - if (zero_fd < 0) - goto fail2; -# endif - auxmap = (void *) mmap ((void *) 0, memneed, PROT_READ | PROT_WRITE, - map_flags | MAP_PRIVATE, zero_fd, 0); -# if !HAVE_MAP_ANONYMOUS - close (zero_fd); -# endif - if (auxmap == (void *) -1) - goto fail2; - auxmap_start = (unsigned long) auxmap; - auxmap_end = auxmap_start + memneed; - maps = (prmap_t *) auxmap; + uintptr_t total = 0; - if (ioctl (fd, PIOCMAP, maps) < 0) - goto fail1; + vma_iterate (vma_iterate_callback, &total); - total = 0; - for (mp = maps;;) - { - unsigned long start, end; - - start = (unsigned long) mp->pr_vaddr; - end = start + mp->pr_size; - if (start == 0 && end == 0) - break; - mp++; - if (start <= auxmap_start && auxmap_end - 1 <= end - 1) - /* Consider [start,end-1] \ [auxmap_start,auxmap_end-1] - = [start,auxmap_start-1] u [auxmap_end,end-1]. */ - total += (end - start) - memneed; - else - total += end - start; - } - munmap (auxmap, memneed); - close (fd); - return total; - - fail1: - munmap (auxmap, memneed); - fail2: - close (fd); - return 0; - -#elif defined __APPLE__ && defined __MACH__ /* MacOS X */ - - task_t task = mach_task_self (); - vm_address_t address; - vm_size_t size; - vm_address_t total = 0; - - for (address = VM_MIN_ADDRESS;; address += size) - { - int more; - mach_port_t object_name; - /* In MacOS X 10.5, the types vm_address_t, vm_offset_t, vm_size_t have - 32 bits in 32-bit processes and 64 bits in 64-bit processes. Whereas - mach_vm_address_t and mach_vm_size_t are always 64 bits large. - MacOS X 10.5 has three vm_region like methods: - - vm_region. It has arguments that depend on whether the current - process is 32-bit or 64-bit. When linking dynamically, this - function exists only in 32-bit processes. Therefore we use it only - in 32-bit processes. - - vm_region_64. It has arguments that depend on whether the current - process is 32-bit or 64-bit. It interprets a flavor - VM_REGION_BASIC_INFO as VM_REGION_BASIC_INFO_64, which is - dangerous since 'struct vm_region_basic_info_64' is larger than - 'struct vm_region_basic_info'; therefore let's write - VM_REGION_BASIC_INFO_64 explicitly. - - mach_vm_region. It has arguments that are 64-bit always. This - function is useful when you want to access the VM of a process - other than the current process. - In 64-bit processes, we could use vm_region_64 or mach_vm_region. - I choose vm_region_64 because it uses the same types as vm_region, - resulting in less conditional code. */ -# if defined __ppc64__ || defined __x86_64__ - struct vm_region_basic_info_64 info; - mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_64; - - more = (vm_region_64 (task, &address, &size, VM_REGION_BASIC_INFO_64, - (vm_region_info_t)&info, &info_count, &object_name) - == KERN_SUCCESS); -# else - struct vm_region_basic_info info; - mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT; - - more = (vm_region (task, &address, &size, VM_REGION_BASIC_INFO, - (vm_region_info_t)&info, &info_count, &object_name) - == KERN_SUCCESS); -# endif - if (object_name != MACH_PORT_NULL) - mach_port_deallocate (mach_task_self (), object_name); - if (!more) - break; - total += size; - } - return total; - -#elif (defined _WIN32 || defined __WIN32__) || defined __CYGWIN__ - /* Windows platform. Use the native Windows API. */ - - MEMORY_BASIC_INFORMATION info; - unsigned long address = 0; - unsigned long total = 0; - - while (VirtualQuery ((void*)address, &info, sizeof(info)) == sizeof(info)) - { - if (info.State != MEM_FREE) - total += info.RegionSize; - address = (unsigned long)info.BaseAddress + info.RegionSize; - } - return total; - -#elif defined __BEOS__ - /* Use the BeOS specific API. */ - - area_info info; - int32 cookie; - unsigned long total = 0; - - cookie = 0; - while (get_next_area_info (0, &cookie, &info) == B_OK) - { - unsigned long start, end; - - start = (unsigned long) info.address; - end = start + info.size; - - total += end - start; - } return total; +} #else +static inline uintptr_t +get_rusage_as_via_iterator (void) +{ return 0; +} #endif -} uintptr_t @@ -705,3 +372,31 @@ get_rusage_as (void) return get_rusage_as_via_iterator (); #endif } + + +#ifdef TEST + +#include + +int +main () +{ + printf ("Initially: 0x%08lX 0x%08lX 0x%08lX\n", + get_rusage_as_via_setrlimit (), get_rusage_as_via_iterator (), + get_rusage_as ()); + malloc (0x88); + printf ("After small malloc: 0x%08lX 0x%08lX 0x%08lX\n", + get_rusage_as_via_setrlimit (), get_rusage_as_via_iterator (), + get_rusage_as ()); + malloc (0x8812); + printf ("After medium malloc: 0x%08lX 0x%08lX 0x%08lX\n", + get_rusage_as_via_setrlimit (), get_rusage_as_via_iterator (), + get_rusage_as ()); + malloc (0x281237); + printf ("After large malloc: 0x%08lX 0x%08lX 0x%08lX\n", + get_rusage_as_via_setrlimit (), get_rusage_as_via_iterator (), + get_rusage_as ()); + return 0; +} + +#endif /* TEST */