bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [bug-gnulib] valloc()?


From: Bruno Haible
Subject: Re: [bug-gnulib] valloc()?
Date: Thu, 3 Mar 2005 15:03:57 +0100
User-agent: KMail/1.5

Derek Price wrote:
> Okay, I've implemented this as you suggested, Bruno.  Installed in CVS,
> it passes tests in all four modes (MMAP, MMAP/NO-MAP_ANON,
> POSIX_MEMALIGN, OTHER).  I've attached the patch, but I still have a few
> questions.

Thanks. I've installed this into gnulib, with the following minor
modifications:
  - Indentation according to GNU standards.
  - pagealign_alloc.h:
    - Add comments.
    - Include <stddef.h>, for size_t.
  - pagealign_alloc.c:
    - Remove the mention of "public domain" since it contradicts the GPL.
    - Include pagealign_alloc.h first, to verify that it is self-consistent.
    - Use the 'exit' module for EXIT_FAILURE.
    - Don't use EINVAL in an error message that is already verbose enough.
    - Drop the trailing dot in error messages that use an errno, since
      they are displayed with a colon and the errno explanation following it.
    - Fixed portability problem of void* computations like 'orig + pagesize - 
1'.
    - Use a typedef to avoid many #ifs.
    - Rename input parameter 'out' to 'aligned_ptr'. (An input parameter called
      'out' is somewhat paradox.)
    - Don't use 'new' as variable name, since we might want to compile the
      code with a C++ compiler some day.
    - Removed unnecessary fields from 'memtable' and renamed it to
      'memnode_table'.
    - In get_memnode, use abort() instead of exit() to signal a bug in the
      calling code.
    - Make pagealign_alloc work also if a 'void *' does not fit in a 'long'.
    - Use "#if HAVE_POSIX_MEMALIGN" consistently, not a mix of #if here and
      #ifdef there.
  - mmap.m4: Renamed to mmap-anon.m4 since it cares only about anonymous
    mappings, not about file or shared mappings. ('grep' has a different
    test for mmap, and 'clisp' yet another one.)
    Write config.h, not <config.h>.

Do you still see some nits that could be improved?

Bruno


=========================== modules/pagealign_alloc ========================
Description:
Memory allocation aligned on page boundaries.

Files:
lib/pagealign_alloc.h
lib/pagealign_alloc.c
m4/mmap-anon.m4
m4/pagealign_alloc.m4

Depends-on:
error
exit
getpagesize
xalloc

configure.ac:
gl_PAGEALIGN_ALLOC

Makefile.am:

Include:
#include "pagealign_alloc.h"

License:
GPL

Maintainer:
address@hidden
============================= lib/pagealign_alloc.h ========================
/* Memory allocation aligned to system page boundaries.

   Copyright (C) 2005 Free Software Foundation, Inc.

   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published
   by the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public
   License along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
   USA.  */

#ifndef _PAGEALIGN_ALLOC_H
# define _PAGEALIGN_ALLOC_H

# include <stddef.h>

/* Allocate a block of memory of SIZE bytes, aligned on a system page
   boundary.
   If SIZE is not a multiple of the system page size, it will be rounded up
   to the next multiple.
   Return a pointer to the start of the memory block, or NULL if the allocation
   failed.  */
extern void *pagealign_alloc (size_t size);

/* Free a memory block.
   PTR must be a pointer returned by pagealign_alloc.  */
extern void pagealign_free (void *ptr);

#endif /* _PAGEALIGN_ALLOC_H */
============================= lib/pagealign_alloc.c ========================
/* Memory allocation aligned to system page boundaries.

   Copyright (C) 2005 Free Software Foundation, Inc.

   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published
   by the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public
   License along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
   USA.  */

/* Written by Derek R. Price <address@hidden>.  */

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include "pagealign_alloc.h"

#include <errno.h>
#include <stdlib.h>

#if HAVE_FCNTL_H
# include <fcntl.h>
#endif

#if HAVE_UNISTD_H
# include <unistd.h>
#endif

#if HAVE_MMAP
# include <sys/mman.h>
#endif

#include "error.h"
#include "exit.h"
#include "getpagesize.h"
#include "xalloc.h"


#if HAVE_MMAP || ! HAVE_POSIX_MEMALIGN

# if HAVE_MMAP
/* For each memory region, we store its size.  */
typedef size_t info_t;
# else
/* For each memory region, we store the original pointer returned by
   malloc().  */
typedef void * info_t;
# endif

/* A simple linked list of allocated memory regions.  It is probably not the
   most efficient way to store these, but anyway...  */
typedef struct memnode_s memnode_t;
struct memnode_s
{
  void *aligned_ptr;
  info_t info;
  memnode_t *next;
};

/* The list of currently allocated memory regions.  */
static memnode_t *memnode_table = NULL;


static void
new_memnode (void *aligned_ptr, info_t info)
{
  memnode_t *new_node = (memnode_t *) xmalloc (sizeof (memnode_t));
  new_node->aligned_ptr = aligned_ptr;
  new_node->info = info;
  new_node->next = memnode_table;
  memnode_table = new_node;
}


/* Dispose of the memnode containing a map for the ALIGNED_PTR in question
   and return the content of the node's INFO field.  */
static info_t
get_memnode (void *aligned_ptr)
{
  info_t ret;
  memnode_t *c;
  memnode_t **p_next = &memnode_table;

  for (c = *p_next; c != NULL; p_next = &c->next, c = c->next)
    if (c->aligned_ptr == aligned_ptr)
      break;

  if (!c)
    /* An attempt to free untracked memory.  A wrong pointer was passed
       to pagealign_free().  */
    abort ();

  /* Remove this entry from the list, save the return value, and free it.  */
  *p_next = c->next;
  ret = c->info;
  free (c);

  return ret;
}

