mirror of
https://git.savannah.gnu.org/git/gnulib.git
synced 2025-08-08 17:22:05 +03:00
alignalloc, xalignalloc: new modules
* lib/alignalloc.c, lib/alignalloc.h, lib/xalignalloc.c: * m4/alignalloc.m4, modules/alignalloc, modules/alignalloc-tests: * modules/xalignalloc, tests/test-alignalloc.c: New files.
This commit is contained in:
@@ -1,3 +1,11 @@
|
|||||||
|
2022-01-23 Paul Eggert <eggert@cs.ucla.edu>
|
||||||
|
|
||||||
|
alignalloc, xalignalloc: new modules
|
||||||
|
* lib/alignalloc.c, lib/alignalloc.h, lib/xalignalloc.c:
|
||||||
|
* m4/alignalloc.m4, modules/alignalloc, modules/alignalloc-tests:
|
||||||
|
* modules/xalignalloc, tests/test-alignalloc.c:
|
||||||
|
New files.
|
||||||
|
|
||||||
2022-01-17 Paul Eggert <eggert@cs.ucla.edu>
|
2022-01-17 Paul Eggert <eggert@cs.ucla.edu>
|
||||||
|
|
||||||
extern-inline: improve macOS port
|
extern-inline: improve macOS port
|
||||||
|
121
lib/alignalloc.c
Normal file
121
lib/alignalloc.c
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
/* aligned memory allocation
|
||||||
|
|
||||||
|
Copyright 2022 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 3 of the License, 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, see <https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
/* Written by Paul Eggert. */
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#define ALIGNALLOC_INLINE _GL_EXTERN_INLINE
|
||||||
|
#include "alignalloc.h"
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdalign.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "intprops.h"
|
||||||
|
#include "verify.h"
|
||||||
|
|
||||||
|
#if !ALIGNALLOC_VIA_ALIGNED_ALLOC
|
||||||
|
# if HAVE_POSIX_MEMALIGN
|
||||||
|
|
||||||
|
/* posix_memalign requires the alignment to be a power-of-two multiple of
|
||||||
|
sizeof (void *), whereas alignalloc requires it to be a power of two.
|
||||||
|
To make it OK for the latter to call the former, check that
|
||||||
|
sizeof (void *) is a power of two, which is true on all known platforms.
|
||||||
|
This check is here rather than in alignalloc.h to save the compiler
|
||||||
|
the trouble of checking it each time alignalloc.h is included. */
|
||||||
|
verify (! (sizeof (void *) & (sizeof (void *) - 1)));
|
||||||
|
|
||||||
|
# else /* !HAVE_POSIX_MEMALIGN */
|
||||||
|
|
||||||
|
/* Return P aligned down to ALIGNMENT, which should be a power of two. */
|
||||||
|
|
||||||
|
static void *
|
||||||
|
align_down (void *p, idx_t alignment)
|
||||||
|
{
|
||||||
|
char *c = p;
|
||||||
|
return c - ((uintptr_t) p & (alignment - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If alignalloc returned R and the base of the originally-allocated
|
||||||
|
storage is less than R - UCHAR_MAX, return the address of a pointer
|
||||||
|
holding the base of the originally-allocated storage. */
|
||||||
|
|
||||||
|
static void **
|
||||||
|
address_of_pointer_to_malloced (unsigned char *r)
|
||||||
|
{
|
||||||
|
/* The pointer P is located at the highest address A such that A is
|
||||||
|
aligned for pointers, and A + sizeof P < R so that there is room
|
||||||
|
for a 0 byte at R - 1. This approach assumes UCHAR_MAX is large
|
||||||
|
enough so that there is room for P; although true on all
|
||||||
|
plausible platforms, check the assumption to be safe. */
|
||||||
|
verify (sizeof (void *) + alignof (void *) - 1 <= UCHAR_MAX);
|
||||||
|
|
||||||
|
return align_down (r - 1 - sizeof (void *), alignof (void *));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return an ALIGNMENT-aligned pointer to new storage of size SIZE,
|
||||||
|
or a null pointer (setting errno) if memory is exhausted.
|
||||||
|
ALIGNMENT must be a power of two.
|
||||||
|
If SIZE is zero, on success return a unique pointer each time.
|
||||||
|
To free storage later, call alignfree. */
|
||||||
|
|
||||||
|
void *
|
||||||
|
alignalloc (idx_t alignment, idx_t size)
|
||||||
|
{
|
||||||
|
/* malloc (ALIGNMENT + SIZE); if it succeeds, there must be at least
|
||||||
|
one byte available before the returned pointer. It's OK if
|
||||||
|
ALIGNMENT + SIZE fits in size_t but not idx_t. */
|
||||||
|
|
||||||
|
size_t malloc_size;
|
||||||
|
unsigned char *q;
|
||||||
|
if (INT_ADD_WRAPV (size, alignment, &malloc_size)
|
||||||
|
|| ! (q = malloc (malloc_size)))
|
||||||
|
{
|
||||||
|
errno = ENOMEM;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *r = align_down (q + alignment, alignment);
|
||||||
|
idx_t offset = r - q;
|
||||||
|
|
||||||
|
if (offset <= UCHAR_MAX)
|
||||||
|
r[-1] = offset;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r[-1] = 0;
|
||||||
|
*address_of_pointer_to_malloced (r) = q;
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free storage allocated via alignalloc. Do nothing if PTR is null. */
|
||||||
|
|
||||||
|
void
|
||||||
|
alignfree (void *ptr)
|
||||||
|
{
|
||||||
|
if (ptr)
|
||||||
|
{
|
||||||
|
unsigned char *r = ptr;
|
||||||
|
unsigned char offset = r[-1];
|
||||||
|
void *q = offset ? r - offset : *address_of_pointer_to_malloced (r);
|
||||||
|
free (q);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# endif /* ! HAVE_POSIX_MEMALIGN */
|
||||||
|
#endif /* ! ALIGNALLOC_VIA_ALIGNED_ALLOC */
|
98
lib/alignalloc.h
Normal file
98
lib/alignalloc.h
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
/* aligned memory allocation
|
||||||
|
|
||||||
|
Copyright 2022 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 3 of the License, 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, see <https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
/* Written by Paul Eggert. */
|
||||||
|
|
||||||
|
#ifndef ALIGNALLOC_H_
|
||||||
|
#define ALIGNALLOC_H_
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "idx.h"
|
||||||
|
|
||||||
|
#ifndef _GL_INLINE_HEADER_BEGIN
|
||||||
|
#error "Please include config.h first."
|
||||||
|
#endif
|
||||||
|
_GL_INLINE_HEADER_BEGIN
|
||||||
|
#ifndef ALIGNALLOC_INLINE
|
||||||
|
# define ALIGNALLOC_INLINE _GL_INLINE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Whether aligned_alloc supports any power-of-two alignment,
|
||||||
|
returns a nonnull pointer for size-zero allocations,
|
||||||
|
and sets errno on failure. */
|
||||||
|
#if 2 < __GLIBC__ + (15 <= __GLIBC_MINOR__)
|
||||||
|
# define ALIGNALLOC_VIA_ALIGNED_ALLOC 1
|
||||||
|
#else
|
||||||
|
# define ALIGNALLOC_VIA_ALIGNED_ALLOC 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ALIGNALLOC_VIA_ALIGNED_ALLOC || HAVE_POSIX_MEMALIGN
|
||||||
|
|
||||||
|
/* Free storage allocated via alignalloc. Do nothing if PTR is null. */
|
||||||
|
|
||||||
|
ALIGNALLOC_INLINE void
|
||||||
|
alignfree (void *ptr)
|
||||||
|
{
|
||||||
|
free (ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return an ALIGNMENT-aligned pointer to new storage of size SIZE,
|
||||||
|
or a null pointer (setting errno) if memory is exhausted.
|
||||||
|
ALIGNMENT must be a power of two.
|
||||||
|
If SIZE is zero, on success return a unique pointer each time.
|
||||||
|
To free storage later, call alignfree. */
|
||||||
|
|
||||||
|
ALIGNALLOC_INLINE
|
||||||
|
_GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_ALLOC_SIZE ((2))
|
||||||
|
/* _GL_ATTRIBUTE_DEALLOC (alignfree, 1) */
|
||||||
|
void *
|
||||||
|
alignalloc (idx_t alignment, idx_t size)
|
||||||
|
{
|
||||||
|
if ((size_t) -1 < alignment)
|
||||||
|
alignment = (size_t) -1;
|
||||||
|
if ((size_t) -1 < size)
|
||||||
|
size = (size_t) -1;
|
||||||
|
|
||||||
|
# if ALIGNALLOC_VIA_ALIGNED_ALLOC
|
||||||
|
return aligned_alloc (alignment, size);
|
||||||
|
# else
|
||||||
|
void *ptr = NULL;
|
||||||
|
if (alignment < sizeof (void *))
|
||||||
|
alignment = sizeof (void *);
|
||||||
|
errno = posix_memalign (&ptr, alignment, size | !size);
|
||||||
|
return ptr;
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* ! (ALIGNALLOC_VIA_ALIGNED_ALLOC || HAVE_POSIX_MEMALIGN) */
|
||||||
|
|
||||||
|
void alignfree (void *);
|
||||||
|
void *alignalloc (idx_t, idx_t)
|
||||||
|
_GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_ALLOC_SIZE ((2))
|
||||||
|
_GL_ATTRIBUTE_DEALLOC (alignfree, 1);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Like alignalloc, but die instead of returning a null pointer. */
|
||||||
|
void *xalignalloc (idx_t, idx_t)
|
||||||
|
_GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_ALLOC_SIZE ((2))
|
||||||
|
_GL_ATTRIBUTE_RETURNS_NONNULL /* _GL_ATTRIBUTE_DEALLOC (alignfree, 1) */;
|
||||||
|
|
||||||
|
_GL_INLINE_HEADER_END
|
||||||
|
|
||||||
|
#endif /* !ALIGNALLOC_H_ */
|
33
lib/xalignalloc.c
Normal file
33
lib/xalignalloc.c
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/* checked aligned memory allocation
|
||||||
|
|
||||||
|
Copyright 2022 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 3 of the License, 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, see <https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
/* Written by Paul Eggert. */
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include "alignalloc.h"
|
||||||
|
|
||||||
|
#include "xalloc.h"
|
||||||
|
|
||||||
|
void *
|
||||||
|
xalignalloc (idx_t alignment, idx_t size)
|
||||||
|
{
|
||||||
|
void *p = alignalloc (alignment, size);
|
||||||
|
if (!p)
|
||||||
|
xalloc_die ();
|
||||||
|
return p;
|
||||||
|
}
|
10
m4/alignalloc.m4
Normal file
10
m4/alignalloc.m4
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
dnl Copyright 2022 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_ALIGNALLOC],
|
||||||
|
[
|
||||||
|
AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
|
||||||
|
AC_CHECK_FUNCS_ONCE([posix_memalign])
|
||||||
|
])
|
32
modules/alignalloc
Normal file
32
modules/alignalloc
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
Description:
|
||||||
|
Aligned memory allocation
|
||||||
|
|
||||||
|
Files:
|
||||||
|
lib/alignalloc.h
|
||||||
|
lib/alignalloc.c
|
||||||
|
m4/alignalloc.m4
|
||||||
|
|
||||||
|
Depends-on:
|
||||||
|
extensions
|
||||||
|
extern-inline
|
||||||
|
idx
|
||||||
|
intprops
|
||||||
|
posix_memalign
|
||||||
|
stdalign
|
||||||
|
stdint
|
||||||
|
verify
|
||||||
|
|
||||||
|
configure.ac:
|
||||||
|
gl_ALIGNALLOC
|
||||||
|
|
||||||
|
Makefile.am:
|
||||||
|
lib_SOURCES += alignalloc.c
|
||||||
|
|
||||||
|
Include:
|
||||||
|
"alignalloc.h"
|
||||||
|
|
||||||
|
License:
|
||||||
|
LGPLv2+
|
||||||
|
|
||||||
|
Maintainer:
|
||||||
|
bug-gnulib@gnu.org
|
14
modules/alignalloc-tests
Normal file
14
modules/alignalloc-tests
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
Files:
|
||||||
|
tests/test-alignalloc.c
|
||||||
|
tests/signature.h
|
||||||
|
tests/macros.h
|
||||||
|
|
||||||
|
Depends-on:
|
||||||
|
intprops
|
||||||
|
stdint
|
||||||
|
|
||||||
|
configure.ac:
|
||||||
|
|
||||||
|
Makefile.am:
|
||||||
|
TESTS += test-alignalloc
|
||||||
|
check_PROGRAMS += test-alignalloc
|
23
modules/xalignalloc
Normal file
23
modules/xalignalloc
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
Description:
|
||||||
|
Checked aligned memory allocation
|
||||||
|
|
||||||
|
Files:
|
||||||
|
lib/xalignalloc.c
|
||||||
|
|
||||||
|
Depends-on:
|
||||||
|
alignalloc
|
||||||
|
xalloc-die
|
||||||
|
|
||||||
|
configure.ac:
|
||||||
|
|
||||||
|
Makefile.am:
|
||||||
|
lib_SOURCES += xalignalloc.c
|
||||||
|
|
||||||
|
Include:
|
||||||
|
"alignalloc.h"
|
||||||
|
|
||||||
|
License:
|
||||||
|
GPL
|
||||||
|
|
||||||
|
Maintainer:
|
||||||
|
bug-gnulib@gnu.org
|
57
tests/test-alignalloc.c
Normal file
57
tests/test-alignalloc.c
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/* Test alignalloc and alignfree.
|
||||||
|
|
||||||
|
Copyright 2022 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 3 of the License, 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, see <https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <alignalloc.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "intprops.h"
|
||||||
|
|
||||||
|
#include "signature.h"
|
||||||
|
SIGNATURE_CHECK (alignalloc, void *, (idx_t, idx_t));
|
||||||
|
SIGNATURE_CHECK (alignfree, void, (void *));
|
||||||
|
|
||||||
|
#include "macros.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
main ()
|
||||||
|
{
|
||||||
|
/* Check that alignalloc returns properly aligned storage,
|
||||||
|
when it succeeds. */
|
||||||
|
for (idx_t alignment = 1; ; )
|
||||||
|
{
|
||||||
|
for (idx_t size = 0; size <= 1024; size = size ? 2 * size : 1)
|
||||||
|
{
|
||||||
|
void *p = alignalloc (alignment, size);
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
memset (p, 0, size);
|
||||||
|
ASSERT ((uintptr_t) p % alignment == 0);
|
||||||
|
}
|
||||||
|
alignfree (p);
|
||||||
|
}
|
||||||
|
if (INT_MULTIPLY_WRAPV (alignment, 2, &alignment))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that alignfree is a no-op on null pointers. */
|
||||||
|
alignfree (NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Reference in New Issue
Block a user