[PATCH] Slightly better way to __USE_MALLOC

Brad Spencer spencer@infointeractive.com
Thu Oct 17 07:43:00 GMT 2002


On Wed, Oct 16, 2002 at 10:37:37PM -0500, Benjamin Kosnik wrote:
> 
> So is this patch finished, and ready to review?

Yes.  Sorry about the delay, but other work has caught up to me.  I
don't know if I'll say it's finished because I'm not sure I can meet
everyone's wishes ;)

Completed:

Renamed __default_alloc_template to __pool_alloc_template.
Made the definitions of both allocation templates present in the
  library, and _GLIBCPP_USE_MALLOC just selects which is the default one
  used by std::allocator.
Added (naive?) link-time guards to prevent objects compiled with
  different _GLIBCPP_USE_MALLOC settings from linking.  Tips on how to
  do this with symbol versioning would be appreciated.

TODO:

Figure out what the comment in c++config.h should say.
Write the final configopts.html entry and FAQ entry.

  
I hate to submit this patch in this semi-finalized form (I don't like
to be sloppy), but it's probably better than letting it rot.  I
haven't had the opportunity to run the test suite on it yet either.
I will be able to work more on it now if there are suggestions.  

-- 
------------------------------------------------------------------
Brad Spencer - spencer@infointeractive.com - "It's quite nice..."
Systems Architect | InfoInterActive Corp. | A Canadian AOL Company
-------------- next part --------------
Index: acconfig.h
===================================================================
RCS file: /cvsroot/gcc/gcc/libstdc++-v3/acconfig.h,v
retrieving revision 1.25
diff -u -p -r1.25 acconfig.h
--- acconfig.h	14 Dec 2001 21:06:32 -0000	1.25
+++ acconfig.h	11 Oct 2002 00:59:36 -0000
@@ -37,6 +37,9 @@
 // Define to use concept checking code from the boost libraries.
 #undef _GLIBCPP_CONCEPT_CHECKS
 
+// Define to use the malloc-based allocator instead pool-based one
+#undef _GLIBCPP_USE_MALLOC
+
 // Define if you have the atan2f function.
 #undef _GLIBCPP_HAVE_ATAN2F 
 
Index: acinclude.m4
===================================================================
RCS file: /cvsroot/gcc/gcc/libstdc++-v3/acinclude.m4,v
retrieving revision 1.220
diff -u -p -r1.220 acinclude.m4
--- acinclude.m4	17 Sep 2002 05:50:31 -0000	1.220
+++ acinclude.m4	11 Oct 2002 00:59:36 -0000
@@ -2106,6 +2106,38 @@ fi
 
 
 dnl
