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>
|
||||
|
||||
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