build/stlport/src/allocators.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/build/stlport/src/allocators.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1121 @@
     1.4 +/*
     1.5 + *
     1.6 + * Copyright (c) 1996,1997
     1.7 + * Silicon Graphics Computer Systems, Inc.
     1.8 + *
     1.9 + * Copyright (c) 1997
    1.10 + * Moscow Center for SPARC Technology
    1.11 + *
    1.12 + * Copyright (c) 1999
    1.13 + * Boris Fomitchev
    1.14 + *
    1.15 + * This material is provided "as is", with absolutely no warranty expressed
    1.16 + * or implied. Any use is at your own risk.
    1.17 + *
    1.18 + * Permission to use or copy this software for any purpose is hereby granted
    1.19 + * without fee, provided the above notices are retained on all copies.
    1.20 + * Permission to modify the code and to distribute modified code is granted,
    1.21 + * provided the above notices are retained, and a notice that the code was
    1.22 + * modified is included with the above copyright notice.
    1.23 + *
    1.24 + */
    1.25 +
    1.26 +#include "stlport_prefix.h"
    1.27 +
    1.28 +#include <memory>
    1.29 +
    1.30 +#if defined (__GNUC__) && (defined (__CYGWIN__) || defined (__MINGW32__))
    1.31 +#  include <malloc.h>
    1.32 +#endif
    1.33 +
    1.34 +#if defined (_STLP_PTHREADS) && !defined (_STLP_NO_THREADS)
    1.35 +#  include <pthread_alloc>
    1.36 +#  include <cerrno>
    1.37 +#endif
    1.38 +
    1.39 +#include <stl/_threads.h>
    1.40 +
    1.41 +#include "lock_free_slist.h"
    1.42 +
    1.43 +#if defined (__WATCOMC__)
    1.44 +#  pragma warning 13 9
    1.45 +#  pragma warning 367 9
    1.46 +#  pragma warning 368 9
    1.47 +#endif
    1.48 +
    1.49 +#if defined (_STLP_SGI_THREADS)
    1.50 +  // We test whether threads are in use before locking.
    1.51 +  // Perhaps this should be moved into stl_threads.h, but that
    1.52 +  // probably makes it harder to avoid the procedure call when
    1.53 +  // it isn't needed.
    1.54 +extern "C" {
    1.55 +  extern int __us_rsthread_malloc;
    1.56 +}
    1.57 +#endif
    1.58 +
    1.59 +// Specialised debug form of new operator which does not provide "false"
    1.60 +// memory leaks when run with debug CRT libraries.
    1.61 +#if defined (_STLP_MSVC) && (_STLP_MSVC >= 1020 && defined (_STLP_DEBUG_ALLOC)) && !defined (_STLP_WCE)
    1.62 +#  include <crtdbg.h>
    1.63 +inline char* __stlp_new_chunk(size_t __bytes) {
    1.64 +  void *__chunk = _STLP_CHECK_NULL_ALLOC(::operator new(__bytes, __FILE__, __LINE__));
    1.65 +  return __STATIC_CAST(char*, __chunk);
    1.66 +}
    1.67 +inline void __stlp_delete_chunck(void* __p) { ::operator delete(__p, __FILE__, __LINE__); }
    1.68 +#else
    1.69 +#  ifdef _STLP_NODE_ALLOC_USE_MALLOC
    1.70 +#    include <cstdlib>
    1.71 +inline char* __stlp_new_chunk(size_t __bytes) {
    1.72 +  // do not use _STLP_CHECK_NULL_ALLOC, this macro is dedicated to new operator.
    1.73 +  void *__chunk = _STLP_VENDOR_CSTD::malloc(__bytes);
    1.74 +  if (__chunk == 0) {
    1.75 +    _STLP_THROW_BAD_ALLOC;
    1.76 +  }
    1.77 +  return __STATIC_CAST(char*, __chunk);
    1.78 +}
    1.79 +inline void __stlp_delete_chunck(void* __p) { _STLP_VENDOR_CSTD::free(__p); }
    1.80 +#  else
    1.81 +inline char* __stlp_new_chunk(size_t __bytes)
    1.82 +{ return __STATIC_CAST(char*, _STLP_STD::__stl_new(__bytes)); }
    1.83 +inline void __stlp_delete_chunck(void* __p) { _STLP_STD::__stl_delete(__p); }
    1.84 +#  endif
    1.85 +#endif
    1.86 +
    1.87 +/* This is an additional atomic operations to the ones already defined in
    1.88 + * stl/_threads.h, platform should try to support it to improve performance.
    1.89 + * __add_atomic_t _STLP_ATOMIC_ADD(volatile __add_atomic_t* __target, __add_atomic_t __val) :
    1.90 + * does *__target = *__target + __val and returns the old *__target value */
    1.91 +typedef long __add_atomic_t;
    1.92 +typedef unsigned long __uadd_atomic_t;
    1.93 +
    1.94 +#if defined (__GNUC__) && defined (__i386__)
    1.95 +inline long _STLP_atomic_add_gcc_x86(long volatile* p, long addend) {
    1.96 +  long result;
    1.97 +  __asm__ __volatile__
    1.98 +    ("lock; xaddl %1, %0;"
    1.99 +    :"=m" (*p), "=r" (result)
   1.100 +    :"m"  (*p), "1"  (addend)
   1.101 +    :"cc");
   1.102 + return result + addend;
   1.103 +}
   1.104 +#  define _STLP_ATOMIC_ADD(__dst, __val)  _STLP_atomic_add_gcc_x86(__dst, __val)
   1.105 +#elif defined (_STLP_WIN32THREADS)
   1.106 +// The Win32 API function InterlockedExchangeAdd is not available on Windows 95.
   1.107 +#  if !defined (_STLP_WIN95_LIKE)
   1.108 +#    if defined (_STLP_NEW_PLATFORM_SDK)
   1.109 +#      define _STLP_ATOMIC_ADD(__dst, __val) InterlockedExchangeAdd(__dst, __val)
   1.110 +#    else
   1.111 +#      define _STLP_ATOMIC_ADD(__dst, __val) InterlockedExchangeAdd(__CONST_CAST(__add_atomic_t*, __dst), __val)
   1.112 +#    endif
   1.113 +#  endif
   1.114 +#endif
   1.115 +
   1.116 +#if defined (__OS400__)
   1.117 +// dums 02/05/2007: is it really necessary ?
   1.118 +enum { _ALIGN = 16, _ALIGN_SHIFT = 4 };
   1.119 +#else
   1.120 +enum { _ALIGN = 2 * sizeof(void*), _ALIGN_SHIFT = 2 + sizeof(void*) / 4 };
   1.121 +#endif
   1.122 +
   1.123 +#define _S_FREELIST_INDEX(__bytes) ((__bytes - size_t(1)) >> (int)_ALIGN_SHIFT)
   1.124 +
   1.125 +_STLP_BEGIN_NAMESPACE
   1.126 +
   1.127 +// malloc_alloc out-of-memory handling
   1.128 +static __oom_handler_type __oom_handler = __STATIC_CAST(__oom_handler_type, 0);
   1.129 +
   1.130 +#ifdef _STLP_THREADS
   1.131 +_STLP_mutex __oom_handler_lock;
   1.132 +#endif
   1.133 +
   1.134 +void* _STLP_CALL __malloc_alloc::allocate(size_t __n)
   1.135 +{
   1.136 +  void *__result = malloc(__n);
   1.137 +  if ( 0 == __result ) {
   1.138 +    __oom_handler_type __my_malloc_handler;
   1.139 +
   1.140 +    for (;;) {
   1.141 +      {
   1.142 +#ifdef _STLP_THREADS
   1.143 +        _STLP_auto_lock _l( __oom_handler_lock );
   1.144 +#endif
   1.145 +        __my_malloc_handler = __oom_handler;
   1.146 +      }
   1.147 +      if ( 0 == __my_malloc_handler) {
   1.148 +        _STLP_THROW_BAD_ALLOC;
   1.149 +      }
   1.150 +      (*__my_malloc_handler)();
   1.151 +      __result = malloc(__n);
   1.152 +      if ( __result )
   1.153 +        return __result;
   1.154 +    }
   1.155 +  }
   1.156 +  return __result;
   1.157 +}
   1.158 +
   1.159 +__oom_handler_type _STLP_CALL __malloc_alloc::set_malloc_handler(__oom_handler_type __f)
   1.160 +{
   1.161 +#ifdef _STLP_THREADS
   1.162 +  _STLP_auto_lock _l( __oom_handler_lock );
   1.163 +#endif
   1.164 +  __oom_handler_type __old = __oom_handler;
   1.165 +  __oom_handler = __f;
   1.166 +  return __old;
   1.167 +}
   1.168 +
   1.169 +// *******************************************************
   1.170 +// Default node allocator.
   1.171 +// With a reasonable compiler, this should be roughly as fast as the
   1.172 +// original STL class-specific allocators, but with less fragmentation.
   1.173 +//
   1.174 +// Important implementation properties:
   1.175 +// 1. If the client request an object of size > _MAX_BYTES, the resulting
   1.176 +//    object will be obtained directly from malloc.
   1.177 +// 2. In all other cases, we allocate an object of size exactly
   1.178 +//    _S_round_up(requested_size).  Thus the client has enough size
   1.179 +//    information that we can return the object to the proper free list
   1.180 +//    without permanently losing part of the object.
   1.181 +//
   1.182 +
   1.183 +#define _STLP_NFREELISTS 16
   1.184 +
   1.185 +#if defined (_STLP_LEAKS_PEDANTIC) && defined (_STLP_USE_DYNAMIC_LIB)
   1.186 +/*
   1.187 + * We can only do cleanup of the node allocator memory pool if we are
   1.188 + * sure that the STLport library is used as a shared one as it guaranties
   1.189 + * the unicity of the node allocator instance. Without that guaranty node
   1.190 + * allocator instances might exchange memory blocks making the implementation
   1.191 + * of a cleaning process much more complicated.
   1.192 + */
   1.193 +#  define _STLP_DO_CLEAN_NODE_ALLOC
   1.194 +#endif
   1.195 +
   1.196 +/* When STLport is used without multi threaded safety we use the node allocator
   1.197 + * implementation with locks as locks becomes no-op. The lock free implementation
   1.198 + * always use system specific atomic operations which are slower than 'normal'
   1.199 + * ones.
   1.200 + */
   1.201 +#if defined (_STLP_THREADS) && \
   1.202 +    defined (_STLP_HAS_ATOMIC_FREELIST) && defined (_STLP_ATOMIC_ADD)
   1.203 +/*
   1.204 + * We have an implementation of the atomic freelist (_STLP_atomic_freelist)
   1.205 + * for this architecture and compiler.  That means we can use the non-blocking
   1.206 + * implementation of the node-allocation engine.*/
   1.207 +#  define _STLP_USE_LOCK_FREE_IMPLEMENTATION
   1.208 +#endif
   1.209 +
   1.210 +#if !defined (_STLP_USE_LOCK_FREE_IMPLEMENTATION)
   1.211 +#  if defined (_STLP_THREADS)
   1.212 +
   1.213 +class _Node_Alloc_Lock {
   1.214 +  static _STLP_STATIC_MUTEX& _S_Mutex() {
   1.215 +    static _STLP_STATIC_MUTEX mutex _STLP_MUTEX_INITIALIZER;
   1.216 +    return mutex;
   1.217 +  }
   1.218 +public:
   1.219 +  _Node_Alloc_Lock() {
   1.220 +#    if defined (_STLP_SGI_THREADS)
   1.221 +    if (__us_rsthread_malloc)
   1.222 +#    endif
   1.223 +      _S_Mutex()._M_acquire_lock();
   1.224 +  }
   1.225 +
   1.226 +  ~_Node_Alloc_Lock() {
   1.227 +#    if defined (_STLP_SGI_THREADS)
   1.228 +    if (__us_rsthread_malloc)
   1.229 +#    endif
   1.230 +      _S_Mutex()._M_release_lock();
   1.231 +  }
   1.232 +};
   1.233 +
   1.234 +#  else
   1.235 +
   1.236 +class _Node_Alloc_Lock {
   1.237 +public:
   1.238 +  _Node_Alloc_Lock() { }
   1.239 +  ~_Node_Alloc_Lock() { }
   1.240 +};
   1.241 +
   1.242 +#  endif
   1.243 +
   1.244 +struct _Node_alloc_obj {
   1.245 +  _Node_alloc_obj * _M_next;
   1.246 +};
   1.247 +#endif
   1.248 +
   1.249 +class __node_alloc_impl {
   1.250 +  static inline size_t _STLP_CALL _S_round_up(size_t __bytes)
   1.251 +  { return (((__bytes) + (size_t)_ALIGN-1) & ~((size_t)_ALIGN - 1)); }
   1.252 +
   1.253 +#if defined (_STLP_USE_LOCK_FREE_IMPLEMENTATION)
   1.254 +  typedef _STLP_atomic_freelist::item   _Obj;
   1.255 +  typedef _STLP_atomic_freelist         _Freelist;
   1.256 +  typedef _STLP_atomic_freelist         _ChunkList;
   1.257 +
   1.258 +  // Header of blocks of memory that have been allocated as part of
   1.259 +  // a larger chunk but have not yet been chopped up into nodes.
   1.260 +  struct _FreeBlockHeader : public _STLP_atomic_freelist::item {
   1.261 +    char* _M_end;     // pointer to end of free memory
   1.262 +  };
   1.263 +#else
   1.264 +  typedef _Node_alloc_obj       _Obj;
   1.265 +  typedef _Obj* _STLP_VOLATILE  _Freelist;
   1.266 +  typedef _Obj*                 _ChunkList;
   1.267 +#endif
   1.268 +
   1.269 +private:
   1.270 +  // Returns an object of size __n, and optionally adds to size __n free list.
   1.271 +  static _Obj* _S_refill(size_t __n);
   1.272 +  // Allocates a chunk for nobjs of size __p_size.  nobjs may be reduced
   1.273 +  // if it is inconvenient to allocate the requested number.
   1.274 +  static char* _S_chunk_alloc(size_t __p_size, int& __nobjs);
   1.275 +  // Chunk allocation state.
   1.276 +  static _Freelist _S_free_list[_STLP_NFREELISTS];
   1.277 +  // Amount of total allocated memory
   1.278 +#if defined (_STLP_USE_LOCK_FREE_IMPLEMENTATION)
   1.279 +  static _STLP_VOLATILE __add_atomic_t _S_heap_size;
   1.280 +#else
   1.281 +  static size_t _S_heap_size;
   1.282 +#endif
   1.283 +
   1.284 +#if defined (_STLP_USE_LOCK_FREE_IMPLEMENTATION)
   1.285 +  // List of blocks of free memory
   1.286 +  static _STLP_atomic_freelist  _S_free_mem_blocks;
   1.287 +#else
   1.288 +  // Start of the current free memory buffer
   1.289 +  static char* _S_start_free;
   1.290 +  // End of the current free memory buffer
   1.291 +  static char* _S_end_free;
   1.292 +#endif
   1.293 +
   1.294 +#if defined (_STLP_DO_CLEAN_NODE_ALLOC)
   1.295 +public:
   1.296 +  // Methods to report alloc/dealloc calls to the counter system.
   1.297 +#  if defined (_STLP_USE_LOCK_FREE_IMPLEMENTATION)
   1.298 +  typedef _STLP_VOLATILE __stl_atomic_t _AllocCounter;
   1.299 +#  else
   1.300 +  typedef __stl_atomic_t _AllocCounter;
   1.301 +#  endif
   1.302 +  static _AllocCounter& _STLP_CALL _S_alloc_counter();
   1.303 +  static void _S_alloc_call();
   1.304 +  static void _S_dealloc_call();
   1.305 +
   1.306 +private:
   1.307 +  // Free all the allocated chuncks of memory
   1.308 +  static void _S_chunk_dealloc();
   1.309 +  // Beginning of the linked list of allocated chunks of memory
   1.310 +  static _ChunkList _S_chunks;
   1.311 +#endif /* _STLP_DO_CLEAN_NODE_ALLOC */
   1.312 +
   1.313 +public:
   1.314 +  /* __n must be > 0      */
   1.315 +  static void* _M_allocate(size_t& __n);
   1.316 +  /* __p may not be 0 */
   1.317 +  static void _M_deallocate(void *__p, size_t __n);
   1.318 +};
   1.319 +
   1.320 +#if !defined (_STLP_USE_LOCK_FREE_IMPLEMENTATION)
   1.321 +void* __node_alloc_impl::_M_allocate(size_t& __n) {
   1.322 +  __n = _S_round_up(__n);
   1.323 +  _Obj * _STLP_VOLATILE * __my_free_list = _S_free_list + _S_FREELIST_INDEX(__n);
   1.324 +  _Obj *__r;
   1.325 +
   1.326 +  // Acquire the lock here with a constructor call.
   1.327 +  // This ensures that it is released in exit or during stack
   1.328 +  // unwinding.
   1.329 +  _Node_Alloc_Lock __lock_instance;
   1.330 +
   1.331 +  if ( (__r  = *__my_free_list) != 0 ) {
   1.332 +    *__my_free_list = __r->_M_next;
   1.333 +  } else {
   1.334 +    __r = _S_refill(__n);
   1.335 +  }
   1.336 +#  if defined (_STLP_DO_CLEAN_NODE_ALLOC)
   1.337 +  _S_alloc_call();
   1.338 +#  endif
   1.339 +  // lock is released here
   1.340 +  return __r;
   1.341 +}
   1.342 +
   1.343 +void __node_alloc_impl::_M_deallocate(void *__p, size_t __n) {
   1.344 +  _Obj * _STLP_VOLATILE * __my_free_list = _S_free_list + _S_FREELIST_INDEX(__n);
   1.345 +  _Obj * __pobj = __STATIC_CAST(_Obj*, __p);
   1.346 +
   1.347 +  // acquire lock
   1.348 +  _Node_Alloc_Lock __lock_instance;
   1.349 +  __pobj->_M_next = *__my_free_list;
   1.350 +  *__my_free_list = __pobj;
   1.351 +
   1.352 +#  if defined (_STLP_DO_CLEAN_NODE_ALLOC)
   1.353 +  _S_dealloc_call();
   1.354 +#  endif
   1.355 +  // lock is released here
   1.356 +}
   1.357 +
   1.358 +#  if defined (_STLP_DO_CLEAN_NODE_ALLOC)
   1.359 +#    define _STLP_OFFSET sizeof(_Obj)
   1.360 +#  else
   1.361 +#    define _STLP_OFFSET 0
   1.362 +#  endif
   1.363 +
   1.364 +/* We allocate memory in large chunks in order to avoid fragmenting     */
   1.365 +/* the malloc heap too much.                                            */
   1.366 +/* We assume that size is properly aligned.                             */
   1.367 +/* We hold the allocation lock.                                         */
   1.368 +char* __node_alloc_impl::_S_chunk_alloc(size_t _p_size, int& __nobjs) {
   1.369 +  char* __result;
   1.370 +  size_t __total_bytes = _p_size * __nobjs;
   1.371 +  size_t __bytes_left = _S_end_free - _S_start_free;
   1.372 +
   1.373 +  if (__bytes_left > 0) {
   1.374 +    if (__bytes_left >= __total_bytes) {
   1.375 +      __result = _S_start_free;
   1.376 +      _S_start_free += __total_bytes;
   1.377 +      return __result;
   1.378 +    }
   1.379 +
   1.380 +    if (__bytes_left >= _p_size) {
   1.381 +      __nobjs = (int)(__bytes_left / _p_size);
   1.382 +      __total_bytes = _p_size * __nobjs;
   1.383 +      __result = _S_start_free;
   1.384 +      _S_start_free += __total_bytes;
   1.385 +      return __result;
   1.386 +    }
   1.387 +
   1.388 +    // Try to make use of the left-over piece.
   1.389 +    _Obj* _STLP_VOLATILE* __my_free_list = _S_free_list + _S_FREELIST_INDEX(__bytes_left);
   1.390 +    __REINTERPRET_CAST(_Obj*, _S_start_free)->_M_next = *__my_free_list;
   1.391 +    *__my_free_list = __REINTERPRET_CAST(_Obj*, _S_start_free);
   1.392 +    _S_start_free = _S_end_free = 0;
   1.393 +  }
   1.394 +
   1.395 +  size_t __bytes_to_get = 2 * __total_bytes + _S_round_up(_S_heap_size) + _STLP_OFFSET;
   1.396 +
   1.397 +  _STLP_TRY {
   1.398 +    _S_start_free = __stlp_new_chunk(__bytes_to_get);
   1.399 +  }
   1.400 +#if defined (_STLP_USE_EXCEPTIONS)
   1.401 +  catch (const _STLP_STD::bad_alloc&) {
   1.402 +    _Obj* _STLP_VOLATILE* __my_free_list;
   1.403 +    _Obj* __p;
   1.404 +    // Try to do with what we have.  That can't hurt.
   1.405 +    // We do not try smaller requests, since that tends
   1.406 +    // to result in disaster on multi-process machines.
   1.407 +    for (size_t __i = _p_size; __i <= (size_t)_MAX_BYTES; __i += (size_t)_ALIGN) {
   1.408 +      __my_free_list = _S_free_list + _S_FREELIST_INDEX(__i);
   1.409 +      __p = *__my_free_list;
   1.410 +      if (0 != __p) {
   1.411 +        *__my_free_list = __p -> _M_next;
   1.412 +        _S_start_free = __REINTERPRET_CAST(char*, __p);
   1.413 +        _S_end_free = _S_start_free + __i;
   1.414 +        return _S_chunk_alloc(_p_size, __nobjs);
   1.415 +        // Any leftover piece will eventually make it to the
   1.416 +        // right free list.
   1.417 +      }
   1.418 +    }
   1.419 +    __bytes_to_get = __total_bytes + _STLP_OFFSET;
   1.420 +    _S_start_free = __stlp_new_chunk(__bytes_to_get);
   1.421 +  }
   1.422 +#endif
   1.423 +
   1.424 +  _S_heap_size += __bytes_to_get >> 4;
   1.425 +#  if defined (_STLP_DO_CLEAN_NODE_ALLOC)
   1.426 +  __REINTERPRET_CAST(_Obj*, _S_start_free)->_M_next = _S_chunks;
   1.427 +  _S_chunks = __REINTERPRET_CAST(_Obj*, _S_start_free);
   1.428 +#  endif
   1.429 +  _S_end_free = _S_start_free + __bytes_to_get;
   1.430 +  _S_start_free += _STLP_OFFSET;
   1.431 +  return _S_chunk_alloc(_p_size, __nobjs);
   1.432 +}
   1.433 +
   1.434 +/* Returns an object of size __n, and optionally adds to size __n free list.*/
   1.435 +/* We assume that __n is properly aligned.                                  */
   1.436 +/* We hold the allocation lock.                                             */
   1.437 +_Node_alloc_obj* __node_alloc_impl::_S_refill(size_t __n) {
   1.438 +  int __nobjs = 20;
   1.439 +  char* __chunk = _S_chunk_alloc(__n, __nobjs);
   1.440 +
   1.441 +  if (1 == __nobjs) return __REINTERPRET_CAST(_Obj*, __chunk);
   1.442 +
   1.443 +  _Obj* _STLP_VOLATILE* __my_free_list = _S_free_list + _S_FREELIST_INDEX(__n);
   1.444 +  _Obj* __result;
   1.445 +  _Obj* __current_obj;
   1.446 +  _Obj* __next_obj;
   1.447 +
   1.448 +  /* Build free list in chunk */
   1.449 +  __result = __REINTERPRET_CAST(_Obj*, __chunk);
   1.450 +  *__my_free_list = __next_obj = __REINTERPRET_CAST(_Obj*, __chunk + __n);
   1.451 +  for (--__nobjs; --__nobjs; ) {
   1.452 +    __current_obj = __next_obj;
   1.453 +    __next_obj = __REINTERPRET_CAST(_Obj*, __REINTERPRET_CAST(char*, __next_obj) + __n);
   1.454 +    __current_obj->_M_next = __next_obj;
   1.455 +  }
   1.456 +  __next_obj->_M_next = 0;
   1.457 +  return __result;
   1.458 +}
   1.459 +
   1.460 +#  if defined (_STLP_DO_CLEAN_NODE_ALLOC)
   1.461 +void __node_alloc_impl::_S_alloc_call()
   1.462 +{ ++_S_alloc_counter(); }
   1.463 +
   1.464 +void __node_alloc_impl::_S_dealloc_call() {
   1.465 +  __stl_atomic_t &counter = _S_alloc_counter();
   1.466 +  if (--counter == 0)
   1.467 +  { _S_chunk_dealloc(); }
   1.468 +}
   1.469 +
   1.470 +/* We deallocate all the memory chunks      */
   1.471 +void __node_alloc_impl::_S_chunk_dealloc() {
   1.472 +  _Obj *__pcur = _S_chunks, *__pnext;
   1.473 +  while (__pcur != 0) {
   1.474 +    __pnext = __pcur->_M_next;
   1.475 +    __stlp_delete_chunck(__pcur);
   1.476 +    __pcur = __pnext;
   1.477 +  }
   1.478 +  _S_chunks = 0;
   1.479 +  _S_start_free = _S_end_free = 0;
   1.480 +  _S_heap_size = 0;
   1.481 +  memset(__REINTERPRET_CAST(char*, __CONST_CAST(_Obj**, &_S_free_list[0])), 0, _STLP_NFREELISTS * sizeof(_Obj*));
   1.482 +}
   1.483 +#  endif
   1.484 +
   1.485 +#else
   1.486 +
   1.487 +void* __node_alloc_impl::_M_allocate(size_t& __n) {
   1.488 +  __n = _S_round_up(__n);
   1.489 +  _Obj* __r = _S_free_list[_S_FREELIST_INDEX(__n)].pop();
   1.490 +  if (__r  == 0)
   1.491 +  { __r = _S_refill(__n); }
   1.492 +
   1.493 +#  if defined (_STLP_DO_CLEAN_NODE_ALLOC)
   1.494 +  _S_alloc_call();
   1.495 +#  endif
   1.496 +  return __r;
   1.497 +}
   1.498 +
   1.499 +void __node_alloc_impl::_M_deallocate(void *__p, size_t __n) {
   1.500 +  _S_free_list[_S_FREELIST_INDEX(__n)].push(__STATIC_CAST(_Obj*, __p));
   1.501 +
   1.502 +#  if defined (_STLP_DO_CLEAN_NODE_ALLOC)
   1.503 +  _S_dealloc_call();
   1.504 +#  endif
   1.505 +}
   1.506 +
   1.507 +/* Returns an object of size __n, and optionally adds additional ones to    */
   1.508 +/* freelist of objects of size __n.                                         */
   1.509 +/* We assume that __n is properly aligned.                                  */
   1.510 +__node_alloc_impl::_Obj* __node_alloc_impl::_S_refill(size_t __n) {
   1.511 +  int __nobjs = 20;
   1.512 +  char* __chunk = _S_chunk_alloc(__n, __nobjs);
   1.513 +
   1.514 +  if (__nobjs <= 1)
   1.515 +    return __REINTERPRET_CAST(_Obj*, __chunk);
   1.516 +
   1.517 +  // Push all new nodes (minus first one) onto freelist
   1.518 +  _Obj* __result   = __REINTERPRET_CAST(_Obj*, __chunk);
   1.519 +  _Obj* __cur_item = __result;
   1.520 +  _Freelist* __my_freelist = _S_free_list + _S_FREELIST_INDEX(__n);
   1.521 +  for (--__nobjs; __nobjs != 0; --__nobjs) {
   1.522 +    __cur_item  = __REINTERPRET_CAST(_Obj*, __REINTERPRET_CAST(char*, __cur_item) + __n);
   1.523 +    __my_freelist->push(__cur_item);
   1.524 +  }
   1.525 +  return __result;
   1.526 +}
   1.527 +
   1.528 +#  if defined (_STLP_DO_CLEAN_NODE_ALLOC)
   1.529 +#    define _STLP_OFFSET _ALIGN
   1.530 +#  else
   1.531 +#    define _STLP_OFFSET 0
   1.532 +#  endif
   1.533 +
   1.534 +/* We allocate memory in large chunks in order to avoid fragmenting     */
   1.535 +/* the malloc heap too much.                                            */
   1.536 +/* We assume that size is properly aligned.                             */
   1.537 +char* __node_alloc_impl::_S_chunk_alloc(size_t _p_size, int& __nobjs) {
   1.538 +#  if defined (_STLP_DO_CLEAN_NODE_ALLOC)
   1.539 +  //We are going to add a small memory block to keep all the allocated blocks
   1.540 +  //address, we need to do so respecting the memory alignment. The following
   1.541 +  //static assert checks that the reserved block is big enough to store a pointer.
   1.542 +  _STLP_STATIC_ASSERT(sizeof(_Obj) <= _ALIGN)
   1.543 +#  endif
   1.544 +  char*  __result       = 0;
   1.545 +  __add_atomic_t __total_bytes  = __STATIC_CAST(__add_atomic_t, _p_size) * __nobjs;
   1.546 +
   1.547 +  _FreeBlockHeader* __block = __STATIC_CAST(_FreeBlockHeader*, _S_free_mem_blocks.pop());
   1.548 +  if (__block != 0) {
   1.549 +    // We checked a block out and can now mess with it with impugnity.
   1.550 +    // We'll put the remainder back into the list if we're done with it below.
   1.551 +    char*  __buf_start  = __REINTERPRET_CAST(char*, __block);
   1.552 +    __add_atomic_t __bytes_left = __block->_M_end - __buf_start;
   1.553 +
   1.554 +    if ((__bytes_left < __total_bytes) && (__bytes_left >= __STATIC_CAST(__add_atomic_t, _p_size))) {
   1.555 +      // There's enough left for at least one object, but not as much as we wanted
   1.556 +      __result      = __buf_start;
   1.557 +      __nobjs       = (int)(__bytes_left/_p_size);
   1.558 +      __total_bytes = __STATIC_CAST(__add_atomic_t, _p_size) * __nobjs;
   1.559 +      __bytes_left -= __total_bytes;
   1.560 +      __buf_start  += __total_bytes;
   1.561 +    }
   1.562 +    else if (__bytes_left >= __total_bytes) {
   1.563 +      // The block has enough left to satisfy all that was asked for
   1.564 +      __result      = __buf_start;
   1.565 +      __bytes_left -= __total_bytes;
   1.566 +      __buf_start  += __total_bytes;
   1.567 +    }
   1.568 +
   1.569 +    if (__bytes_left != 0) {
   1.570 +      // There is still some memory left over in block after we satisfied our request.
   1.571 +      if ((__result != 0) && (__bytes_left >= (__add_atomic_t)sizeof(_FreeBlockHeader))) {
   1.572 +        // We were able to allocate at least one object and there is still enough
   1.573 +        // left to put remainder back into list.
   1.574 +        _FreeBlockHeader* __newblock = __REINTERPRET_CAST(_FreeBlockHeader*, __buf_start);
   1.575 +        __newblock->_M_end  = __block->_M_end;
   1.576 +        _S_free_mem_blocks.push(__newblock);
   1.577 +      }
   1.578 +      else {
   1.579 +        // We were not able to allocate enough for at least one object.
   1.580 +        // Shove into freelist of nearest (rounded-down!) size.
   1.581 +        size_t __rounded_down = _S_round_up(__bytes_left + 1) - (size_t)_ALIGN;
   1.582 +        if (__rounded_down > 0)
   1.583 +          _S_free_list[_S_FREELIST_INDEX(__rounded_down)].push((_Obj*)__buf_start);
   1.584 +      }
   1.585 +    }
   1.586 +    if (__result != 0)
   1.587 +      return __result;
   1.588 +  }
   1.589 +
   1.590 +  // We couldn't satisfy it from the list of free blocks, get new memory.
   1.591 +  __add_atomic_t __bytes_to_get = 2 * __total_bytes +
   1.592 +                                  __STATIC_CAST(__add_atomic_t,
   1.593 +                                                _S_round_up(__STATIC_CAST(__uadd_atomic_t, _STLP_ATOMIC_ADD(&_S_heap_size, 0)))) +
   1.594 +                                  _STLP_OFFSET;
   1.595 +  _STLP_TRY {
   1.596 +    __result = __stlp_new_chunk(__bytes_to_get);
   1.597 +  }
   1.598 +#if defined (_STLP_USE_EXCEPTIONS)
   1.599 +  catch (const bad_alloc&) {
   1.600 +    // Allocation failed; try to canibalize from freelist of a larger object size.
   1.601 +    for (size_t __i = _p_size; __i <= (size_t)_MAX_BYTES; __i += (size_t)_ALIGN) {
   1.602 +      _Obj* __p  = _S_free_list[_S_FREELIST_INDEX(__i)].pop();
   1.603 +      if (0 != __p) {
   1.604 +        if (__i < sizeof(_FreeBlockHeader)) {
   1.605 +          // Not enough to put into list of free blocks, divvy it up here.
   1.606 +          // Use as much as possible for this request and shove remainder into freelist.
   1.607 +          __nobjs = (int)(__i/_p_size);
   1.608 +          __total_bytes = __nobjs * __STATIC_CAST(__add_atomic_t, _p_size);
   1.609 +          size_t __bytes_left = __i - __total_bytes;
   1.610 +          size_t __rounded_down = _S_round_up(__bytes_left+1) - (size_t)_ALIGN;
   1.611 +          if (__rounded_down > 0) {
   1.612 +            _S_free_list[_S_FREELIST_INDEX(__rounded_down)].push(__REINTERPRET_CAST(_Obj*, __REINTERPRET_CAST(char*, __p) + __total_bytes));
   1.613 +          }
   1.614 +          return __REINTERPRET_CAST(char*, __p);
   1.615 +        }
   1.616 +        else {
   1.617 +          // Add node to list of available blocks and recursively allocate from it.
   1.618 +          _FreeBlockHeader* __newblock = (_FreeBlockHeader*)__p;
   1.619 +          __newblock->_M_end  = __REINTERPRET_CAST(char*, __p) + __i;
   1.620 +          _S_free_mem_blocks.push(__newblock);
   1.621 +          return _S_chunk_alloc(_p_size, __nobjs);
   1.622 +        }
   1.623 +      }
   1.624 +    }
   1.625 +
   1.626 +    // We were not able to find something in a freelist, try to allocate a smaller amount.
   1.627 +    __bytes_to_get  = __total_bytes + _STLP_OFFSET;
   1.628 +    __result = __stlp_new_chunk(__bytes_to_get);
   1.629 +
   1.630 +    // This should either throw an exception or remedy the situation.
   1.631 +    // Thus we assume it succeeded.
   1.632 +  }
   1.633 +#endif
   1.634 +  // Alignment check
   1.635 +  _STLP_VERBOSE_ASSERT(((__REINTERPRET_CAST(size_t, __result) & __STATIC_CAST(size_t, _ALIGN - 1)) == 0),
   1.636 +                       _StlMsg_DBA_DELETED_TWICE)
   1.637 +  _STLP_ATOMIC_ADD(&_S_heap_size, __bytes_to_get >> 4);
   1.638 +
   1.639 +#  if defined (_STLP_DO_CLEAN_NODE_ALLOC)
   1.640 +  // We have to track the allocated memory chunks for release on exit.
   1.641 +  _S_chunks.push(__REINTERPRET_CAST(_Obj*, __result));
   1.642 +  __result       += _ALIGN;
   1.643 +  __bytes_to_get -= _ALIGN;
   1.644 +#  endif
   1.645 +
   1.646 +  if (__bytes_to_get > __total_bytes) {
   1.647 +    // Push excess memory allocated in this chunk into list of free memory blocks
   1.648 +    _FreeBlockHeader* __freeblock = __REINTERPRET_CAST(_FreeBlockHeader*, __result + __total_bytes);
   1.649 +    __freeblock->_M_end  = __result + __bytes_to_get;
   1.650 +    _S_free_mem_blocks.push(__freeblock);
   1.651 +  }
   1.652 +  return __result;
   1.653 +}
   1.654 +
   1.655 +#  if defined (_STLP_DO_CLEAN_NODE_ALLOC)
   1.656 +void __node_alloc_impl::_S_alloc_call()
   1.657 +{ _STLP_ATOMIC_INCREMENT(&_S_alloc_counter()); }
   1.658 +
   1.659 +void __node_alloc_impl::_S_dealloc_call() {
   1.660 +  _STLP_VOLATILE __stl_atomic_t *pcounter = &_S_alloc_counter();
   1.661 +  if (_STLP_ATOMIC_DECREMENT(pcounter) == 0)
   1.662 +    _S_chunk_dealloc();
   1.663 +}
   1.664 +
   1.665 +/* We deallocate all the memory chunks      */
   1.666 +void __node_alloc_impl::_S_chunk_dealloc() {
   1.667 +  // Note: The _Node_alloc_helper class ensures that this function
   1.668 +  // will only be called when the (shared) library is unloaded or the
   1.669 +  // process is shutdown.  It's thus not possible that another thread
   1.670 +  // is currently trying to allocate a node (we're not thread-safe here).
   1.671 +  //
   1.672 +
   1.673 +  // Clear the free blocks and all freelistst.  This makes sure that if
   1.674 +  // for some reason more memory is allocated again during shutdown
   1.675 +  // (it'd also be really nasty to leave references to deallocated memory).
   1.676 +  _S_free_mem_blocks.clear();
   1.677 +  _S_heap_size      = 0;
   1.678 +
   1.679 +  for (size_t __i = 0; __i < _STLP_NFREELISTS; ++__i) {
   1.680 +    _S_free_list[__i].clear();
   1.681 +  }
   1.682 +
   1.683 +  // Detach list of chunks and free them all
   1.684 +  _Obj* __chunk = _S_chunks.clear();
   1.685 +  while (__chunk != 0) {
   1.686 +    _Obj* __next = __chunk->_M_next;
   1.687 +    __stlp_delete_chunck(__chunk);
   1.688 +    __chunk  = __next;
   1.689 +  }
   1.690 +}
   1.691 +#  endif
   1.692 +
   1.693 +#endif
   1.694 +
   1.695 +#if defined (_STLP_DO_CLEAN_NODE_ALLOC)
   1.696 +struct __node_alloc_cleaner {
   1.697 +  ~__node_alloc_cleaner()
   1.698 +  { __node_alloc_impl::_S_dealloc_call(); }
   1.699 +};
   1.700 +
   1.701 +#  if defined (_STLP_USE_LOCK_FREE_IMPLEMENTATION)
   1.702 +_STLP_VOLATILE __stl_atomic_t& _STLP_CALL
   1.703 +#  else
   1.704 +__stl_atomic_t& _STLP_CALL
   1.705 +#  endif
   1.706 +__node_alloc_impl::_S_alloc_counter() {
   1.707 +  static _AllocCounter _S_counter = 1;
   1.708 +  static __node_alloc_cleaner _S_node_alloc_cleaner;
   1.709 +  return _S_counter;
   1.710 +}
   1.711 +#endif
   1.712 +
   1.713 +#if !defined (_STLP_USE_LOCK_FREE_IMPLEMENTATION)
   1.714 +_Node_alloc_obj * _STLP_VOLATILE
   1.715 +__node_alloc_impl::_S_free_list[_STLP_NFREELISTS]
   1.716 += {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
   1.717 +// The 16 zeros are necessary to make version 4.1 of the SunPro
   1.718 +// compiler happy.  Otherwise it appears to allocate too little
   1.719 +// space for the array.
   1.720 +#else
   1.721 +_STLP_atomic_freelist __node_alloc_impl::_S_free_list[_STLP_NFREELISTS];
   1.722 +_STLP_atomic_freelist __node_alloc_impl::_S_free_mem_blocks;
   1.723 +#endif
   1.724 +
   1.725 +#if !defined (_STLP_USE_LOCK_FREE_IMPLEMENTATION)
   1.726 +char *__node_alloc_impl::_S_start_free = 0;
   1.727 +char *__node_alloc_impl::_S_end_free = 0;
   1.728 +#endif
   1.729 +
   1.730 +#if defined (_STLP_USE_LOCK_FREE_IMPLEMENTATION)
   1.731 +_STLP_VOLATILE __add_atomic_t
   1.732 +#else
   1.733 +size_t
   1.734 +#endif
   1.735 +__node_alloc_impl::_S_heap_size = 0;
   1.736 +
   1.737 +#if defined (_STLP_DO_CLEAN_NODE_ALLOC)
   1.738 +#  if defined (_STLP_USE_LOCK_FREE_IMPLEMENTATION)
   1.739 +_STLP_atomic_freelist __node_alloc_impl::_S_chunks;
   1.740 +#  else
   1.741 +_Node_alloc_obj* __node_alloc_impl::_S_chunks  = 0;
   1.742 +#  endif
   1.743 +#endif
   1.744 +
   1.745 +void * _STLP_CALL __node_alloc::_M_allocate(size_t& __n)
   1.746 +{ return __node_alloc_impl::_M_allocate(__n); }
   1.747 +
   1.748 +void _STLP_CALL __node_alloc::_M_deallocate(void *__p, size_t __n)
   1.749 +{ __node_alloc_impl::_M_deallocate(__p, __n); }
   1.750 +
   1.751 +#if defined (_STLP_PTHREADS) && !defined (_STLP_NO_THREADS)
   1.752 +
   1.753 +#  define _STLP_DATA_ALIGNMENT 8
   1.754 +
   1.755 +_STLP_MOVE_TO_PRIV_NAMESPACE
   1.756 +
   1.757 +// *******************************************************
   1.758 +// __perthread_alloc implementation
   1.759 +union _Pthread_alloc_obj {
   1.760 +  union _Pthread_alloc_obj * __free_list_link;
   1.761 +  char __client_data[_STLP_DATA_ALIGNMENT];    /* The client sees this.    */
   1.762 +};
   1.763 +
   1.764 +// Pthread allocators don't appear to the client to have meaningful
   1.765 +// instances.  We do in fact need to associate some state with each
   1.766 +// thread.  That state is represented by _Pthread_alloc_per_thread_state.
   1.767 +
   1.768 +struct _Pthread_alloc_per_thread_state {
   1.769 +  typedef _Pthread_alloc_obj __obj;
   1.770 +  enum { _S_NFREELISTS = _MAX_BYTES / _STLP_DATA_ALIGNMENT };
   1.771 +
   1.772 +  // Free list link for list of available per thread structures.
   1.773 +  // When one of these becomes available for reuse due to thread
   1.774 +  // termination, any objects in its free list remain associated
   1.775 +  // with it.  The whole structure may then be used by a newly
   1.776 +  // created thread.
   1.777 +  _Pthread_alloc_per_thread_state() : __next(0)
   1.778 +  { memset((void *)__CONST_CAST(_Pthread_alloc_obj**, __free_list), 0, (size_t)_S_NFREELISTS * sizeof(__obj *)); }
   1.779 +  // Returns an object of size __n, and possibly adds to size n free list.
   1.780 +  void *_M_refill(size_t __n);
   1.781 +
   1.782 +  _Pthread_alloc_obj* volatile __free_list[_S_NFREELISTS];
   1.783 +  _Pthread_alloc_per_thread_state *__next;
   1.784 +  // this data member is only to be used by per_thread_allocator, which returns memory to the originating thread.
   1.785 +  _STLP_mutex _M_lock;
   1.786 +};
   1.787 +
   1.788 +// Pthread-specific allocator.
   1.789 +class _Pthread_alloc_impl {
   1.790 +public: // but only for internal use:
   1.791 +  typedef _Pthread_alloc_per_thread_state __state_type;
   1.792 +  typedef char value_type;
   1.793 +
   1.794 +  // Allocates a chunk for nobjs of size size.  nobjs may be reduced
   1.795 +  // if it is inconvenient to allocate the requested number.
   1.796 +  static char *_S_chunk_alloc(size_t __size, size_t &__nobjs, __state_type*);
   1.797 +
   1.798 +  enum {_S_ALIGN = _STLP_DATA_ALIGNMENT};
   1.799 +
   1.800 +  static size_t _S_round_up(size_t __bytes)
   1.801 +  { return (((__bytes) + (int)_S_ALIGN - 1) & ~((int)_S_ALIGN - 1)); }
   1.802 +  static size_t _S_freelist_index(size_t __bytes)
   1.803 +  { return (((__bytes) + (int)_S_ALIGN - 1) / (int)_S_ALIGN - 1); }
   1.804 +
   1.805 +private:
   1.806 +  // Chunk allocation state. And other shared state.
   1.807 +  // Protected by _S_chunk_allocator_lock.
   1.808 +  static _STLP_STATIC_MUTEX _S_chunk_allocator_lock;
   1.809 +  static char *_S_start_free;
   1.810 +  static char *_S_end_free;
   1.811 +  static size_t _S_heap_size;
   1.812 +  static __state_type *_S_free_per_thread_states;
   1.813 +  static pthread_key_t _S_key;
   1.814 +  static bool _S_key_initialized;
   1.815 +  // Pthread key under which per thread state is stored.
   1.816 +  // Allocator instances that are currently unclaimed by any thread.
   1.817 +  static void _S_destructor(void *instance);
   1.818 +  // Function to be called on thread exit to reclaim per thread
   1.819 +  // state.
   1.820 +  static __state_type *_S_new_per_thread_state();
   1.821 +public:
   1.822 +  // Return a recycled or new per thread state.
   1.823 +  static __state_type *_S_get_per_thread_state();
   1.824 +private:
   1.825 +        // ensure that the current thread has an associated
   1.826 +        // per thread state.
   1.827 +  class _M_lock;
   1.828 +  friend class _M_lock;
   1.829 +  class _M_lock {
   1.830 +  public:
   1.831 +    _M_lock () { _S_chunk_allocator_lock._M_acquire_lock(); }
   1.832 +    ~_M_lock () { _S_chunk_allocator_lock._M_release_lock(); }
   1.833 +  };
   1.834 +
   1.835 +public:
   1.836 +
   1.837 +  /* n must be > 0      */
   1.838 +  static void * allocate(size_t& __n);
   1.839 +
   1.840 +  /* p may not be 0 */
   1.841 +  static void deallocate(void *__p, size_t __n);
   1.842 +
   1.843 +  // boris : versions for per_thread_allocator
   1.844 +  /* n must be > 0      */
   1.845 +  static void * allocate(size_t& __n, __state_type* __a);
   1.846 +
   1.847 +  /* p may not be 0 */
   1.848 +  static void deallocate(void *__p, size_t __n, __state_type* __a);
   1.849 +
   1.850 +  static void * reallocate(void *__p, size_t __old_sz, size_t& __new_sz);
   1.851 +};
   1.852 +
   1.853 +/* Returns an object of size n, and optionally adds to size n free list.*/
   1.854 +/* We assume that n is properly aligned.                                */
   1.855 +/* We hold the allocation lock.                                         */
   1.856 +void *_Pthread_alloc_per_thread_state::_M_refill(size_t __n) {
   1.857 +  typedef _Pthread_alloc_obj __obj;
   1.858 +  size_t __nobjs = 128;
   1.859 +  char * __chunk = _Pthread_alloc_impl::_S_chunk_alloc(__n, __nobjs, this);
   1.860 +  __obj * volatile * __my_free_list;
   1.861 +  __obj * __result;
   1.862 +  __obj * __current_obj, * __next_obj;
   1.863 +  size_t __i;
   1.864 +
   1.865 +  if (1 == __nobjs)  {
   1.866 +    return __chunk;
   1.867 +  }
   1.868 +
   1.869 +  __my_free_list = __free_list + _Pthread_alloc_impl::_S_freelist_index(__n);
   1.870 +
   1.871 +  /* Build free list in chunk */
   1.872 +  __result = (__obj *)__chunk;
   1.873 +  *__my_free_list = __next_obj = (__obj *)(__chunk + __n);
   1.874 +  for (__i = 1; ; ++__i) {
   1.875 +    __current_obj = __next_obj;
   1.876 +    __next_obj = (__obj *)((char *)__next_obj + __n);
   1.877 +    if (__nobjs - 1 == __i) {
   1.878 +      __current_obj -> __free_list_link = 0;
   1.879 +      break;
   1.880 +    } else {
   1.881 +      __current_obj -> __free_list_link = __next_obj;
   1.882 +    }
   1.883 +  }
   1.884 +  return __result;
   1.885 +}
   1.886 +
   1.887 +void _Pthread_alloc_impl::_S_destructor(void *__instance) {
   1.888 +  _M_lock __lock_instance;  // Need to acquire lock here.
   1.889 +  _Pthread_alloc_per_thread_state* __s = (_Pthread_alloc_per_thread_state*)__instance;
   1.890 +  __s -> __next = _S_free_per_thread_states;
   1.891 +  _S_free_per_thread_states = __s;
   1.892 +}
   1.893 +
   1.894 +_Pthread_alloc_per_thread_state* _Pthread_alloc_impl::_S_new_per_thread_state() {
   1.895 +  /* lock already held here.  */
   1.896 +  if (0 != _S_free_per_thread_states) {
   1.897 +    _Pthread_alloc_per_thread_state *__result = _S_free_per_thread_states;
   1.898 +    _S_free_per_thread_states = _S_free_per_thread_states -> __next;
   1.899 +    return __result;
   1.900 +  }
   1.901 +  else {
   1.902 +    return new _Pthread_alloc_per_thread_state;
   1.903 +  }
   1.904 +}
   1.905 +
   1.906 +_Pthread_alloc_per_thread_state* _Pthread_alloc_impl::_S_get_per_thread_state() {
   1.907 +  int __ret_code;
   1.908 +  __state_type* __result;
   1.909 +
   1.910 +  if (_S_key_initialized && (__result = (__state_type*) pthread_getspecific(_S_key)))
   1.911 +    return __result;
   1.912 +
   1.913 +  /*REFERENCED*/
   1.914 +  _M_lock __lock_instance;  // Need to acquire lock here.
   1.915 +  if (!_S_key_initialized) {
   1.916 +    if (pthread_key_create(&_S_key, _S_destructor)) {
   1.917 +      _STLP_THROW_BAD_ALLOC;  // failed
   1.918 +    }
   1.919 +    _S_key_initialized = true;
   1.920 +  }
   1.921 +
   1.922 +  __result = _S_new_per_thread_state();
   1.923 +  __ret_code = pthread_setspecific(_S_key, __result);
   1.924 +  if (__ret_code) {
   1.925 +    if (__ret_code == ENOMEM) {
   1.926 +      _STLP_THROW_BAD_ALLOC;
   1.927 +    } else {
   1.928 +  // EINVAL
   1.929 +      _STLP_ABORT();
   1.930 +    }
   1.931 +  }
   1.932 +  return __result;
   1.933 +}
   1.934 +
   1.935 +/* We allocate memory in large chunks in order to avoid fragmenting     */
   1.936 +/* the malloc heap too much.                                            */
   1.937 +/* We assume that size is properly aligned.                             */
   1.938 +char *_Pthread_alloc_impl::_S_chunk_alloc(size_t __p_size, size_t &__nobjs, _Pthread_alloc_per_thread_state *__a) {
   1.939 +  typedef _Pthread_alloc_obj __obj;
   1.940 +  {
   1.941 +    char * __result;
   1.942 +    size_t __total_bytes;
   1.943 +    size_t __bytes_left;
   1.944 +    /*REFERENCED*/
   1.945 +    _M_lock __lock_instance;         // Acquire lock for this routine
   1.946 +
   1.947 +    __total_bytes = __p_size * __nobjs;
   1.948 +    __bytes_left = _S_end_free - _S_start_free;
   1.949 +    if (__bytes_left >= __total_bytes) {
   1.950 +      __result = _S_start_free;
   1.951 +      _S_start_free += __total_bytes;
   1.952 +      return __result;
   1.953 +    } else if (__bytes_left >= __p_size) {
   1.954 +      __nobjs = __bytes_left/__p_size;
   1.955 +      __total_bytes = __p_size * __nobjs;
   1.956 +      __result = _S_start_free;
   1.957 +      _S_start_free += __total_bytes;
   1.958 +      return __result;
   1.959 +    } else {
   1.960 +      size_t __bytes_to_get = 2 * __total_bytes + _S_round_up(_S_heap_size);
   1.961 +      // Try to make use of the left-over piece.
   1.962 +      if (__bytes_left > 0) {
   1.963 +        __obj * volatile * __my_free_list = __a->__free_list + _S_freelist_index(__bytes_left);
   1.964 +        ((__obj *)_S_start_free) -> __free_list_link = *__my_free_list;
   1.965 +        *__my_free_list = (__obj *)_S_start_free;
   1.966 +      }
   1.967 +#  ifdef _SGI_SOURCE
   1.968 +      // Try to get memory that's aligned on something like a
   1.969 +      // cache line boundary, so as to avoid parceling out
   1.970 +      // parts of the same line to different threads and thus
   1.971 +      // possibly different processors.
   1.972 +      {
   1.973 +        const int __cache_line_size = 128;  // probable upper bound
   1.974 +        __bytes_to_get &= ~(__cache_line_size-1);
   1.975 +        _S_start_free = (char *)memalign(__cache_line_size, __bytes_to_get);
   1.976 +        if (0 == _S_start_free) {
   1.977 +          _S_start_free = (char *)__malloc_alloc::allocate(__bytes_to_get);
   1.978 +        }
   1.979 +      }
   1.980 +#  else  /* !SGI_SOURCE */
   1.981 +      _S_start_free = (char *)__malloc_alloc::allocate(__bytes_to_get);
   1.982 +#  endif
   1.983 +      _S_heap_size += __bytes_to_get >> 4;
   1.984 +      _S_end_free = _S_start_free + __bytes_to_get;
   1.985 +    }
   1.986 +  }
   1.987 +  // lock is released here
   1.988 +  return _S_chunk_alloc(__p_size, __nobjs, __a);
   1.989 +}
   1.990 +
   1.991 +
   1.992 +/* n must be > 0      */
   1.993 +void *_Pthread_alloc_impl::allocate(size_t& __n) {
   1.994 +  typedef _Pthread_alloc_obj __obj;
   1.995 +  __obj * volatile * __my_free_list;
   1.996 +  __obj * __result;
   1.997 +  __state_type* __a;
   1.998 +
   1.999 +  if (__n > _MAX_BYTES) {
  1.1000 +    return __malloc_alloc::allocate(__n);
  1.1001 +  }
  1.1002 +
  1.1003 +  __n = _S_round_up(__n);
  1.1004 +  __a = _S_get_per_thread_state();
  1.1005 +
  1.1006 +  __my_free_list = __a->__free_list + _S_freelist_index(__n);
  1.1007 +  __result = *__my_free_list;
  1.1008 +  if (__result == 0) {
  1.1009 +    void *__r = __a->_M_refill(__n);
  1.1010 +    return __r;
  1.1011 +  }
  1.1012 +  *__my_free_list = __result->__free_list_link;
  1.1013 +  return __result;
  1.1014 +};
  1.1015 +
  1.1016 +/* p may not be 0 */
  1.1017 +void _Pthread_alloc_impl::deallocate(void *__p, size_t __n) {
  1.1018 +  typedef _Pthread_alloc_obj __obj;
  1.1019 +  __obj *__q = (__obj *)__p;
  1.1020 +  __obj * volatile * __my_free_list;
  1.1021 +  __state_type* __a;
  1.1022 +
  1.1023 +  if (__n > _MAX_BYTES) {
  1.1024 +      __malloc_alloc::deallocate(__p, __n);
  1.1025 +      return;
  1.1026 +  }
  1.1027 +
  1.1028 +  __a = _S_get_per_thread_state();
  1.1029 +
  1.1030 +  __my_free_list = __a->__free_list + _S_freelist_index(__n);
  1.1031 +  __q -> __free_list_link = *__my_free_list;
  1.1032 +  *__my_free_list = __q;
  1.1033 +}
  1.1034 +
  1.1035 +// boris : versions for per_thread_allocator
  1.1036 +/* n must be > 0      */
  1.1037 +void *_Pthread_alloc_impl::allocate(size_t& __n, __state_type* __a) {
  1.1038 +  typedef _Pthread_alloc_obj __obj;
  1.1039 +  __obj * volatile * __my_free_list;
  1.1040 +  __obj * __result;
  1.1041 +
  1.1042 +  if (__n > _MAX_BYTES) {
  1.1043 +    return __malloc_alloc::allocate(__n);
  1.1044 +  }
  1.1045 +  __n = _S_round_up(__n);
  1.1046 +
  1.1047 +  // boris : here, we have to lock per thread state, as we may be getting memory from
  1.1048 +  // different thread pool.
  1.1049 +  _STLP_auto_lock __lock(__a->_M_lock);
  1.1050 +
  1.1051 +  __my_free_list = __a->__free_list + _S_freelist_index(__n);
  1.1052 +  __result = *__my_free_list;
  1.1053 +  if (__result == 0) {
  1.1054 +    void *__r = __a->_M_refill(__n);
  1.1055 +    return __r;
  1.1056 +  }
  1.1057 +  *__my_free_list = __result->__free_list_link;
  1.1058 +  return __result;
  1.1059 +};
  1.1060 +
  1.1061 +/* p may not be 0 */
  1.1062 +void _Pthread_alloc_impl::deallocate(void *__p, size_t __n, __state_type* __a) {
  1.1063 +  typedef _Pthread_alloc_obj __obj;
  1.1064 +  __obj *__q = (__obj *)__p;
  1.1065 +  __obj * volatile * __my_free_list;
  1.1066 +
  1.1067 +  if (__n > _MAX_BYTES) {
  1.1068 +    __malloc_alloc::deallocate(__p, __n);
  1.1069 +    return;
  1.1070 +  }
  1.1071 +
  1.1072 +  // boris : here, we have to lock per thread state, as we may be returning memory from
  1.1073 +  // different thread.
  1.1074 +  _STLP_auto_lock __lock(__a->_M_lock);
  1.1075 +
  1.1076 +  __my_free_list = __a->__free_list + _S_freelist_index(__n);
  1.1077 +  __q -> __free_list_link = *__my_free_list;
  1.1078 +  *__my_free_list = __q;
  1.1079 +}
  1.1080 +
  1.1081 +void *_Pthread_alloc_impl::reallocate(void *__p, size_t __old_sz, size_t& __new_sz) {
  1.1082 +  void * __result;
  1.1083 +  size_t __copy_sz;
  1.1084 +
  1.1085 +  if (__old_sz > _MAX_BYTES && __new_sz > _MAX_BYTES) {
  1.1086 +    return realloc(__p, __new_sz);
  1.1087 +  }
  1.1088 +
  1.1089 +  if (_S_round_up(__old_sz) == _S_round_up(__new_sz)) return __p;
  1.1090 +  __result = allocate(__new_sz);
  1.1091 +  __copy_sz = __new_sz > __old_sz? __old_sz : __new_sz;
  1.1092 +  memcpy(__result, __p, __copy_sz);
  1.1093 +  deallocate(__p, __old_sz);
  1.1094 +  return __result;
  1.1095 +}
  1.1096 +
  1.1097 +_Pthread_alloc_per_thread_state* _Pthread_alloc_impl::_S_free_per_thread_states = 0;
  1.1098 +pthread_key_t _Pthread_alloc_impl::_S_key = 0;
  1.1099 +_STLP_STATIC_MUTEX _Pthread_alloc_impl::_S_chunk_allocator_lock _STLP_MUTEX_INITIALIZER;
  1.1100 +bool _Pthread_alloc_impl::_S_key_initialized = false;
  1.1101 +char *_Pthread_alloc_impl::_S_start_free = 0;
  1.1102 +char *_Pthread_alloc_impl::_S_end_free = 0;
  1.1103 +size_t _Pthread_alloc_impl::_S_heap_size = 0;
  1.1104 +
  1.1105 +void * _STLP_CALL _Pthread_alloc::allocate(size_t& __n)
  1.1106 +{ return _Pthread_alloc_impl::allocate(__n); }
  1.1107 +void _STLP_CALL _Pthread_alloc::deallocate(void *__p, size_t __n)
  1.1108 +{ _Pthread_alloc_impl::deallocate(__p, __n); }
  1.1109 +void * _STLP_CALL _Pthread_alloc::allocate(size_t& __n, __state_type* __a)
  1.1110 +{ return _Pthread_alloc_impl::allocate(__n, __a); }
  1.1111 +void _STLP_CALL _Pthread_alloc::deallocate(void *__p, size_t __n, __state_type* __a)
  1.1112 +{ _Pthread_alloc_impl::deallocate(__p, __n, __a); }
  1.1113 +void * _STLP_CALL _Pthread_alloc::reallocate(void *__p, size_t __old_sz, size_t& __new_sz)
  1.1114 +{ return _Pthread_alloc_impl::reallocate(__p, __old_sz, __new_sz); }
  1.1115 +_Pthread_alloc_per_thread_state* _STLP_CALL _Pthread_alloc::_S_get_per_thread_state()
  1.1116 +{ return _Pthread_alloc_impl::_S_get_per_thread_state(); }
  1.1117 +
  1.1118 +_STLP_MOVE_TO_STD_NAMESPACE
  1.1119 +
  1.1120 +#endif
  1.1121 +
  1.1122 +_STLP_END_NAMESPACE
  1.1123 +
  1.1124 +#undef _S_FREELIST_INDEX

mercurial