This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: [PATCH] malloca v2
On Sun, Jan 13, 2013 at 12:34:23PM -0800, Paul Eggert wrote:
> Some comments:
>
Thanks, they were helpful.
I decided to write portable implementation for now and add platform
specific optimizations later.
I wanted to be also eventualy used outside libc, one of possible
applications.
Now it only requires a cleanup attribute which most compilers supported
for ages.
Roland, what is your opinion? If this would be accepted as new interface
I could replace libc_use_alloca/alloca_account logic by malloca which would
simplify implementation and had faster allocation and free paths.
/* Safe automatic memory allocation.
Copyright (C) 2012-2013 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, see <http://www.gnu.org/licenses/>. */
#ifndef _MALLOCA_H
#define _MALLOCA_H
#include <alloca.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
/* malloca(N) is a safe variant of alloca(N). Malloca allocates N bytes of
memory from stack until limit specified below in MALLOCA_INIT_CUTOFF
is reached. Then it returns memory allocated on heap.
When no memory is available malloca returns NULL.
At start of function you have to write MALLOCA_INIT_CUTOFF(S) to specify
that all malloca calls use together at most S bytes of stack memory.
You can instead write MALLOCA_INIT which supplies a reasonable default.
Memory is freed automatically when function returns.
This header can be used with c compilers that supports cleanup attribute. */
#ifndef __MAX_ALLOCA_CUTOFF
#define __MAX_ALLOCA_CUTOFF (1<<16)
#endif
#ifdef MALLOC_ALIGNMENT
#define _MALLOC_ALIGNMENT MALLOC_ALIGNMENT
#else
#define _MALLOC_ALIGNMENT 16
#endif
#define MALLOCA_INIT MALLOCA_INIT_CUTOFF(__MAX_ALLOCA_CUTOFF)
#define MALLOCA_INIT_CUTOFF(__siz) \
void *__malloca_gc __attribute__ ((__cleanup__ (__ifreeall))) = NULL;\
size_t __frame_estimate = (__siz);
/* These functions are used to save space factoring out paths that rarely happen. */
#ifdef SHARED_MALLOCA
void __freeall (void *__malloca_gc);
void *__malloca_alloc (void *__malloca_gc,size_t __n);
#else
static void *
__malloca_alloc (void *__malloca_gc,size_t __n)
{
size_t __al = __n + _MALLOC_ALIGNMENT;
void *__r = malloc (__al);
void **__pr = __r;
if (!__r || __al < _MALLOC_ALIGNMENT)
return NULL;
*__pr = __malloca_gc;
__malloca_gc = __pr;
return __r + _MALLOC_ALIGNMENT;
}
/* Noinline because gcc inlines this to __ifreeall which defeats the point. */
__attribute ((noinline)) static void
__freeall (void *__malloca_gc)
{
while (__malloca_gc)
{
void **__tmp = __malloca_gc;
__malloca_gc = *__tmp;
free (__tmp);
}
}
#endif
static inline void
__ifreeall (void *__malloca_gc)
{
if (__malloca_gc)
__freeall (__malloca_gc);
}
/* Possibly faster test is __frame_estimate - __n <= __frame_estimate
which uses unsigned wraparound. */
#define malloca(n) ({ \
size_t __n = (n); \
void *__r; \
if (__frame_estimate >= (__n)) \
{ \
__frame_estimate -= (__n); \
__r = alloca (__n); \
} \
else \
{ \
__r = __malloca_alloc (__malloca_gc, __n); \
} \
__r; \
})
#ifdef __cplusplus
}
#endif
#endif /* _MALLOCA_H */