+dnl Check for whether the _GLIBCPP_USE_MALLOC macro should be defined and thus
+dnl whether the library should be built with the malloc-based allocator
+dnl underneath the STL containers instead of the pool-based allocator.
+dnl
+dnl GLIBCPP_ENABLE_POOL_ALLOCATOR
+dnl --enable-pool-allocator enables the pool-based allocator.
+dnl --disable-pool-allocator turns it off off.
+dnl  +  Usage:  GLIBCPP_ENABLE_USE_MALLOC[(DEFAULT)]
+dnl       Where DEFAULT is either `yes' or `no'.  If ommitted, it
+dnl       defaults to `yes'.
+AC_DEFUN(GLIBCPP_ENABLE_POOL_ALLOCATOR, [dnl
+define([GLIBCPP_ENABLE_POOL_ALLOCATOR_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE(pool-allocator,
+changequote(<<, >>)dnl
+<<  --enable-pool-allocator use the fast pool-based allocator [default=>>GLIBCPP_ENABLE_POOL_ALLOCATOR_DEFAULT],
+changequote([, ])dnl
+[case "$enableval" in
+ yes) enable_pool_allocator=yes ;;
+ no)  enable_pool_allocator=no ;;
+ *)   AC_MSG_ERROR([Unknown argument to enable/disable pool allocator]) ;;
+ esac],
+enable_pool_allocator=GLIBCPP_ENABLE_POOL_ALLOCATOR_DEFAULT)dnl
+dnl Option parsed, now set things appropriately
+AC_MSG_CHECKING([whether to use pool allocator])
+if test x"$enable_pool_allocator" = xno; then
+  AC_DEFINE(_GLIBCPP_USE_MALLOC)
+fi
+AC_MSG_RESULT($enable_pool_allocator)
+])
+
+
+dnl
 dnl Add version tags to symbols in shared library (or not), additionally
 dnl marking other symbols as private/local (or not).
 dnl
Index: config.h.in
===================================================================
RCS file: /cvsroot/gcc/gcc/libstdc++-v3/config.h.in,v
retrieving revision 1.56
diff -u -p -r1.56 config.h.in
--- config.h.in	11 Jun 2002 17:53:59 -0000	1.56
+++ config.h.in	11 Oct 2002 00:59:37 -0000
@@ -24,6 +24,9 @@
 // Define to use concept checking code from the boost libraries.
 #undef _GLIBCPP_CONCEPT_CHECKS
 
+// Define to use the malloc-based allocator instead pool-based one
+#undef _GLIBCPP_USE_MALLOC
+
 // Define if mbstate_t exists in wchar.h.
 #undef HAVE_MBSTATE_T
 
Index: configure.in
===================================================================
RCS file: /cvsroot/gcc/gcc/libstdc++-v3/configure.in,v
retrieving revision 1.105
diff -u -p -r1.105 configure.in
--- configure.in	26 Sep 2002 05:25:05 -0000	1.105
+++ configure.in	11 Oct 2002 00:59:37 -0000
@@ -66,6 +66,7 @@ GLIBCPP_ENABLE_CXX_FLAGS([none])
 GLIBCPP_ENABLE_SJLJ_EXCEPTIONS
 GLIBCPP_ENABLE_LIBUNWIND_EXCEPTIONS
 GLIBCPP_ENABLE_CONCEPT_CHECKS
+GLIBCPP_ENABLE_POOL_ALLOCATOR        
 
 # Check for headers necessary for libsupc++ using dyn-string.c/cxa_demangle.c
 AC_CHECK_HEADERS(string.h stdlib.h)
Index: include//backward/alloc.h
===================================================================
RCS file: /cvsroot/gcc/gcc/libstdc++-v3/include/backward/alloc.h,v
retrieving revision 1.11
diff -u -p -r1.11 alloc.h
--- include//backward/alloc.h	6 Dec 2001 20:29:30 -0000	1.11
+++ include//backward/alloc.h	11 Oct 2002 00:59:37 -0000
@@ -50,13 +50,9 @@
 using std::__malloc_alloc_template; 
 using std::__simple_alloc; 
 using std::__debug_alloc; 
+using std::__pool_alloc_template;
 using std::__alloc; 
 using std::__single_client_alloc; 
 using std::allocator;
-#ifdef __USE_MALLOC
-using std::malloc_alloc; 
-#else
-using std::__default_alloc_template; 
-#endif
 
 #endif 
Index: include//bits/c++config
===================================================================
RCS file: /cvsroot/gcc/gcc/libstdc++-v3/include/bits/c++config,v
retrieving revision 1.505
diff -u -p -r1.505 c++config
--- include//bits/c++config	7 Oct 2002 07:19:04 -0000	1.505
+++ include//bits/c++config	11 Oct 2002 00:59:37 -0000
@@ -69,15 +69,19 @@
 // that threads are properly configured on your platform before
 // assigning blame to the STL container-memory allocator.  After doing
 // so, please report any possible issues to libstdc++@gcc.gnu.org .
-// Do not define __USE_MALLOC on the command line.  Enforce it here:
-#ifdef __USE_MALLOC
-#error __USE_MALLOC should only be defined within \
-libstdc++-v3/include/bits/c++config before full recompilation of the library.
-#endif
-// Define __USE_MALLOC after this point in the file in order to aid debugging
-// or globally change allocation policy.  This breaks the ABI, thus
-// completely recompile the library.  A patch to better support
-// changing the global allocator policy would be probably be accepted.
+//
+// TODO: XXX Fix this comment!
+// Do not arbitrarily define _GLIBCPP_USE_MALLOC on the command line.
+// It must be defined at library-build time (via the
+// --enable-pool-allocator option).  Configure the library to use
+// malloc (via --enable-pool-allocator=no) in order to aid debugging or
+// globally change allocation policy.  This breaks the ABI, thus
+// completely recompile the library.
+//
+// See libstdc++-v3/docs/html/configopts.html for details.
+//
+// A patch to better support changing the global allocator policy would be
+// probably be accepted. 
 
 // The remainder of the prewritten config is mostly automatic; all the
 // user hooks are listed above.
Index: include//bits/stl_alloc.h
===================================================================
RCS file: /cvsroot/gcc/gcc/libstdc++-v3/include/bits/stl_alloc.h,v
retrieving revision 1.24
diff -u -p -r1.24 stl_alloc.h
--- include//bits/stl_alloc.h	23 Aug 2002 16:52:29 -0000	1.24
+++ include//bits/stl_alloc.h	11 Oct 2002 00:59:38 -0000
@@ -115,9 +115,9 @@ namespace std
   /**
    *  @if maint
    *  A malloc-based allocator.  Typically slower than the
-   *  __default_alloc_template (below).  Typically thread-safe and more
+   *  __pool_alloc_template (below).  Typically thread-safe and more
    *  storage efficient.  The template argument is unused and is only present
-   *  to permit multiple instantiations (but see __default_alloc_template
+   *  to permit multiple instantiations (but see __pool_alloc_template
    *  for caveats).  "SGI" style, plus __set_malloc_handler for OOM conditions.
    *  @endif
    *  (See @link Allocators allocators info @endlink for more.)
@@ -211,8 +211,11 @@ namespace std
 #endif
 
 
-  // Determines the underlying allocator choice for the node allocator.
-#ifdef __USE_MALLOC
+  // Determines the underlying allocator choice for the node allocator.  The
+  // standard requires new and delete, but we allow raw malloc and free when
+  // the malloc allocator is in use.  This can (probably) change the ABI.
+  // TODO: XXX Is this wise?
+#ifdef _GLIBCPP_USE_MALLOC
   typedef __malloc_alloc_template<0>  __mem_interface;
 #else
   typedef __new_alloc                 __mem_interface;
@@ -306,15 +309,6 @@ namespace std
 #endif
     };
 
-
-#ifdef __USE_MALLOC
-
-  typedef __mem_interface __alloc;
-  typedef __mem_interface __single_client_alloc;
-
-#else
-
-
   /**
    *  @if maint
    *  Default node allocator.  "SGI" style.  Uses __mem_interface for its
@@ -331,21 +325,21 @@ namespace std
    *
    *  The first template parameter specifies whether more than one thread may
    *  use this allocator.  It is safe to allocate an object from one instance
-   *  of a default_alloc and deallocate it with another one.  This effectively
+   *  of a pool_alloc and deallocate it with another one.  This effectively
    *  transfers its ownership to the second one.  This may have undesirable
    *  effects on reference locality.
    *
    *  The second parameter is unused and serves only to allow the creation of
-   *  multiple default_alloc instances.  Note that containers built on different
+   *  multiple pool_alloc instances.  Note that containers built on different
    *  allocator instances have different types, limiting the utility of this
    *  approach.  If you do not wish to share the free lists with the main
-   *  default_alloc instance, instantiate this with a non-zero __inst.
+   *  pool_alloc instance, instantiate this with a non-zero __inst.
    *
    *  @endif
    *  (See @link Allocators allocators info @endlink for more.)
    */
   template<bool __threads, int __inst>
-    class __default_alloc_template
+    class __pool_alloc_template
     {
     private:
       enum {_ALIGN = 8};
@@ -453,14 +447,14 @@ namespace std
 
   template<bool __threads, int __inst>
     inline bool
-    operator==(const __default_alloc_template<__threads,__inst>&,
-               const __default_alloc_template<__threads,__inst>&)
+    operator==(const __pool_alloc_template<__threads,__inst>&,
+               const __pool_alloc_template<__threads,__inst>&)
     { return true; }
 
   template<bool __threads, int __inst>
     inline bool
-    operator!=(const __default_alloc_template<__threads,__inst>&,
-               const __default_alloc_template<__threads,__inst>&)
+    operator!=(const __pool_alloc_template<__threads,__inst>&,
+               const __pool_alloc_template<__threads,__inst>&)
     { return false; }
 
 
@@ -469,7 +463,7 @@ namespace std
   // that __size is properly aligned.  We hold the allocation lock.
   template<bool __threads, int __inst>
     char*
-    __default_alloc_template<__threads, __inst>::
+    __pool_alloc_template<__threads, __inst>::
     _S_chunk_alloc(size_t __size, int& __nobjs)
     {
       char* __result;
@@ -544,7 +538,7 @@ namespace std
   // hold the allocation lock.
   template<bool __threads, int __inst>
     void*
-    __default_alloc_template<__threads, __inst>::_S_refill(size_t __n)
+    __pool_alloc_template<__threads, __inst>::_S_refill(size_t __n)
     {
       int __nobjs = 20;
       char* __chunk = _S_chunk_alloc(__n, __nobjs);
@@ -580,7 +574,7 @@ namespace std
 #ifdef _GLIBCPP_DEPRECATED
   template<bool threads, int inst>
     void*
-    __default_alloc_template<threads, inst>::
+    __pool_alloc_template<threads, inst>::
     reallocate(void* __p, size_t __old_sz, size_t __new_sz)
     {
       void* __result;
@@ -600,25 +594,37 @@ namespace std
 
   template<bool __threads, int __inst>
     _STL_mutex_lock
-    __default_alloc_template<__threads,__inst>::_S_node_allocator_lock
+    __pool_alloc_template<__threads,__inst>::_S_node_allocator_lock
     __STL_MUTEX_INITIALIZER;
 
   template<bool __threads, int __inst>
-    char* __default_alloc_template<__threads,__inst>::_S_start_free = 0;
+    char* __pool_alloc_template<__threads,__inst>::_S_start_free = 0;
 
   template<bool __threads, int __inst>
-    char* __default_alloc_template<__threads,__inst>::_S_end_free = 0;
+    char* __pool_alloc_template<__threads,__inst>::_S_end_free = 0;
 
   template<bool __threads, int __inst>
-    size_t __default_alloc_template<__threads,__inst>::_S_heap_size = 0;
+    size_t __pool_alloc_template<__threads,__inst>::_S_heap_size = 0;
 
   template<bool __threads, int __inst>
-    typename __default_alloc_template<__threads,__inst>::_Obj* volatile
-    __default_alloc_template<__threads,__inst>::_S_free_list[_NFREELISTS];
+    typename __pool_alloc_template<__threads,__inst>::_Obj* volatile
+    __pool_alloc_template<__threads,__inst>::_S_free_list[_NFREELISTS];
+
+  // Select the implementation of the standard std::allocator (hereafter
+  // referred to as the "default allocator").  This can change the ABI.
+#ifdef _GLIBCPP_USE_MALLOC
+  
+  // Use the malloc-based allocator for all node allocations themselves
+  typedef __mem_interface __alloc;
+  typedef __mem_interface __single_client_alloc;
+  
+#else /* _GLIBCPP_USE_MALLOC */
 
-  typedef __default_alloc_template<true,0>    __alloc;
-  typedef __default_alloc_template<false,0>   __single_client_alloc;
-#endif /* ! __USE_MALLOC */
+  // Use the pool-based allocator for all node allocations themselves
+  typedef __pool_alloc_template<true,0>    __alloc;
+  typedef __pool_alloc_template<false,0>   __single_client_alloc;
+  
+#endif /* ! _GLIBCPP_USE_MALLOC */
 
 
   /**
@@ -628,11 +634,11 @@ namespace std
    *  of stl_alloc.h.)
    *
    *  The underlying allocator behaves as follows.
-   *  - if __USE_MALLOC then
+   *  - if _GLIBCPP_USE_MALLOC then
    *    - thread safety depends on malloc and is entirely out of our hands
    *    - __malloc_alloc_template is used for memory requests
    *  - else (the default)
-   *    - __default_alloc_template is used via two typedefs
+   *    - __pool_alloc_template is used via two typedefs
    *    - "__single_client_alloc" typedef does no locking for threads
    *    - "__alloc" typedef is threadsafe via the locks
    *    - __new_alloc is used for memory requests
@@ -908,17 +914,15 @@ namespace std
       typedef __allocator<_Tp, __malloc_alloc_template<__inst> > allocator_type;
     };
 
-#ifndef __USE_MALLOC
   template<typename _Tp, bool __threads, int __inst>
-    struct _Alloc_traits<_Tp, __default_alloc_template<__threads, __inst> >
+    struct _Alloc_traits<_Tp, __pool_alloc_template<__threads, __inst> >
     {
       static const bool _S_instanceless = true;
-      typedef __simple_alloc<_Tp, __default_alloc_template<__threads, __inst> >
+      typedef __simple_alloc<_Tp, __pool_alloc_template<__threads, __inst> >
       _Alloc_type;
-      typedef __allocator<_Tp, __default_alloc_template<__threads, __inst> >
+      typedef __allocator<_Tp, __pool_alloc_template<__threads, __inst> >
       allocator_type;
     };
-#endif
 
   template<typename _Tp, typename _Alloc>
     struct _Alloc_traits<_Tp, __debug_alloc<_Alloc> >
@@ -941,17 +945,15 @@ namespace std
       typedef __allocator<_Tp, __malloc_alloc_template<__inst> > allocator_type;
     };
 
-#ifndef __USE_MALLOC
   template<typename _Tp, typename _Tp1, bool __thr, int __inst>
-    struct _Alloc_traits<_Tp, __allocator<_Tp1, __default_alloc_template<__thr, __inst> > >
+    struct _Alloc_traits<_Tp, __allocator<_Tp1, __pool_alloc_template<__thr, __inst> > >
     {
       static const bool _S_instanceless = true;
-      typedef __simple_alloc<_Tp, __default_alloc_template<__thr,__inst> >
+      typedef __simple_alloc<_Tp, __pool_alloc_template<__thr,__inst> >
       _Alloc_type;
-      typedef __allocator<_Tp, __default_alloc_template<__thr,__inst> >
+      typedef __allocator<_Tp, __pool_alloc_template<__thr,__inst> >
       allocator_type;
     };
-#endif
 
   template<typename _Tp, typename _Tp1, typename _Alloc>
     struct _Alloc_traits<_Tp, __allocator<_Tp1, __debug_alloc<_Alloc> > >
@@ -967,11 +969,37 @@ namespace std
   // NB: This syntax is a GNU extension.
   extern template class allocator<char>;
   extern template class allocator<wchar_t>;
-#ifdef __USE_MALLOC
+
+  // Both allocators are instantiated in the library itself regardless of
+  // which is the default node allocator.
   extern template class __malloc_alloc_template<0>;
+  extern template class __pool_alloc_template<true,0>;
+
+  // Possible extension mentioned in
+  // http://gcc.gnu.org/ml/libstdc++/2002-10/msg00079.html 
+  // Provides an easy way for the user to ask for either allocation mechanism
+  // regardless of the default.  We pick the most efficient form that
+  // implements the desired mechanism.
+  // Another way
+#ifdef _GLIBCPP_USE_MALLOC
+  typedef allocator<void> __malloc_allocator;
+  typedef __allocator<void, __pool_alloc_template<true, 0> > __pool_allocator;
+#else /* _GLIBCPP_USE_MALLOC */
+  typedef __allocator<void, __malloc_alloc_template<0> > __malloc_allocator;
+  typedef allocator<void> __pool_allocator;
+#endif /* _GLIBCPP_USE_MALLOC */
+  
+  // Prevent linkage of objects compiled with different default allocators
+#ifdef _GLIBCPP_USE_MALLOC
+  extern const int __default_allocator_is_malloc_alloc_template;
+  static const int* __default_allocator =
+    &__default_allocator_is_malloc_alloc_template;
 #else
-  extern template class __default_alloc_template<true,0>;
+  extern const int __default_allocator_is_pool_alloc_template;
+  static const int* __default_allocator =
+    &__default_allocator_is_pool_alloc_template;
 #endif
+
 } // namespace std
 
 #endif
Index: testsuite//ext/allocators.cc
===================================================================
RCS file: /cvsroot/gcc/gcc/libstdc++-v3/testsuite/ext/allocators.cc,v
retrieving revision 1.1
diff -u -p -r1.1 allocators.cc
--- testsuite//ext/allocators.cc	11 Dec 2001 19:04:58 -0000	1.1
+++ testsuite//ext/allocators.cc	11 Oct 2002 00:59:39 -0000
@@ -20,7 +20,6 @@
 
 // 20.4.1.1 allocator members
 
-#undef __USE_MALLOC
 #include <memory>
 #include <cstdlib>
 #include <testsuite_hooks.h>
@@ -31,11 +30,11 @@ template class std::__malloc_alloc_templ
 typedef std::__debug_alloc<weird_alloc>             debug_weird_alloc;
 template class std::__debug_alloc<weird_alloc>;
 
-typedef std::__default_alloc_template<true, 3>      unshared_normal_alloc;
-template class std::__default_alloc_template<true, 3>;
+typedef std::__pool_alloc_template<true, 3>      unshared_normal_alloc;
+template class std::__pool_alloc_template<true, 3>;
 
-typedef std::__default_alloc_template<false, 3>     unshared_singlethreaded;
-template class std::__default_alloc_template<false, 3>;
+typedef std::__pool_alloc_template<false, 3>     unshared_singlethreaded;
+template class std::__pool_alloc_template<false, 3>;
 
 //std::malloc_alloc test_malloc_alloc;
 


More information about the Libstdc++ mailing list