This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]