#endif /* HAVE_MMAP || !HAVE_POSIX_MEMALIGN */


void *
pagealign_alloc (size_t size)
{
  void *ret;
#if HAVE_MMAP
  int flags;
  static int fd = -1;  /* Only open /dev/zero once in order to avoid limiting
                          the amount of memory we may allocate based on the
                          number of open file descriptors.  */
# ifdef HAVE_MAP_ANONYMOUS
  flags = MAP_ANONYMOUS | MAP_PRIVATE;
  fd = -1;
# else /* !HAVE_MAP_ANONYMOUS */
  flags = MAP_FILE | MAP_PRIVATE;
  if (fd == -1)
    {
      fd = open ("/dev/zero", O_RDONLY, 0666);
      if (fd < 0)
        error (EXIT_FAILURE, errno, "Failed to open /dev/zero for read");
    }
# endif /* HAVE_MAP_ANONYMOUS */
  ret = mmap (NULL, size, PROT_READ | PROT_WRITE, flags, fd, 0);
  if (!ret)
    error (EXIT_FAILURE, errno, "mmap to /dev/zero failed");
  new_memnode (ret, size);
#elif HAVE_POSIX_MEMALIGN
  int status = posix_memalign (&ret, getpagesize (), size);
  if (status)
    error (EXIT_FAILURE, status, "posix_memalign failed");
#else /* !HAVE_MMAP && !HAVE_POSIX_MEMALIGN */
  size_t pagesize = getpagesize ();
  void *unaligned_ptr = xmalloc (size + pagesize - 1);
  ret = (char *) unaligned_ptr
        + ((- (unsigned long) unaligned_ptr) & (pagesize - 1));
  new_memnode (ret, unaligned_ptr);
#endif /* HAVE_MMAP && HAVE_POSIX_MEMALIGN */
  return ret;
}


void
pagealign_free (void *aligned_ptr)
{
#if HAVE_MMAP
  munmap (aligned_ptr, get_memnode (aligned_ptr));
#elif HAVE_POSIX_MEMALIGN
  free (aligned_ptr);
#else
  free (get_memnode (aligned_ptr));
#endif
}
=============================== m4/mmap_anon.m4 ============================
# mmap-anon.m4 serial 1
dnl Copyright (C) 2005 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.

AC_DEFUN([gl_FUNC_MMAP],
[
  dnl Work around a bug of AC_EGREP_CPP in autoconf-2.57.
  AC_REQUIRE([AC_PROG_CPP])
  AC_REQUIRE([AC_PROG_EGREP])

  dnl Persuade glibc <sys/mman.h> to define MAP_ANONYMOUS.
  AC_REQUIRE([AC_GNU_SOURCE])

  # Check for mmap()
  AC_FUNC_MMAP

  # Try to allow MAP_ANONYMOUS.
  gl_have_mmap_anonymous=no
  if test $ac_cv_func_mmap_fixed_mapped = yes; then
    AC_MSG_CHECKING([for MAP_ANONYMOUS])
    AC_EGREP_CPP([I cant identify this map.], [
#include <sys/mman.h>
#ifdef MAP_ANONYMOUS
    I cant identify this map.
#endif
],
      [gl_have_mmap_anonymous=yes])
    if test $gl_have_mmap_anonymous = no; then
      AC_EGREP_HEADER([MAP_ANON], [
#include <sys/mman.h>
#ifdef MAP_ANON
    I cant identify this map.
#endif
],
        [AC_DEFINE(MAP_ANONYMOUS, MAP_ANON,
          [Define to a substitute value for mmap()'s MAP_ANONYMOUS flag.])
         gl_have_mmap_anonymous=yes])
    fi
    AC_MSG_RESULT($gl_have_mmap_anonymous)
    if test $gl_have_mmap_anonymous = yes; then
      AC_DEFINE(HAVE_MAP_ANONYMOUS, 1,
        [Define to 1 if mmap()'s MAP_ANONYMOUS flag is available after including
         config.h and <sys/mman.h>.])
    fi

    AH_VERBATIM([MAP_FILE],
[/* Define MAP_FILE when it isn't otherwise.  */
#ifndef MAP_FILE
# define MAP_FILE 0
#endif])
  fi
])
============================ m4/pagealign_alloc.m4 =========================
# pagealign_alloc.m4 serial 1
dnl Copyright (C) 2005 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.

AC_DEFUN([gl_PAGEALIGN_ALLOC],
[
  dnl Persuade glibc <sys/mman.h> to define MAP_ANONYMOUS.
  AC_REQUIRE([AC_GNU_SOURCE])

  AC_LIBSOURCE([pagealign_alloc.h])
  AC_LIBOBJ([pagealign_alloc])
  gl_PREREQ_PAGEALIGN_ALLOC
])

# Prerequisites of lib/pagealign_alloc.c.
AC_DEFUN([gl_PREREQ_PAGEALIGN_ALLOC],
[
  AC_REQUIRE([gl_FUNC_MMAP])
  AC_REQUIRE([gl_GETPAGESIZE])
  AC_CHECK_FUNCS_ONCE([posix_memalign])
  AC_CHECK_HEADERS_ONCE([fcntl.h unistd.h])
])
============================================================================





reply via email to

[Prev in Thread] Current Thread [Next in Thread]