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

/usr/src/libcwd/libcwd/include/libcwd/private_allocator.h

Go to the documentation of this file.
00001 // $Header: /cvsroot/libcwd/libcwd/include/libcwd/private_allocator.h,v 1.7 2004/07/15 10:14:34 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 
00056    There are five different allocators in use by libcwd:
00057 
00058 Multi-threaded case:
00059 
00060    Allocator name               | internal | Pool instance                      | Needs lock
00061    ----------------------------------------------------------------------------------------------------
00062    memblk_map_allocator         | yes      | memblk_map_instance                | no (memblk_map_instance critical area)
00063    object_files_allocator       | yes      | object_files_instance              | no (object_files_instance critical area)
00064    internal_allocator           | yes      | multi_threaded_internal_instance   | yes
00065    auto_internal_allocator      | auto     | multi_threaded_internal_instance   | yes
00066    userspace_allocator          | no       | userspace_instance                 | yes
00067 
00068 Single-threaded case:
00069 
00070    Allocator name               | internal | Pool instance                      | Needs lock
00071    ----------------------------------------------------------------------------------------------------
00072    memblk_map_allocator         | yes      | single_threaded_internal_instance  | no
00073    object_files_allocator       | yes      | single_threaded_internal_instance  | no
00074    internal_allocator           | yes      | single_threaded_internal_instance  | no
00075    auto_internal_allocator      | auto     | single_threaded_internal_instance  | no
00076    userspace_allocator          | no       | std::alloc                         | -
00077 
00078 */
00079 
00080 #if __GNUC_MINOR__ >= 4
00081 #include <ext/pool_allocator.h>         // __gnu_cxx::__pool_alloc
00082 #endif
00083 
00084 namespace libcwd {
00085   namespace _private_ {
00086 
00087 // This is a random number in the hope nobody else uses it.
00088 int const random_salt = 327665;
00089 
00090 #if __GNUC_MINOR__ < 4
00091 template<bool needs_lock, int pool_instance>
00092   struct CharPoolAlloc : public std::__default_alloc_template<needs_lock, random_salt + pool_instance> {
00093     typedef char* pointer;
00094   };
00095 #elif __GNUC_MINOR__ == 4 && __GNUC_PATCHLEVEL__ == 0
00096 template<bool needs_lock, int pool_instance>
00097   struct CharPoolAlloc : public __gnu_cxx::__pool_alloc<needs_lock, random_salt + pool_instance> {
00098     typedef char* pointer;
00099   };
00100 #else
00101 template<int pool_instance>
00102   struct char_wrapper {
00103     char c;
00104   };
00105 // gcc 3.4.1 and higher always use a lock, in the threaded case.
00106 template<bool needs_lock, int pool_instance>
00107   class CharPoolAlloc : public __gnu_cxx::__pool_alloc<char_wrapper<pool_instance> > { };
00108 #endif
00109 
00110 // Dummy mutex instance numbers, these must be negative.
00111 int const multi_threaded_internal_instance = -1;
00112 int const single_threaded_internal_instance = -2;
00113 int const userspace_instance = -3;
00114 
00115 // Convenience macros.
00116 #if CWDEBUG_DEBUG
00117 #define LIBCWD_COMMA_INT_INSTANCE , int instance
00118 #define LIBCWD_COMMA_INSTANCE , instance
00119 #define LIBCWD_DEBUGDEBUG_COMMA(x) , x
00120 #else
00121 #define LIBCWD_COMMA_INT_INSTANCE
00122 #define LIBCWD_COMMA_INSTANCE
00123 #define LIBCWD_DEBUGDEBUG_COMMA(x)
00124 #endif
00125 
00126 enum pool_nt {
00127   userspace_pool,
00128   internal_pool,
00129   auto_internal_pool
00130 };
00131 
00132 // This wrapper adds sanity checks to the allocator use (like testing if
00133 // 'internal' allocators are indeed only used while in internal mode, and
00134 // critical area allocators are only used when the related lock is indeed
00135 // locked etc.
00136 template<typename T, class CharAlloc, pool_nt internal LIBCWD_COMMA_INT_INSTANCE>
00137     class allocator_adaptor {
00138     private:
00139       // The underlying allocator.
00140       CharAlloc M_char_allocator;
00141 
00142     public:
00143       // Type definitions.
00144       typedef T         value_type;
00145       typedef size_t    size_type;
00146       typedef ptrdiff_t difference_type;
00147       typedef T*                pointer;
00148       typedef T const*  const_pointer;
00149       typedef T&                reference;
00150       typedef T const&  const_reference;
00151 
00152       // Rebind allocator to type U.
00153       template <class U>
00154         struct rebind {
00155           typedef allocator_adaptor<U, CharAlloc, internal LIBCWD_COMMA_INSTANCE> other;
00156         };
00157 
00158       // Return address of values.
00159       pointer address(reference value) const { return &value; }
00160       const_pointer address(const_reference value) const { return &value; }
00161 
00162       // Constructors and destructor.
00163       allocator_adaptor(void) throw() { }
00164       allocator_adaptor(allocator_adaptor const& a) : M_char_allocator(a.M_char_allocator) { }
00165       template<class U>
00166         allocator_adaptor(allocator_adaptor<U, CharAlloc, internal LIBCWD_COMMA_INSTANCE> const& a) :
00167             M_char_allocator(a.M_char_allocator) { }
00168       template<class T2, class CharAlloc2, pool_nt internal2 LIBCWD_DEBUGDEBUG_COMMA(int instance2)>
00169         friend class allocator_adaptor;
00170       ~allocator_adaptor() throw() { }
00171 
00172       // Return maximum number of elements that can be allocated.
00173       size_type max_size(void) const { return M_char_allocator.max_size() / sizeof(T); }
00174 
00175       // Allocate but don't initialize num elements of type T.
00176       pointer allocate(size_type num);
00177       pointer allocate(size_type num, void const* hint);
00178 
00179       // Deallocate storage p of deleted elements.
00180       void deallocate(pointer p, size_type num);
00181 
00182       // Initialize elements of allocated storage p with value value.
00183       void construct(pointer p, T const& value) { new ((void*)p) T(value); }
00184 
00185       // Destroy elements of initialized storage p.
00186       void destroy(pointer p) { p->~T(); }
00187 
00188 #if CWDEBUG_DEBUG || CWDEBUG_DEBUGM
00189     private:
00190       static void sanity_check(void);
00191 #endif
00192 
00193       template <class T1, class CharAlloc1, pool_nt internal1 LIBCWD_DEBUGDEBUG_COMMA(int inst1),
00194                 class T2, class CharAlloc2, pool_nt internal2 LIBCWD_DEBUGDEBUG_COMMA(int inst2)>
00195         friend inline
00196         bool operator==(allocator_adaptor<T1, CharAlloc1, internal1 LIBCWD_DEBUGDEBUG_COMMA(inst1)> const& a1,
00197                         allocator_adaptor<T2, CharAlloc2, internal2 LIBCWD_DEBUGDEBUG_COMMA(inst2)> const& a2);
00198       template <class T1, class CharAlloc1, pool_nt internal1 LIBCWD_DEBUGDEBUG_COMMA(int inst1),
00199                 class T2, class CharAlloc2, pool_nt internal2 LIBCWD_DEBUGDEBUG_COMMA(int inst2)>
00200         friend inline
00201         bool operator!=(allocator_adaptor<T1, CharAlloc1, internal1 LIBCWD_DEBUGDEBUG_COMMA(inst1)> const& a1,
00202                         allocator_adaptor<T2, CharAlloc2, internal2 LIBCWD_DEBUGDEBUG_COMMA(inst2)> const& a2);
00203     };
00204 
00205 #if LIBCWD_THREAD_SAFE
00206 // We normally would be able to use the default allocator, but... libcwd functions can
00207 // at all times be called from malloc which might be called from std::allocator with its
00208 // lock set.  Therefore we also use a seperate allocator pool for the userspace, in the
00209 // threaded case.
00210 #define LIBCWD_CHARALLOCATOR_USERSPACE(instance) ::libcwd::_private_::                  \
00211         allocator_adaptor<char,                                                                 \
00212                           CharPoolAlloc<true, userspace_instance>,                              \
00213                           userspace_pool                                                        \
00214                           LIBCWD_DEBUGDEBUG_COMMA(::libcwd::_private_::instance)>
00215 #endif
00216 
00217 // Both, multi_threaded_internal_instance and memblk_map_instance use also locks for
00218 // the allocator pool itself because they (the memory pools) are being shared between
00219 // threads from within critical areas with different mutexes.
00220 // Other instances (> 0) are supposed to only use the allocator instance from within
00221 // the critical area of the corresponding mutex_tct<instance>, and thus only by one
00222 // thread at a time.
00223 #if LIBCWD_THREAD_SAFE
00224 #define LIBCWD_ALLOCATOR_POOL_NEEDS_LOCK(instance)                                              \
00225                                 ::libcwd::_private_::instance ==                                \
00226                                 ::libcwd::_private_::multi_threaded_internal_instance ||        \
00227                                 ::libcwd::_private_::instance ==                                \
00228                                 ::libcwd::_private_::memblk_map_instance
00229 #else // !LIBCWD_THREAD_SAFE
00230 #define LIBCWD_ALLOCATOR_POOL_NEEDS_LOCK(instance) false
00231 #endif // !LIBCWD_THREAD_SAFE
00232 
00233 #define LIBCWD_CHARALLOCATOR_INTERNAL(instance) ::libcwd::_private_::                   \
00234         allocator_adaptor<char,                                                                 \
00235                           CharPoolAlloc<LIBCWD_ALLOCATOR_POOL_NEEDS_LOCK(instance),             \
00236                                         ::libcwd::_private_::instance >,                        \
00237                           internal_pool                                                         \
00238                           LIBCWD_DEBUGDEBUG_COMMA(::libcwd::_private_::instance)>
00239 
00240 #define LIBCWD_CHARALLOCATOR_AUTO_INTERNAL(instance) ::libcwd::_private_::              \
00241         allocator_adaptor<char,                                                                 \
00242                           CharPoolAlloc<LIBCWD_ALLOCATOR_POOL_NEEDS_LOCK(instance),             \
00243                                         ::libcwd::_private_::instance >,                        \
00244                           auto_internal_pool                                                    \
00245                           LIBCWD_DEBUGDEBUG_COMMA(::libcwd::_private_::instance)>
00246 
00247 #if LIBCWD_THREAD_SAFE
00248 // Our allocator adaptor for the Non-Shared internal cases: Single Threaded
00249 // (inst = single_threaded_internal_instance) or inside the critical area of the corresponding
00250 // libcwd mutex instance.
00251 #define LIBCWD_NS_INTERNAL_ALLOCATOR(instance)  LIBCWD_CHARALLOCATOR_INTERNAL(instance)
00252 #else // !LIBCWD_THREAD_SAFE
00253 // In a single threaded application, the Non-Shared case is equivalent to the Single Threaded case.
00254 #define LIBCWD_NS_INTERNAL_ALLOCATOR(instance)  LIBCWD_CHARALLOCATOR_INTERNAL(single_threaded_internal_instance)
00255 #endif // !LIBCWD_THREAD_SAFE
00256 
00257 #if LIBCWD_THREAD_SAFE
00258 // LIBCWD_MT_*_ALLOCATOR uses a different allocator than the normal default allocator of libstdc++
00259 // in the case of multi-threading because it can be that the allocator mutex is locked, which would
00260 // result in a deadlock if we try to use it again here.
00261 #define LIBCWD_MT_USERSPACE_ALLOCATOR           LIBCWD_CHARALLOCATOR_USERSPACE(userspace_instance)
00262 #define LIBCWD_MT_INTERNAL_ALLOCATOR            LIBCWD_CHARALLOCATOR_INTERNAL(multi_threaded_internal_instance)
00263 #define LIBCWD_MT_AUTO_INTERNAL_ALLOCATOR       LIBCWD_CHARALLOCATOR_AUTO_INTERNAL(multi_threaded_internal_instance)
00264 #else // !LIBCWD_THREAD_SAFE
00265 // LIBCWD_MT_*_ALLOCATOR uses the normal default allocator of libstdc++-v3 (alloc) using locking
00266 // itself.  The userspace allocator shares it memory pool with everything else (that uses this
00267 // allocator, which is most of the (userspace) STL).
00268 #define LIBCWD_MT_USERSPACE_ALLOCATOR           std::allocator<char>
00269 #define LIBCWD_MT_INTERNAL_ALLOCATOR            LIBCWD_CHARALLOCATOR_INTERNAL(single_threaded_internal_instance)
00270 #define LIBCWD_MT_AUTO_INTERNAL_ALLOCATOR       LIBCWD_CHARALLOCATOR_AUTO_INTERNAL(single_threaded_internal_instance)
00271 #endif // !LIBCWD_THREAD_SAFE
00272 
00273 //---------------------------------------------------------------------------------------------------
00274 // Internal allocator types.
00275 
00276 // This allocator is used in critical areas that are already locked by memblk_map_instance.
00277 typedef LIBCWD_NS_INTERNAL_ALLOCATOR(memblk_map_instance) memblk_map_allocator;
00278 
00279 // This allocator is used in critical areas that are already locked by object_files_instance.
00280 typedef LIBCWD_NS_INTERNAL_ALLOCATOR(object_files_instance) object_files_allocator;
00281 
00282 // This general allocator can be used outside libcwd-specific critical areas,
00283 // but inside a set_alloc_checking_off() .. set_alloc_checking_on() pair.
00284 typedef LIBCWD_MT_INTERNAL_ALLOCATOR internal_allocator;
00285 
00286 // This general allocator can be used outside libcwd-specific critical areas,
00287 // in "user space" but that will cause internal memory to be allocated.
00288 typedef LIBCWD_MT_AUTO_INTERNAL_ALLOCATOR auto_internal_allocator;
00289 
00290 //---------------------------------------------------------------------------------------------------
00291 // User space allocator type.
00292 
00293 // This general allocator can be used outside libcwd-specific critical areas.
00294 typedef LIBCWD_MT_USERSPACE_ALLOCATOR userspace_allocator;
00295 
00296   } // namespace _private_
00297 } // namespace libcwd
00298  
00299 #endif // CWDEBUG_ALLOC
00300 #endif // LIBCWD_PRIVATE_ALLOCATOR_H
00301 
Copyright © 2001 - 2004 Carlo Wood.  All rights reserved.