This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH] malloca v2
- From: OndÅej BÃlka <neleai at seznam dot cz>
- To: libc-alpha at sourceware dot org
- Date: Sat, 12 Jan 2013 18:22:53 +0100
- Subject: [PATCH] malloca v2
Hello,
I realized that I can make simpler and faster malloca than my previous
attempt.
You need to write MALLOCA_INIT(); at function header.
Allocation is done my malloca(n) which allocates at most __MAX_ALLOCA_CUTOFF
bytes per stack frame.
For deallocation it now suffices to call freeall() which frees all
elements mallocated in frame.
I made per frame choice as alloca_acccont estimates frame size and it
is better to just use real size.
Now I do freeing by putting malloc results into linked list and freeing
them at once. Most of time list is empty so it is only one null check.
I wrote this as standalone header. As part of libc I would move
functions to separate file.
diff --git a/malloc/malloca.h b/malloc/malloca.h
new file mode 100644
index 0000000..c36cb4e
--- /dev/null
+++ b/malloc/malloca.h
@@ -0,0 +1,117 @@
+/* Safe automatic memory allocation.
+ Copyright (C) 2012 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). It allocates N bytes of
+ memory allocated on the stack until stack frame has __MAX_ALLOCA_CUTOFF
+ bytes and heap otherwise. When memory cannot be allocated from heap
+ malloca aborts.
+ You must write MALLOCA_INIT() at start of each function that uses malloca.
+ To free memory you must call freeall() before function returns. */
+
+
+/* TODO: switch to later case when -fomit-frame-pointer.*/
+#if 1
+ #define MALLOCA_INIT() void *__malloca_gc=NULL;
+ #define __MALLOCA_EBP __builtin_frame_address(0)
+#else
+ #define MALLOCA_INIT() void *__malloca_gc=NULL; void *__malloca_ebp = &__malloca_ebp;
+ #define __MALLOCA_EBP __malloca_ebp
+#endif
+
+#ifdef _STACK_GROWS_DOWN
+ #define __MALLOCA_UB __MALLOCA_EBP
+ #define __MALLOCA_LB stackinfo_get_sp ()
+#endif
+#ifdef _STACK_GROWS_UP
+ #define __MALLOCA_UB stackinfo_get_sp ()
+ #define __MALLOCA_LB __MALLOCA_EBP
+#endif
+
+#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 __libc_use_alloca(x) ( __MALLOCA_UB - __MALLOCA_LB + (x) < __MAX_ALLOCA_CUTOFF )
+
+#ifdef SHARED_MALLOCA
+void __freeall(void *__malloca_gc);
+void* __malloca_alloc(void *__malloca_gc,size_t __n);
+#else
+static void __freeall(void *__malloca_gc)
+ {
+ while(__malloca_gc)
+ {
+ void * __tmp = __malloca_gc;
+ __malloca_gc = ((void **)__malloca_gc)[0];
+ free(__tmp);
+ }
+ }
+
+static void* __malloca_alloc(void *__malloca_gc,size_t __n)
+ {
+ void *__r = malloc (__n + _MALLOC_ALIGNMENT);
+ if (!__r || __n+_MALLOC_ALIGNMENT < _MALLOC_ALIGNMENT)
+ abort();
+ ((void **)__r)[0] = __malloca_gc;
+ __malloca_gc = __r;
+ return __r + _MALLOC_ALIGNMENT;
+ }
+#endif
+
+#define malloca(n) ({ \
+ size_t __n = (n); \
+ void * __r = NULL; \
+ if (__libc_use_alloca (__n)) \
+ { \
+ __r = alloca (__n); \
+ } \
+ else \
+ { \
+ __r = __malloca_alloc (__malloca_gc, __n); \
+ } \
+ __r; \
+})
+
+#define freeall() \
+do { \
+ if (__malloca_gc) \
+ __freeall(__malloca_gc); \
+} while (0)
+
+
+#undef alloca_account
+#define alloca_account(n, var) ({ \
+ void *__r = alloca(n); \
+ __r; \
+})
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MALLOCA_H */
diff --git a/argp/argp-help.c b/argp/argp-help.c
index 80c2b7d..1ec95c4 100644
--- a/argp/argp-help.c
+++ b/argp/argp-help.c
@@ -25,20 +25,7 @@
#include <config.h>
#endif
-/* AIX requires this to be the first thing in the file. */
-#ifndef __GNUC__
-# if HAVE_ALLOCA_H || defined _LIBC
-# include <alloca.h>
-# else
-# ifdef _AIX
-#pragma alloca
-# else
-# ifndef alloca /* predefined by HP cc +Olibcalls */
-char *alloca ();
-# endif
-# endif
-# endif
-#endif
+#include <malloc/malloca.h>
#include <stdbool.h>
#include <stddef.h>
@@ -1310,11 +1297,13 @@ usage_long_opt (const struct argp_option *opt,
static void
hol_usage (struct hol *hol, argp_fmtstream_t stream)
{
+ MALLOCA_INIT();
+ char *short_no_arg_opts = NULL;
if (hol->num_entries > 0)
{
unsigned nentries;
struct hol_entry *entry;
- char *short_no_arg_opts = alloca (strlen (hol->short_options) + 1);
+ short_no_arg_opts = malloca (strlen (hol->short_options) + 1);
char *snao_end = short_no_arg_opts;
/* First we put a list of short options without arguments. */
@@ -1343,6 +1332,7 @@ hol_usage (struct hol *hol, argp_fmtstream_t stream)
hol_entry_long_iterate (entry, usage_long_opt,
entry->argp->argp_domain, stream);
}
+ freeall ();
}
/* Make a HOL containing all levels of options in ARGP. CLUSTER is the
@@ -1547,6 +1537,8 @@ static void
_help (const struct argp *argp, const struct argp_state *state, FILE *stream,
unsigned flags, char *name)
{
+ MALLOCA_INIT();
+ char *pattern_levels = NULL;
int anything = 0; /* Whether we've output anything. */
struct hol *hol = 0;
argp_fmtstream_t fs;
@@ -1585,7 +1577,7 @@ _help (const struct argp *argp, const struct argp_state *state, FILE *stream,
{
int first_pattern = 1, more_patterns;
size_t num_pattern_levels = argp_args_levels (argp);
- char *pattern_levels = alloca (num_pattern_levels);
+ pattern_levels = malloca (num_pattern_levels);
memset (pattern_levels, 0, num_pattern_levels);
@@ -1680,6 +1672,7 @@ Try `%s --help' or `%s --usage' for more information.\n"),
if (hol)
hol_free (hol);
+ freeall ();
__argp_fmtstream_free (fs);
}
--
1.7.4.4