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

libcwd/private_allocator.h

Go to the documentation of this file.
00001 // $Header: /cvsroot/libcwd/libcwd/include/libcwd/private_allocator.h,v 1.9 2004/10/10 17:17:30 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 
00088 namespace libcwd {
00089   namespace _private_ {
00090 
00091 // This is a random number in the hope nobody else uses it.
00092 int const random_salt = 327665;
00093 
00094 // Dummy mutex instance numbers, these must be negative.
00095 int const multi_threaded_internal_instance = -1;
00096 int const single_threaded_internal_instance = -2;
00097 int const userspace_instance = -3;
00098 
00099 #if __GNUC__ == 3 && __GNUC_MINOR__ < 4
00100 template<bool needs_lock, int pool_instance>
00101   struct CharPoolAlloc : public std::__default_alloc_template<needs_lock, random_salt + pool_instance> {
00102     typedef char* pointer;
00103   };
00104 #elif __GNUC__ == 3 && __GNUC_MINOR__ == 4 && __GNUC_PATCHLEVEL__ == 0
00105 template<bool needs_lock, int pool_instance>
00106   struct CharPoolAlloc : public __gnu_cxx::__pool_alloc<needs_lock, random_salt + pool_instance> {
00107     typedef char* pointer;
00108   };
00109 #else // gcc 3.4.1 and higher.
00110 template<int pool_instance>
00111   struct char_wrapper {
00112     char c;
00113   };
00114 #if __GNUC__ == 3
00115 // gcc 3.4.1 and 3.4.2 always use a lock, in the threaded case.
00116 template<bool needs_lock, int pool_instance>
00117   class CharPoolAlloc : public __gnu_cxx::__pool_alloc<char_wrapper<pool_instance> > { };
00118 #else // gcc 4.0 and higher.
00119 // A wrapper around a pointer to the actual pool type (__gnu_cxx::__pool<>)
00120 // that automatically deletes its pointer on destruction.
00121 // This class does not need a reference counter because we only use it for static objects.
00122 template<class __pool_type>
00123   struct static_pool_instance {
00124     __pool_type* ptr;
00125     bool M_internal;
00126     static_pool_instance(void) { }      // Do NOT initialize `ptr'! It is automatically initialized
00127                                         // to NULL because this is a static POD object and ptr might
00128                                         // already be initialized before the global constructor of
00129                                         // this object would be called.
00130     void create(void);                  // This does the initialization.
00131   };
00132 // The class that holds the actual pool instance.
00133 // This class also defines policies (so far only whether or not threading is used).
00134 template<int pool_instance, bool needs_lock>
00135   struct pool_instance_and_policy {
00136     typedef __gnu_cxx::__pool<needs_lock> __pool_type;          // Underlaying pool type.
00137     static static_pool_instance<__pool_type> _S_pool_instance;  // The actual pool instance.
00138 
00139     // The following is needed as interface of a 'pool_policy' class as used by __gnu_cxx::__mt_alloc.
00140     static __pool_type& _S_get_pool(void)                       // Accessor to the __pool_type singleton.
00141         { return *_S_pool_instance.ptr; }
00142     static void _S_initialize_once(void)                        // This is called every time a new allocation is done.
00143     { 
00144       static bool __init;
00145       if (__builtin_expect(__init == false, false))
00146       {
00147         _S_pool_instance.create();
00148         _S_pool_instance.ptr->_M_initialize_once(); 
00149         __init = true;
00150       }
00151     }
00152   };
00153 
00154 #ifdef __GTHREADS
00155 // Specialization, needed because in this case more interface is needed for the
00156 // 'pool_policy' class as used by __gnu_cxx::__mt_alloc.
00157 template<int pool_instance>
00158   struct pool_instance_and_policy<pool_instance, true>
00159   {
00160     typedef __gnu_cxx::__pool<true> __pool_type;                // Underlaying pool type.
00161     static static_pool_instance<__pool_type> _S_pool_instance;  // The actual pool instance.
00162     
00163     // The following is needed as interface of a 'pool_policy' class as used by __gnu_cxx::__mt_alloc.
00164     static __pool_type& _S_get_pool(void)                       // Accessor to the __pool_type singleton.
00165         { return *_S_pool_instance.ptr; }
00166     static void _S_initialize_once(void)                        // This is called every time a new allocation is done.
00167     { 
00168       static bool __init;
00169       if (__builtin_expect(__init == false, false))
00170       {
00171         _S_pool_instance.create();
00172         _S_pool_instance.ptr->_M_initialize_once(_S_initialize);        // Passes _S_initialize in this case.
00173         __init = true;
00174       }
00175     }
00176     // And the extra interface:
00177     static void _S_destroy_thread_key(void* __freelist_pos) { _S_get_pool()._M_destroy_thread_key(__freelist_pos); }
00178     static void _S_initialize(void) { _S_get_pool()._M_initialize(_S_destroy_thread_key); }
00179   };
00180 
00181 template<int pool_instance>
00182   static_pool_instance<typename pool_instance_and_policy<pool_instance, true>::__pool_type>
00183       pool_instance_and_policy<pool_instance, true>::_S_pool_instance;
00184 #endif // __GTHREADS
00185 
00186 template<int pool_instance, bool needs_lock>
00187   static_pool_instance<typename pool_instance_and_policy<pool_instance, needs_lock>::__pool_type>
00188       pool_instance_and_policy<pool_instance, needs_lock>::_S_pool_instance;
00189 
00190 template<bool needs_lock, int pool_instance>
00191   class CharPoolAlloc : public __gnu_cxx::__mt_alloc<char, pool_instance_and_policy<pool_instance, needs_lock> > { };
00192 #endif // gcc 4.0 and higher.
00193 #endif // gcc 3.4.1 and higher.
00194 
00195 // Convenience macros.
00196 #if CWDEBUG_DEBUG
00197 #define LIBCWD_COMMA_INT_INSTANCE , int instance
00198 #define LIBCWD_COMMA_INSTANCE , instance
00199 #define LIBCWD_DEBUGDEBUG_COMMA(x) , x
00200 #else
00201 #define LIBCWD_COMMA_INT_INSTANCE
00202 #define LIBCWD_COMMA_INSTANCE
00203 #define LIBCWD_DEBUGDEBUG_COMMA(x)
00204 #endif
00205 
00206 enum pool_nt {
00207   userspace_pool,
00208   internal_pool,
00209   auto_internal_pool
00210 };
00211 
00212 // This wrapper adds sanity checks to the allocator use (like testing if
00213 // 'internal' allocators are indeed only used while in internal mode, and
00214 // critical area allocators are only used when the related lock is indeed
00215 // locked etc.
00216 template<typename T, class CharAlloc, pool_nt internal LIBCWD_COMMA_INT_INSTANCE>
00217     class allocator_adaptor {
00218     private:
00219       // The underlying allocator.
00220       CharAlloc M_char_allocator;
00221 
00222     public:
00223       // Type definitions.
00224       typedef T         value_type;
00225       typedef size_t    size_type;
00226       typedef ptrdiff_t difference_type;
00227       typedef T*                pointer;
00228       typedef T const*  const_pointer;
00229       typedef T&                reference;
00230       typedef T const&  const_reference;
00231 
00232       // Rebind allocator to type U.
00233       template <class U>
00234         struct rebind {
00235           typedef allocator_adaptor<U, CharAlloc, internal LIBCWD_COMMA_INSTANCE> other;
00236         };
00237 
00238       // Return address of values.
00239       pointer address(reference value) const { return &value; }
00240       const_pointer address(const_reference value) const { return &value; }
00241 
00242       // Constructors and destructor.
00243       allocator_adaptor(void) throw() { }
00244       allocator_adaptor(allocator_adaptor const& a) : M_char_allocator(a.M_char_allocator) { }
00245       template<class U>
00246         allocator_adaptor(allocator_adaptor<U, CharAlloc, internal LIBCWD_COMMA_INSTANCE> const& a) :
00247             M_char_allocator(a.M_char_allocator) { }
00248       template<class T2, class CharAlloc2, pool_nt internal2 LIBCWD_DEBUGDEBUG_COMMA(int instance2)>
00249         friend class allocator_adaptor;
00250       ~allocator_adaptor() throw() { }
00251 
00252       // Return maximum number of elements that can be allocated.
00253       size_type max_size(void) const { return M_char_allocator.max_size() / sizeof(T); }
00254 
00255       // Allocate but don't initialize num elements of type T.
00256       pointer allocate(size_type num);
00257       pointer allocate(size_type num, void const* hint);
00258 
00259       // Deallocate storage p of deleted elements.
00260       void deallocate(pointer p, size_type num);
00261 
00262       // Initialize elements of allocated storage p with value value.
00263       void construct(pointer p, T const& value) { new ((void*)p) T(value); }
00264 
00265       // Destroy elements of initialized storage p.
00266       void destroy(pointer p) { p->~T(); }
00267 
00268 #if CWDEBUG_DEBUG || CWDEBUG_DEBUGM
00269     private:
00270       static void sanity_check(void);
00271 #endif
00272 
00273       template <class T1, class CharAlloc1, pool_nt internal1 LIBCWD_DEBUGDEBUG_COMMA(int inst1),
00274                 class T2, class CharAlloc2, pool_nt internal2 LIBCWD_DEBUGDEBUG_COMMA(int inst2)>
00275         friend inline
00276         bool operator==(allocator_adaptor<T1, CharAlloc1, internal1 LIBCWD_DEBUGDEBUG_COMMA(inst1)> const& a1,
00277                         allocator_adaptor<T2, CharAlloc2, internal2 LIBCWD_DEBUGDEBUG_COMMA(inst2)> const& a2);
00278       template <class T1, class CharAlloc1, pool_nt internal1 LIBCWD_DEBUGDEBUG_COMMA(int inst1),
00279                 class T2, class CharAlloc2, pool_nt internal2 LIBCWD_DEBUGDEBUG_COMMA(int inst2)>
00280         friend inline
00281         bool operator!=(allocator_adaptor<T1, CharAlloc1, internal1 LIBCWD_DEBUGDEBUG_COMMA(inst1)> const& a1,
00282                         allocator_adaptor<T2, CharAlloc2, internal2 LIBCWD_DEBUGDEBUG_COMMA(inst2)> const& a2);
00283     };
00284 
00285 #if LIBCWD_THREAD_SAFE
00286 // We normally would be able to use the default allocator, but... libcwd functions can
00287 // at all times be called from malloc which might be called from std::allocator with its
00288 // lock set.  Therefore we also use a separate allocator pool for the userspace, in the
00289 // threaded case.
00290 #define LIBCWD_CHARALLOCATOR_USERSPACE(instance) ::libcwd::_private_::                          \
00291         allocator_adaptor<char,                                                                 \
00292                           CharPoolAlloc<true, userspace_instance>,                              \
00293                           userspace_pool                                                        \
00294                           LIBCWD_DEBUGDEBUG_COMMA(::libcwd::_private_::instance)>
00295 #endif
00296 
00297 // Both, multi_threaded_internal_instance and memblk_map_instance use also locks for
00298 // the allocator pool itself because they (the memory pools) are being shared between
00299 // threads from within critical areas with different mutexes.
00300 // Other instances (> 0) are supposed to only use the allocator instance from within
00301 // the critical area of the corresponding mutex_tct<instance>, and thus only by one
00302 // thread at a time.
00303 #if LIBCWD_THREAD_SAFE
00304 #define LIBCWD_ALLOCATOR_POOL_NEEDS_LOCK(instance)                                              \
00305                                 ::libcwd::_private_::instance ==                                \
00306                                 ::libcwd::_private_::multi_threaded_internal_instance ||        \
00307                                 ::libcwd::_private_::instance ==                                \
00308                                 ::libcwd::_private_::memblk_map_instance
00309 #else // !LIBCWD_THREAD_SAFE
00310 #define LIBCWD_ALLOCATOR_POOL_NEEDS_LOCK(instance) false
00311 #endif // !LIBCWD_THREAD_SAFE
00312 
00313 #define LIBCWD_CHARALLOCATOR_INTERNAL(instance) ::libcwd::_private_::                   \
00314         allocator_adaptor<char,                                                                 \
00315                           CharPoolAlloc<LIBCWD_ALLOCATOR_POOL_NEEDS_LOCK(instance),             \
00316                                         ::libcwd::_private_::instance >,                        \
00317                           internal_pool                                                         \
00318                           LIBCWD_DEBUGDEBUG_COMMA(::libcwd::_private_::instance)>
00319 
00320 #define LIBCWD_CHARALLOCATOR_AUTO_INTERNAL(instance) ::libcwd::_private_::              \
00321         allocator_adaptor<char,                                                                 \
00322                           CharPoolAlloc<LIBCWD_ALLOCATOR_POOL_NEEDS_LOCK(instance),             \
00323                                         ::libcwd::_private_::instance >,                        \
00324                           auto_internal_pool                                                    \
00325                           LIBCWD_DEBUGDEBUG_COMMA(::libcwd::_private_::instance)>
00326 
00327 #if LIBCWD_THREAD_SAFE
00328 // Our allocator adaptor for the Non-Shared internal cases: Single Threaded
00329 // (inst = single_threaded_internal_instance) or inside the critical area of the corresponding
00330 // libcwd mutex instance.
00331 #define LIBCWD_NS_INTERNAL_ALLOCATOR(instance)  LIBCWD_CHARALLOCATOR_INTERNAL(instance)
00332 #else // !LIBCWD_THREAD_SAFE
00333 // In a single threaded application, the Non-Shared case is equivalent to the Single Threaded case.
00334 #define LIBCWD_NS_INTERNAL_ALLOCATOR(instance)  LIBCWD_CHARALLOCATOR_INTERNAL(single_threaded_internal_instance)
00335 #endif // !LIBCWD_THREAD_SAFE
00336 
00337 #if LIBCWD_THREAD_SAFE
00338 // LIBCWD_MT_*_ALLOCATOR uses a different allocator than the normal default allocator of libstdc++
00339 // in the case of multi-threading because it can be that the allocator mutex is locked, which would
00340 // result in a deadlock if we try to use it again here.
00341 #define LIBCWD_MT_USERSPACE_ALLOCATOR           LIBCWD_CHARALLOCATOR_USERSPACE(userspace_instance)
00342 #define LIBCWD_MT_INTERNAL_ALLOCATOR            LIBCWD_CHARALLOCATOR_INTERNAL(multi_threaded_internal_instance)
00343 #define LIBCWD_MT_AUTO_INTERNAL_ALLOCATOR       LIBCWD_CHARALLOCATOR_AUTO_INTERNAL(multi_threaded_internal_instance)
00344 #else // !LIBCWD_THREAD_SAFE
00345 // LIBCWD_MT_*_ALLOCATOR uses the normal default allocator of libstdc++-v3 (alloc) using locking
00346 // itself.  The userspace allocator shares it memory pool with everything else (that uses this
00347 // allocator, which is most of the (userspace) STL).
00348 #define LIBCWD_MT_USERSPACE_ALLOCATOR           std::allocator<char>
00349 #define LIBCWD_MT_INTERNAL_ALLOCATOR            LIBCWD_CHARALLOCATOR_INTERNAL(single_threaded_internal_instance)
00350 #define LIBCWD_MT_AUTO_INTERNAL_ALLOCATOR       LIBCWD_CHARALLOCATOR_AUTO_INTERNAL(single_threaded_internal_instance)
00351 #endif // !LIBCWD_THREAD_SAFE
00352 
00353 //---------------------------------------------------------------------------------------------------
00354 // Internal allocator types.
00355 
00356 // This allocator is used in critical areas that are already locked by memblk_map_instance.
00357 typedef LIBCWD_NS_INTERNAL_ALLOCATOR(memblk_map_instance) memblk_map_allocator;
00358 
00359 // This allocator is used in critical areas that are already locked by object_files_instance.
00360 typedef LIBCWD_NS_INTERNAL_ALLOCATOR(object_files_instance) object_files_allocator;
00361 
00362 // This general allocator can be used outside libcwd-specific critical areas,
00363 // but inside a set_alloc_checking_off() .. set_alloc_checking_on() pair.
00364 typedef LIBCWD_MT_INTERNAL_ALLOCATOR internal_allocator;
00365 
00366 // This general allocator can be used outside libcwd-specific critical areas,
00367 // in "user space" but that will cause internal memory to be allocated.
00368 typedef LIBCWD_MT_AUTO_INTERNAL_ALLOCATOR auto_internal_allocator;
00369 
00370 //---------------------------------------------------------------------------------------------------
00371 // User space allocator type.
00372 
00373 // This general allocator can be used outside libcwd-specific critical areas.
00374 typedef LIBCWD_MT_USERSPACE_ALLOCATOR userspace_allocator;
00375 
00376   } // namespace _private_
00377 } // namespace libcwd
00378  
00379 #endif // CWDEBUG_ALLOC
00380 #endif // LIBCWD_PRIVATE_ALLOCATOR_H
00381 
Copyright © 2001 - 2004 Carlo Wood.  All rights reserved.