Main Page   Reference Manual   Namespace List   Compound List   Namespace Members   Compound Members   File Members  

private_allocator.h

Go to the documentation of this file.
00001 // $Header: /cvsroot/libcwd/libcwd/include/libcwd/private_allocator.h,v 1.11 2005/05/31 02:06:35 libcw Exp $
00002 //
00003 // Copyright (C) 2001 - 2004, by
00004 // 
00005 // Carlo Wood, Run on IRC <carlo@alinoe.com>
00006 // RSA-1024 0x624ACAD5 1997-01-26                    Sign & Encrypt
00007 // Fingerprint16 = 32 EC A7 B6 AC DB 65 A6  F6 F6 55 DD 1C DC FF 61
00008 //
00009 // This file may be distributed under the terms of the Q Public License
00010 // version 1.0 as appearing in the file LICENSE.QPL included in the
00011 // packaging of this file.
00012 //
00013 
00018 #ifndef LIBCWD_PRIVATE_ALLOCATOR_H
00019 #define LIBCWD_PRIVATE_ALLOCATOR_H
00020 
00021 #ifndef LIBCWD_CONFIG_H
00022 #include <libcwd/config.h>
00023 #endif
00024 
00025 #if CWDEBUG_ALLOC               // This file is not used when --disable-alloc was used.
00026 
00027 #ifndef LIBCWD_PRIVATE_MUTEX_INSTANCES_H
00028 #include <libcwd/private_mutex_instances.h>
00029 #endif
00030 #ifndef LIBCWD_CORE_DUMP_H
00031 #include <libcwd/core_dump.h>
00032 #endif
00033 #ifndef LIBCW_CSTDDEF
00034 #define LIBCW_CSTDDEF
00035 #include <cstddef>              // Needed for size_t
00036 #endif
00037 
00038 //===================================================================================================
00039 // Allocators
00040 //
00041 //
00042 
00043 /* The allocators used by libcwd have the following characteristics:
00044 
00045    1) The type T that is being allocated and deallocated.
00046    2) Whether or not the allocation is internal, auto-internal or in userspace.
00047    3) The pool instance from which the allocation should be drawn.
00048    4) Whether or not a lock is needed for this pool.
00049    5) Whether or not this allocation belongs to a libcwd
00050       critical area and if so, which one.
00051 
00052    Note that each critical area (if any) uses its own lock and
00053    therefore no (additional) lock will be needed for the allocator.
00054    Otherwise a lock is always needed (in the multi-threaded case).
00055    As of gcc 4.0, the used pool allocator doesn't use locks anymore
00056    but separates the pools per thread (except for one common pool),
00057    this need is equivalent for us to needing a lock or not: if we
00058    don't need a lock then there is also no need to separate per thread.
00059 
00060    There are five different allocators in use by libcwd:
00061 
00062 Multi-threaded case:
00063 
00064    Allocator name               | internal | Pool instance                      | Needs lock
00065    ----------------------------------------------------------------------------------------------------
00066    memblk_map_allocator         | yes      | memblk_map_instance                | no (memblk_map_instance critical area)
00067    object_files_allocator       | yes      | object_files_instance              | no (object_files_instance critical area)
00068    internal_allocator           | yes      | multi_threaded_internal_instance   | yes
00069    auto_internal_allocator      | auto     | multi_threaded_internal_instance   | yes
00070    userspace_allocator          | no       | userspace_instance                 | yes
00071 
00072 Single-threaded case:
00073 
00074    Allocator name               | internal | Pool instance                      | Needs lock
00075    ----------------------------------------------------------------------------------------------------
00076    memblk_map_allocator         | yes      | single_threaded_internal_instance  | no
00077    object_files_allocator       | yes      | single_threaded_internal_instance  | no
00078    internal_allocator           | yes      | single_threaded_internal_instance  | no
00079    auto_internal_allocator      | auto     | single_threaded_internal_instance  | no
00080    userspace_allocator          | no       | std::alloc                         | -
00081 
00082 */
00083 
00084 #if __GNUC__ == 3 && __GNUC_MINOR__ == 4
00085 #include <ext/pool_allocator.h>         // __gnu_cxx::__pool_alloc
00086 #endif
00087 #if __GNUC__ >= 4
00088 #include <ext/mt_allocator.h>           // __gnu_cxx::__pool
00089 #endif
00090 
00091 namespace libcwd {
00092   namespace _private_ {
00093 
00094 // This is a random number in the hope nobody else uses it.
00095 int const random_salt = 327665;
00096 
00097 // Dummy mutex instance numbers, these must be negative.
00098 int const multi_threaded_internal_instance = -1;
00099 int const single_threaded_internal_instance = -2;
00100 int const userspace_instance = -3;
00101 
00102 #if __GNUC__ == 3 && __GNUC_MINOR__ < 4
00103 template<bool needs_lock, int pool_instance>
00104   struct CharPoolAlloc : public std::__default_alloc_template<needs_lock, random_salt + pool_instance> {
00105     typedef char* pointer;
00106   };
00107 #elif __GNUC__ == 3 && __GNUC_MINOR__ == 4 && __GNUC_PATCHLEVEL__ == 0
00108 template<bool needs_lock, int pool_instance>
00109   struct CharPoolAlloc : public __gnu_cxx::__pool_alloc<needs_lock, random_salt + pool_instance> {
00110     typedef char* pointer;
00111   };
00112 #else // gcc 3.4.1 and higher.
00113 template<int pool_instance>
00114   struct char_wrapper {
00115     char c;
00116   };
00117 #if __GNUC__ == 3
00118 // gcc 3.4.1 and 3.4.2 always use a lock, in the threaded case.
00119 template<bool needs_lock, int pool_instance>
00120   class CharPoolAlloc : public __gnu_cxx::__pool_alloc<char_wrapper<pool_instance> > { };
00121 #else // gcc 4.0 and higher.
00122 // A wrapper around a pointer to the actual pool type (__gnu_cxx::__pool<>)
00123 // that automatically deletes its pointer on destruction.
00124 // This class does not need a reference counter because we only use it for static objects.
00125 template<class __pool_type>
00126   struct static_pool_instance {
00127     __pool_type* ptr;
00128     bool M_internal;
00129     static_pool_instance(void) { }      // Do NOT initialize `ptr'! It is automatically initialized
00130                                         // to NULL because this is a static POD object and ptr might
00131                                         // already be initialized before the global constructor of
00132                                         // this object would be called.
00133     void create(void);                  // This does the initialization.
00134   };
00135 // The class that holds the actual pool instance.
00136 // This class also defines policies (so far only whether or not threading is used).
00137 template<int pool_instance, bool needs_lock>
00138   struct pool_instance_and_policy {
00139     typedef __gnu_cxx::__pool<needs_lock> pool_type;            // Underlaying pool type.
00140     static static_pool_instance<pool_type> _S_pool_instance;    // The actual pool instance.
00141 
00142     // The following is needed as interface of a 'pool_policy' class as used by __gnu_cxx::__mt_alloc.
00143     static pool_type& _S_get_pool(void)                         // Accessor to the pool_type singleton.
00144         { return *_S_pool_instance.ptr; }
00145     static void _S_initialize_once(void)                        // This is called every time a new allocation is done.
00146     { 
00147       static bool __init;
00148       if (__builtin_expect(__init == false, false))
00149       {
00150         _S_pool_instance.create();
00151         _S_pool_instance.ptr->_M_initialize_once(); 
00152         __init = true;
00153       }
00154     }
00155   };
00156 
00157 #ifdef __GTHREADS
00158 // Specialization, needed because in this case more interface is needed for the
00159 // 'pool_policy' class as used by __gnu_cxx::__mt_alloc.
00160 template<int pool_instance>
00161   struct pool_instance_and_policy<pool_instance, true>
00162   {
00163     typedef __gnu_cxx::__pool<true> pool_type;                  // Underlaying pool type.
00164     static static_pool_instance<pool_type> _S_pool_instance;    // The actual pool instance.
00165     
00166     // The following is needed as interface of a 'pool_policy' class as used by __gnu_cxx::__mt_alloc.
00167     static pool_type& _S_get_pool(void)                         // Accessor to the pool_type singleton.
00168         { return *_S_pool_instance.ptr; }
00169     static void _S_initialize_once(void)                        // This is called every time a new allocation is done.
00170     { 
00171       static bool __init;
00172       if (__builtin_expect(__init == false, false))
00173       {
00174         _S_pool_instance.create();
00175         _S_pool_instance.ptr->_M_initialize_once(_S_initialize);        // Passes _S_initialize in this case.
00176         __init = true;
00177       }
00178     }
00179     // And the extra interface:
00180     static void _S_destroy_thread_key(void* __freelist_pos) { _S_get_pool()._M_destroy_thread_key(__freelist_pos); }
00181     static void _S_initialize(void) { _S_get_pool()._M_initialize(_S_destroy_thread_key); }
00182   };
00183 
00184 template<int pool_instance>
00185   static_pool_instance<typename pool_instance_and_policy<pool_instance, true>::pool_type>
00186       pool_instance_and_policy<pool_instance, true>::_S_pool_instance;
00187 #endif // __GTHREADS
00188 
00189 template<int pool_instance, bool needs_lock>
00190   static_pool_instance<typename pool_instance_and_policy<pool_instance, needs_lock>::pool_type>
00191       pool_instance_and_policy<pool_instance, needs_lock>::_S_pool_instance;
00192 
00193 template<bool needs_lock, int pool_instance>
00194   class CharPoolAlloc : public __gnu_cxx::__mt_alloc<char, pool_instance_and_policy<pool_instance, needs_lock> > { };
00195 #endif // gcc 4.0 and higher.
00196 #endif // gcc 3.4.1 and higher.
00197 
00198 // Convenience macros.
00199 #if CWDEBUG_DEBUG
00200 #define LIBCWD_COMMA_INT_INSTANCE , int instance
00201 #define LIBCWD_COMMA_INSTANCE , instance
00202 #define LIBCWD_DEBUGDEBUG_COMMA(x) , x
00203 #else
00204 #define LIBCWD_COMMA_INT_INSTANCE
00205 #define LIBCWD_COMMA_INSTANCE
00206 #define LIBCWD_DEBUGDEBUG_COMMA(x)
00207 #endif
00208 
00209 enum pool_nt {
00210   userspace_pool,
00211   internal_pool,
00212   auto_internal_pool
00213 };
00214 
00215 // This wrapper adds sanity checks to the allocator use (like testing if
00216 // 'internal' allocators are indeed only used while in internal mode, and
00217 // critical area allocators are only used when the related lock is indeed
00218 // locked etc.
00219 template<typename T, class CharAlloc, pool_nt internal LIBCWD_COMMA_INT_INSTANCE>
00220     class allocator_adaptor {
00221     private:
00222       // The underlying allocator.
00223       CharAlloc M_char_allocator;
00224 
00225     public:
00226       // Type definitions.
00227       typedef T         value_type;
00228       typedef size_t    size_type;
00229       typedef ptrdiff_t difference_type;
00230       typedef T*                pointer;
00231       typedef T const*  const_pointer;
00232       typedef T&                reference;
00233       typedef T const&  const_reference;
00234 
00235       // Rebind allocator to type U.
00236       template <class U>
00237         struct rebind {
00238           typedef allocator_adaptor<U, CharAlloc, internal LIBCWD_COMMA_INSTANCE> other;
00239         };
00240 
00241       // Return address of values.
00242       pointer address(reference value) const { return &value; }
00243       const_pointer address(const_reference value) const { return &value; }
00244 
00245       // Constructors and destructor.
00246       allocator_adaptor(void) throw() { }
00247       allocator_adaptor(allocator_adaptor const& a) : M_char_allocator(a.M_char_allocator) { }
00248       template<class U>
00249         allocator_adaptor(allocator_adaptor<U, CharAlloc, internal LIBCWD_COMMA_INSTANCE> const& a) :
00250             M_char_allocator(a.M_char_allocator) { }
00251       template<class T2, class CharAlloc2, pool_nt internal2 LIBCWD_DEBUGDEBUG_COMMA(int instance2)>
00252         friend class allocator_adaptor;
00253       ~allocator_adaptor() throw() { }
00254 
00255       // Return maximum number of elements that can be allocated.
00256       size_type max_size(void) const { return M_char_allocator.max_size() / sizeof(T); }
00257 
00258       // Allocate but don't initialize num elements of type T.
00259       pointer allocate(size_type num);
00260       pointer allocate(size_type num, void const* hint);
00261 
00262       // Deallocate storage p of deleted elements.
00263       void deallocate(pointer p, size_type num);
00264 
00265       // Initialize elements of allocated storage p with value value.
00266       void construct(pointer p, T const& value) { new ((void*)p) T(value); }
00267 
00268       // Destroy elements of initialized storage p.
00269       void destroy(pointer p) { p->~T(); }
00270 
00271 #if CWDEBUG_DEBUG || CWDEBUG_DEBUGM
00272     private:
00273       static void sanity_check(void);
00274 #endif
00275 
00276       template <class T1, class CharAlloc1, pool_nt internal1 LIBCWD_DEBUGDEBUG_COMMA(int inst1),
00277                 class T2, class CharAlloc2, pool_nt internal2 LIBCWD_DEBUGDEBUG_COMMA(int inst2)>
00278         friend inline
00279         bool operator==(allocator_adaptor<T1, CharAlloc1, internal1 LIBCWD_DEBUGDEBUG_COMMA(inst1)> const& a1,
00280                         allocator_adaptor<T2, CharAlloc2, internal2 LIBCWD_DEBUGDEBUG_COMMA(inst2)> const& a2);
00281       template <class T1, class CharAlloc1, pool_nt internal1 LIBCWD_DEBUGDEBUG_COMMA(int inst1),
00282                 class T2, class CharAlloc2, pool_nt internal2 LIBCWD_DEBUGDEBUG_COMMA(int inst2)>
00283         friend inline
00284         bool operator!=(allocator_adaptor<T1, CharAlloc1, internal1 LIBCWD_DEBUGDEBUG_COMMA(inst1)> const& a1,
00285                         allocator_adaptor<T2, CharAlloc2, internal2 LIBCWD_DEBUGDEBUG_COMMA(inst2)> const& a2);
00286     };
00287 
00288 #if LIBCWD_THREAD_SAFE
00289 // We normally would be able to use the default allocator, but... libcwd functions can
00290 // at all times be called from malloc which might be called from std::allocator with its
00291 // lock set.  Therefore we also use a separate allocator pool for the userspace, in the
00292 // threaded case.
00293 #define LIBCWD_CHARALLOCATOR_USERSPACE(instance) ::libcwd::_private_::                          \
00294         allocator_adaptor<char,                                                                 \
00295                           CharPoolAlloc<true, userspace_instance>,                              \
00296                           userspace_pool                                                        \
00297                           LIBCWD_DEBUGDEBUG_COMMA(::libcwd::_private_::instance)>
00298 #endif
00299 
00300 // Both, multi_threaded_internal_instance and memblk_map_instance use also locks for
00301 // the allocator pool itself because they (the memory pools) are being shared between
00302 // threads from within critical areas with different mutexes.
00303 // Other instances (> 0) are supposed to only use the allocator instance from within
00304 // the critical area of the corresponding mutex_tct<instance>, and thus only by one
00305 // thread at a time.
00306 #if LIBCWD_THREAD_SAFE
00307 #define LIBCWD_ALLOCATOR_POOL_NEEDS_LOCK(instance)                                              \
00308                                 ::libcwd::_private_::instance ==                                \
00309                                 ::libcwd::_private_::multi_threaded_internal_instance ||        \
00310                                 ::libcwd::_private_::instance ==                                \
00311                                 ::libcwd::_private_::memblk_map_instance
00312 #else // !LIBCWD_THREAD_SAFE
00313 #define LIBCWD_ALLOCATOR_POOL_NEEDS_LOCK(instance) false
00314 #endif // !LIBCWD_THREAD_SAFE
00315 
00316 #define LIBCWD_CHARALLOCATOR_INTERNAL(instance) ::libcwd::_private_::                   \
00317         allocator_adaptor<char,                                                                 \
00318                           CharPoolAlloc<LIBCWD_ALLOCATOR_POOL_NEEDS_LOCK(instance),             \
00319                                         ::libcwd::_private_::instance >,                        \
00320                           internal_pool                                                         \
00321                           LIBCWD_DEBUGDEBUG_COMMA(::libcwd::_private_::instance)>
00322 
00323 #define LIBCWD_CHARALLOCATOR_AUTO_INTERNAL(instance) ::libcwd::_private_::              \
00324         allocator_adaptor<char,                                                                 \
00325                           CharPoolAlloc<LIBCWD_ALLOCATOR_POOL_NEEDS_LOCK(instance),             \
00326                                         ::libcwd::_private_::instance >,                        \
00327                           auto_internal_pool                                                    \
00328                           LIBCWD_DEBUGDEBUG_COMMA(::libcwd::_private_::instance)>
00329 
00330 #if LIBCWD_THREAD_SAFE
00331 // Our allocator adaptor for the Non-Shared internal cases: Single Threaded
00332 // (inst = single_threaded_internal_instance) or inside the critical area of the corresponding
00333 // libcwd mutex instance.
00334 #define LIBCWD_NS_INTERNAL_ALLOCATOR(instance)  LIBCWD_CHARALLOCATOR_INTERNAL(instance)
00335 #else // !LIBCWD_THREAD_SAFE
00336 // In a single threaded application, the Non-Shared case is equivalent to the Single Threaded case.
00337 #define LIBCWD_NS_INTERNAL_ALLOCATOR(instance)  LIBCWD_CHARALLOCATOR_INTERNAL(single_threaded_internal_instance)
00338 #endif // !LIBCWD_THREAD_SAFE
00339 
00340 #if LIBCWD_THREAD_SAFE
00341 // LIBCWD_MT_*_ALLOCATOR uses a different allocator than the normal default allocator of libstdc++
00342 // in the case of multi-threading because it can be that the allocator mutex is locked, which would
00343 // result in a deadlock if we try to use it again here.
00344 #define LIBCWD_MT_USERSPACE_ALLOCATOR           LIBCWD_CHARALLOCATOR_USERSPACE(userspace_instance)
00345 #define LIBCWD_MT_INTERNAL_ALLOCATOR            LIBCWD_CHARALLOCATOR_INTERNAL(multi_threaded_internal_instance)
00346 #define LIBCWD_MT_AUTO_INTERNAL_ALLOCATOR       LIBCWD_CHARALLOCATOR_AUTO_INTERNAL(multi_threaded_internal_instance)
00347 #else // !LIBCWD_THREAD_SAFE
00348 // LIBCWD_MT_*_ALLOCATOR uses the normal default allocator of libstdc++-v3 (alloc) using locking
00349 // itself.  The userspace allocator shares it memory pool with everything else (that uses this
00350 // allocator, which is most of the (userspace) STL).
00351 #define LIBCWD_MT_USERSPACE_ALLOCATOR           std::allocator<char>
00352 #define LIBCWD_MT_INTERNAL_ALLOCATOR            LIBCWD_CHARALLOCATOR_INTERNAL(single_threaded_internal_instance)
00353 #define LIBCWD_MT_AUTO_INTERNAL_ALLOCATOR       LIBCWD_CHARALLOCATOR_AUTO_INTERNAL(single_threaded_internal_instance)
00354 #endif // !LIBCWD_THREAD_SAFE
00355 
00356 //---------------------------------------------------------------------------------------------------
00357 // Internal allocator types.
00358 
00359 // This allocator is used in critical areas that are already locked by memblk_map_instance.
00360 typedef LIBCWD_NS_INTERNAL_ALLOCATOR(memblk_map_instance) memblk_map_allocator;
00361 
00362 // This allocator is used in critical areas that are already locked by object_files_instance.
00363 typedef LIBCWD_NS_INTERNAL_ALLOCATOR(object_files_instance) object_files_allocator;
00364 
00365 // This general allocator can be used outside libcwd-specific critical areas,
00366 // but inside a set_alloc_checking_off() .. set_alloc_checking_on() pair.
00367 typedef LIBCWD_MT_INTERNAL_ALLOCATOR internal_allocator;
00368 
00369 // This general allocator can be used outside libcwd-specific critical areas,
00370 // in "user space" but that will cause internal memory to be allocated.
00371 typedef LIBCWD_MT_AUTO_INTERNAL_ALLOCATOR auto_internal_allocator;
00372 
00373 //---------------------------------------------------------------------------------------------------
00374 // User space allocator type.
00375 
00376 // This general allocator can be used outside libcwd-specific critical areas.
00377 typedef LIBCWD_MT_USERSPACE_ALLOCATOR userspace_allocator;
00378 
00379   } // namespace _private_
00380 } // namespace libcwd
00381  
00382 #endif // CWDEBUG_ALLOC
00383 #endif // LIBCWD_PRIVATE_ALLOCATOR_H
00384 
Copyright © 2001 - 2004 Carlo Wood.  All rights reserved.