head	1.4;
access;
symbols
	isolib-2:1.1.1.1
	isolib:1.1.1;
locks; strict;
comment	@# @;


1.4
date	99.05.05.00.43.59;	author bkoz;	state dead;
branches;
next	1.3;

1.3
date	98.07.24.18.42.07;	author ncm;	state Exp;
branches;
next	1.2;

1.2
date	98.06.10.05.33.57;	author ncm;	state Exp;
branches;
next	1.1;

1.1
date	98.04.15.04.57.47;	author ncm;	state Exp;
branches
	1.1.1.1;
next	;

1.1.1.1
date	98.04.15.04.57.47;	author ncm;	state Exp;
branches;
next	;


desc
@@


1.4
log
@
1999-05-04  Benjamin Kosnik  <bkoz@@cygnus.com>
	* src/gen-num-limits.cc (round_style): Need to use mknumericlimits
	to generate bits/std_limits.h now, as the SGI std_limits.h is
	being depricated. Not done, but should be done immediately: need
	to make sure this script is run as part of the configuration
	process, because without it "make" in a configured build directory
	will fail. Also tweaked: added a space for float_round_style, and
	used static_cast of zero to default-initialize, which should be ok
	according to the standard. (see 8.5 p5 and 20.1.3).
	* mknumeric_limits (OUT_C): Need this for x86 long
	double extensions.
	* bits/basic_file.h: Include libio.h, not libioP.h.
	* src/basic_file.cc: And add libioP.h include here, so that
	_IO_init, et. al are well-declared.
	* testsuite/make_check_libfree++ (LIB_PATH): Test installed
	headers, not source directory headers.
	* src/Makefile.am (headers): Add stl_range_errors.h, also adjust
	for ext/*.  Also add basic_file.h.
	* src/Makefile.in (headers): Same.
	* bits/std_string.h: Reduce dependencies for faster
	pre-processing. Move istream and ostream specific defines into
	istream.tcc and ostream.tcc respectively.
	* bits/string.tcc: And here.
	* bits/basic_string.h: Move getline inline out-of-line, and to
	istream.tcc.
	* bits/istream.tcc: Move string::getline and operator>> here.
	* bits/ostream.tcc: And here too.
	* bits/utility.h: Remove, as clashes with a standard header. Put
	__OUTOFRANGE and __LENGTHERROR macros into string.tcc for the time
	being, until this can be combined with SGI's approach.
	* bits/string.tcc: Add macros, as above.
	* bits/loccore.h: Add _Count_ones defines.
	* bits/std_string.h: And here too.
	* bits/std_locale.h: And here.
	* bits/std_ios.h: Take out include here.
	* src/Makefile.am (headers): Remove utility.h
	* src/Makefile.in (headers): Remove utility.h
	* stl/bits/*: Update to SGI STL 3.20.
	* stl/ext/pthread_alloc: Delete this file.
@
text
@/*
 * Copyright (c) 1996
 * Silicon Graphics Computer Systems, Inc.
 *
 * Permission to use, copy, modify, distribute and sell this software
 * and its documentation for any purpose is hereby granted without fee,
 * provided that the above copyright notice appear in all copies and
 * that both that copyright notice and this permission notice appear
 * in supporting documentation.  Silicon Graphics makes no
 * representations about the suitability of this software for any
 * purpose.  It is provided "as is" without express or implied warranty.
 */

#ifndef _CPP_EXT_PTHREAD_ALLOC
#define _CPP_EXT_PTHREAD_ALLOC 1

// Pthread-specific node allocator.
// This is similar to the default allocator, except that free-list
// information is kept separately for each thread, avoiding locking.
// This should be reasonably fast even in the presence of threads.
// The down side is that storage may not be well-utilized.
// It is not an error to allocate memory in thread A and deallocate
// it in thread B.  But this effectively transfers ownership of the memory,
// so that it can only be reallocated by thread B.  Thus this can effectively
// result in a storage leak if it's done on a regular basis.
// It can also result in frequent sharing of
// cache lines among processors, with potentially serious performance
// consequences.

#include <bits/stl_config.h>
#include <bits/stl_alloc.h>
#ifndef __RESTRICT
#  define __RESTRICT
#endif

__STL_BEGIN_NAMESPACE

#define __STL_DATA_ALIGNMENT 8

union _Pthread_alloc_obj {
    union _Pthread_alloc_obj * __free_list_link;
    char __client_data[__STL_DATA_ALIGNMENT];    /* The client sees this.    */
};

// Pthread allocators don't appear to the client to have meaningful
// instances.  We do in fact need to associate some state with each
// thread.  That state is represented by
// _Pthread_alloc_per_thread_state<_Max_size>.

template<size_t _Max_size>
struct _Pthread_alloc_per_thread_state {
  typedef _Pthread_alloc_obj __obj;
  enum { _S_NFREELISTS = _Max_size/__STL_DATA_ALIGNMENT };
  _Pthread_alloc_obj* volatile __free_list[_S_NFREELISTS]; 
  _Pthread_alloc_per_thread_state<_Max_size> * __next; 
	// Free list link for list of available per thread structures.
  	// When one of these becomes available for reuse due to thread
	// termination, any objects in its free list remain associated
	// with it.  The whole structure may then be used by a newly
	// created thread.
  _Pthread_alloc_per_thread_state() : __next(0)
  {
    memset((void *)__free_list, 0, _S_NFREELISTS * sizeof(__obj *));
  }
  // Returns an object of size __n, and possibly adds to size n free list.
  void *_M_refill(size_t __n);
};

// Pthread-specific allocator.
// The argument specifies the largest object size allocated from per-thread
// free lists.  Larger objects are allocated using malloc_alloc.
// Max_size must be a power of 2.
template <size_t _Max_size = 128>
class _Pthread_alloc_template {

public: // but only for internal use:

  typedef _Pthread_alloc_obj __obj;

  // Allocates a chunk for nobjs of size size.  nobjs may be reduced
  // if it is inconvenient to allocate the requested number.
  static char *_S_chunk_alloc(size_t __size, int &__nobjs);

  enum {_S_ALIGN = __STL_DATA_ALIGNMENT};

  static size_t _S_round_up(size_t __bytes) {
        return (((__bytes) + _S_ALIGN-1) & ~(_S_ALIGN - 1));
  }
  static size_t _S_freelist_index(size_t __bytes) {
        return (((__bytes) + _S_ALIGN-1)/_S_ALIGN - 1);
  }

private:
  // Chunk allocation state. And other shared state.
  // Protected by _S_chunk_allocator_lock.
  static pthread_mutex_t _S_chunk_allocator_lock;
  static char *_S_start_free;
  static char *_S_end_free;
  static size_t _S_heap_size;
  static _Pthread_alloc_per_thread_state<_Max_size>* _S_free_per_thread_states;
  static pthread_key_t _S_key;
  static bool _S_key_initialized;
        // Pthread key under which per thread state is stored. 
        // Allocator instances that are currently unclaimed by any thread.
  static void _S_destructor(void *instance);
        // Function to be called on thread exit to reclaim per thread
        // state.
  static _Pthread_alloc_per_thread_state<_Max_size> *_S_new_per_thread_state();
        // Return a recycled or new per thread state.
  static _Pthread_alloc_per_thread_state<_Max_size> *_S_get_per_thread_state();
        // ensure that the current thread has an associated
        // per thread state.
  friend class _M_lock;
  class _M_lock {
      public:
        _M_lock () { pthread_mutex_lock(&_S_chunk_allocator_lock); }
        ~_M_lock () { pthread_mutex_unlock(&_S_chunk_allocator_lock); }
  };

public:

  /* n must be > 0      */
  static void * allocate(size_t __n)
  {
    __obj * volatile * __my_free_list;
    __obj * __RESTRICT __result;
    _Pthread_alloc_per_thread_state<_Max_size>* __a;

    if (__n > _Max_size) {
        return(malloc_alloc::allocate(__n));
    }
    if (!_S_key_initialized ||
        !(__a = (_Pthread_alloc_per_thread_state<_Max_size>*)
                                 pthread_getspecific(_S_key))) {
        __a = _S_get_per_thread_state();
    }
    __my_free_list = __a -> __free_list + _S_freelist_index(__n);
    __result = *__my_free_list;
    if (__result == 0) {
        void *__r = __a -> _M_refill(_S_round_up(__n));
        return __r;
    }
    *__my_free_list = __result -> __free_list_link;
    return (__result);
  };

  /* p may not be 0 */
  static void deallocate(void *__p, size_t __n)
  {
    __obj *__q = (__obj *)__p;
    __obj * volatile * __my_free_list;
    _Pthread_alloc_per_thread_state<_Max_size>* __a;

    if (__n > _Max_size) {
        malloc_alloc::deallocate(__p, __n);
        return;
    }
    if (!_S_key_initialized ||
        !(__a = (_Pthread_alloc_per_thread_state<_Max_size> *)
                pthread_getspecific(_S_key))) {
        __a = _S_get_per_thread_state();
    }
    __my_free_list = __a->__free_list + _S_freelist_index(__n);
    __q -> __free_list_link = *__my_free_list;
    *__my_free_list = __q;
  }

  static void * reallocate(void *__p, size_t __old_sz, size_t __new_sz);

} ;

typedef _Pthread_alloc_template<> pthread_alloc;


template <size_t _Max_size>
void _Pthread_alloc_template<_Max_size>::_S_destructor(void * __instance)
{
    _M_lock __lock_instance;	// Need to acquire lock here.
    _Pthread_alloc_per_thread_state<_Max_size>* __s =
        (_Pthread_alloc_per_thread_state<_Max_size> *)__instance;
    __s -> __next = _S_free_per_thread_states;
    _S_free_per_thread_states = __s;
}

template <size_t _Max_size>
_Pthread_alloc_per_thread_state<_Max_size> *
_Pthread_alloc_template<_Max_size>::_S_new_per_thread_state()
{    
    /* lock already held here.	*/
    if (0 != _S_free_per_thread_states) {
        _Pthread_alloc_per_thread_state<_Max_size> *__result =
					_S_free_per_thread_states;
        _S_free_per_thread_states = _S_free_per_thread_states -> __next;
        return __result;
    } else {
        return new _Pthread_alloc_per_thread_state<_Max_size>;
    }
}

template <size_t _Max_size>
_Pthread_alloc_per_thread_state<_Max_size> *
_Pthread_alloc_template<_Max_size>::_S_get_per_thread_state()
{
    /*REFERENCED*/
    _M_lock __lock_instance;	// Need to acquire lock here.
    _Pthread_alloc_per_thread_state<_Max_size> * __result;
    if (!_S_key_initialized) {
        if (pthread_key_create(&_S_key, _S_destructor)) {
            abort();  // failed
        }
        _S_key_initialized = true;
    }
    __result = _S_new_per_thread_state();
    if (pthread_setspecific(_S_key, __result)) abort();
    return __result;
}

/* We allocate memory in large chunks in order to avoid fragmenting     */
/* the malloc heap too much.                                            */
/* We assume that size is properly aligned.                             */
template <size_t _Max_size>
char *_Pthread_alloc_template<_Max_size>
::_S_chunk_alloc(size_t __size, int &__nobjs)
{
  {
    char * __result;
    size_t __total_bytes;
    size_t __bytes_left;
    /*REFERENCED*/
    _M_lock __lock_instance;         // Acquire lock for this routine

    __total_bytes = __size * __nobjs;
    __bytes_left = _S_end_free - _S_start_free;
    if (__bytes_left >= __total_bytes) {
        __result = _S_start_free;
        _S_start_free += __total_bytes;
        return(__result);
    } else if (__bytes_left >= __size) {
        __nobjs = __bytes_left/__size;
        __total_bytes = __size * __nobjs;
        __result = _S_start_free;
        _S_start_free += __total_bytes;
        return(__result);
    } else {
        size_t __bytes_to_get =
		2 * __total_bytes + _S_round_up(_S_heap_size >> 4);
        // Try to make use of the left-over piece.
        if (__bytes_left > 0) {
            _Pthread_alloc_per_thread_state<_Max_size>* __a = 
                (_Pthread_alloc_per_thread_state<_Max_size>*)
			pthread_getspecific(_S_key);
            __obj * volatile * __my_free_list =
                        __a->__free_list + _S_freelist_index(__bytes_left);

            ((__obj *)_S_start_free) -> __free_list_link = *__my_free_list;
            *__my_free_list = (__obj *)_S_start_free;
        }
#       ifdef _SGI_SOURCE
          // Try to get memory that's aligned on something like a
          // cache line boundary, so as to avoid parceling out
          // parts of the same line to different threads and thus
          // possibly different processors.
          {
            const int __cache_line_size = 128;  // probable upper bound
            __bytes_to_get &= ~(__cache_line_size-1);
            _S_start_free = (char *)memalign(__cache_line_size, __bytes_to_get); 
            if (0 == _S_start_free) {
              _S_start_free = (char *)malloc_alloc::allocate(__bytes_to_get);
            }
          }
#       else  /* !SGI_SOURCE */
          _S_start_free = (char *)malloc_alloc::allocate(__bytes_to_get);
#       endif
        _S_heap_size += __bytes_to_get;
        _S_end_free = _S_start_free + __bytes_to_get;
    }
  }
  // lock is released here
  return(_S_chunk_alloc(__size, __nobjs));
}


/* Returns an object of size n, and optionally adds to size n free list.*/
/* We assume that n is properly aligned.                                */
/* We hold the allocation lock.                                         */
template <size_t _Max_size>
void *_Pthread_alloc_per_thread_state<_Max_size>
::_M_refill(size_t __n)
{
    int __nobjs = 128;
    char * __chunk =
	_Pthread_alloc_template<_Max_size>::_S_chunk_alloc(__n, __nobjs);
    __obj * volatile * __my_free_list;
    __obj * __result;
    __obj * __current_obj, * __next_obj;
    int __i;

    if (1 == __nobjs)  {
        return(__chunk);
    }
    __my_free_list = __free_list
		 + _Pthread_alloc_template<_Max_size>::_S_freelist_index(__n);

    /* Build free list in chunk */
      __result = (__obj *)__chunk;
      *__my_free_list = __next_obj = (__obj *)(__chunk + __n);
      for (__i = 1; ; __i++) {
        __current_obj = __next_obj;
        __next_obj = (__obj *)((char *)__next_obj + __n);
        if (__nobjs - 1 == __i) {
            __current_obj -> __free_list_link = 0;
            break;
        } else {
            __current_obj -> __free_list_link = __next_obj;
        }
      }
    return(__result);
}

template <size_t _Max_size>
void *_Pthread_alloc_template<_Max_size>
::reallocate(void *__p, size_t __old_sz, size_t __new_sz)
{
    void * __result;
    size_t __copy_sz;

    if (__old_sz > _Max_size
	&& __new_sz > _Max_size) {
        return(realloc(__p, __new_sz));
    }
    if (_S_round_up(__old_sz) == _S_round_up(__new_sz)) return(__p);
    __result = allocate(__new_sz);
    __copy_sz = __new_sz > __old_sz? __old_sz : __new_sz;
    memcpy(__result, __p, __copy_sz);
    deallocate(__p, __old_sz);
    return(__result);
}

template <size_t _Max_size>
_Pthread_alloc_per_thread_state<_Max_size> *
_Pthread_alloc_template<_Max_size>::_S_free_per_thread_states = 0;

template <size_t _Max_size>
pthread_key_t _Pthread_alloc_template<_Max_size>::_S_key;

template <size_t _Max_size>
bool _Pthread_alloc_template<_Max_size>::_S_key_initialized = false;

template <size_t _Max_size>
pthread_mutex_t _Pthread_alloc_template<_Max_size>::_S_chunk_allocator_lock
= PTHREAD_MUTEX_INITIALIZER;

template <size_t _Max_size>
char *_Pthread_alloc_template<_Max_size>
::_S_start_free = 0;

template <size_t _Max_size>
char *_Pthread_alloc_template<_Max_size>
::_S_end_free = 0;

template <size_t _Max_size>
size_t _Pthread_alloc_template<_Max_size>
::_S_heap_size = 0;

#ifdef __STL_USE_STD_ALLOCATORS

template <class _Tp>
class pthread_allocator {
  typedef pthread_alloc _S_Alloc;          // The underlying allocator.
public:
  typedef size_t    size_type;
  typedef ptrdiff_t difference_type;
  typedef _Tp*       pointer;
  typedef const _Tp* const_pointer;
  typedef _Tp&       reference;
  typedef const _Tp&  const_reference;
  typedef _Tp        value_type;

  template <class _U> struct rebind {
    typedef pthread_allocator<_U> other;
  };

  pthread_allocator() __STL_NOTHROW {}
  pthread_allocator(const pthread_allocator& a) __STL_NOTHROW {}
  template <class _U> pthread_allocator(const pthread_allocator<_U>&)
		__STL_NOTHROW {}
  ~pthread_allocator() __STL_NOTHROW {}

  pointer address(reference __x) const { return &__x; }
  const_pointer address(const_reference __x) const { return &__x; }

  // __n is permitted to be 0.  The C++ standard says nothing about what
  // the return value is when __n == 0.
  _Tp* allocate(size_type __n, const void* = 0) {
    return __n != 0 ? static_cast<_Tp*>(_S_Alloc::allocate(__n * sizeof(_Tp)))
                    : 0;
  }

  // p is not permitted to be a null pointer.
  void deallocate(pointer __p, size_type __n)
    { _S_Alloc::deallocate(__p, __n * sizeof(_Tp)); }

  size_type max_size() const __STL_NOTHROW 
    { return size_t(-1) / sizeof(_Tp); }

  void construct(pointer __p, const _Tp& __val) { new(__p) _Tp(__val); }
  void destroy(pointer _p) { _p->~_Tp(); }
};

template<>
class pthread_allocator<void> {
public:
  typedef size_t      size_type;
  typedef ptrdiff_t   difference_type;
  typedef void*       pointer;
  typedef const void* const_pointer;
  typedef void        value_type;

  template <class _U> struct rebind {
    typedef pthread_allocator<_U> other;
  };
};

template <size_t _Max_size>
inline bool operator==(const _Pthread_alloc_template<_Max_size>&,
                       const _Pthread_alloc_template<_Max_size>&)
{
  return true;
}

template <class _Tp1, class _Tp2>
inline bool operator==(const pthread_allocator<_Tp1>&,
                       const pthread_allocator<_Tp2>& a2) 
{
  return true;
}

template <class _Tp1, class _Tp2>
inline bool operator!=(const pthread_allocator<_Tp1>&,
                       const pthread_allocator<_Tp2>&)
{
  return false;
}

template <class _Tp, size_t _Max_size>
struct _Alloc_traits<_Tp, _Pthread_alloc_template<_Max_size> >
{
  static const bool _S_instanceless = true;
  typedef simple_alloc<_Tp, _Pthread_alloc_template<_Max_size> > _Alloc_type;
  typedef __allocator<_Tp, _Pthread_alloc_template<_Max_size> > 
          allocator_type;
};

template <class _Tp, class _U, size_t _Max>
struct _Alloc_traits<_Tp, __allocator<_U, _Pthread_alloc_template<_Max> > >
{
  static const bool _S_instanceless = true;
  typedef simple_alloc<_Tp, _Pthread_alloc_template<_Max> > _Alloc_type;
  typedef __allocator<_Tp, _Pthread_alloc_template<_Max> > allocator_type;
};

template <class _Tp, class _U>
struct _Alloc_traits<_Tp, pthread_allocator<_U> >
{
  static const bool _S_instanceless = true;
  typedef simple_alloc<_Tp, _Pthread_alloc_template<> > _Alloc_type;
  typedef pthread_allocator<_Tp> allocator_type;
};


#endif /* __STL_USE_STD_ALLOCATORS */

__STL_END_NAMESPACE

#endif /* _CPP_EXT_PTHREAD_ALLOC */

// Local Variables:
// mode:C++
// End:
@


1.3
log
@
 * Fold in SGI STL 3.11
 * Uglify names elsewhere to match (s/_T/_Tp); this mostly afflicts valarray
 * Begin optimizing streambuf (bits/streambuf.h)
 * Prep for parsing numerics (bits/locfacets.[h,tcc])
@
text
@@


1.2
log
@SGI snapshot merge ->sgi-stl-3.1
Iostream major surgery
@
text
@d367 1
a367 1
template <class _T>
d373 5
a377 5
  typedef _T*       pointer;
  typedef const _T* const_pointer;
  typedef _T&       reference;
  typedef const _T&  const_reference;
  typedef _T        value_type;
d394 3
a396 2
  _T* allocate(size_type __n, const void* = 0) {
    return __n != 0 ? static_cast<_T*>(_S_Alloc::allocate(__n * sizeof(_T))) : 0;
d401 1
a401 1
    { _S_Alloc::deallocate(__p, __n * sizeof(_T)); }
d404 1
a404 1
    { return size_t(-1) / sizeof(_T); }
d406 2
a407 2
  void construct(pointer __p, const _T& __val) { new(__p) _T(__val); }
  void destroy(pointer _p) { _p->~_T(); }
d431 3
a433 3
template <class _T1, class _T2>
inline bool operator==(const pthread_allocator<_T1>&,
                       const pthread_allocator<_T2>& a2) 
d438 3
a440 3
template <class _T1, class _T2>
inline bool operator!=(const pthread_allocator<_T1>&,
                       const pthread_allocator<_T2>&)
d445 2
a446 2
template <class _T, size_t _Max_size>
struct _Alloc_traits<_T, _Pthread_alloc_template<_Max_size> >
d449 3
a451 2
  typedef simple_alloc<_T, _Pthread_alloc_template<_Max_size> > _Alloc_type;
  typedef __allocator<_T, _Pthread_alloc_template<_Max_size> > allocator_type;
d454 2
a455 2
template <class _T, class _U, size_t _Max_size>
struct _Alloc_traits<_T, __allocator<_U, _Pthread_alloc_template<_Max_size> > >
d458 2
a459 2
  typedef simple_alloc<_T, _Pthread_alloc_template<_Max_size> > _Alloc_type;
  typedef __allocator<_T, _Pthread_alloc_template<_Max_size> > allocator_type;
d462 2
a463 2
template <class _T, class _U>
struct _Alloc_traits<_T, pthread_allocator<_U> >
d466 2
a467 2
  typedef simple_alloc<_T, _Pthread_alloc_template<> > _Alloc_type;
  typedef pthread_allocator<_T> allocator_type;
@


1.1
log
@Initial revision
@
text
@d23 1
a23 1
// it __n thread B.  But this effectively transfers ownership of the memory,
d25 2
a26 2
// __result in __a storage leak if it's done on __a regular basis.
// It can also __result in frequent sharing of
d38 36
a73 3
// Note that this class has nonstatic members.  We instantiate it once
// per thread.
template <bool __dummy>
d76 7
a82 9
private:
  enum {_ALIGN = 8};
  enum {_MAX_BYTES = 128};  // power of 2
  enum {_NFREELISTS = _MAX_BYTES/_ALIGN};

  union _Obj {
        union _Obj * _M_free_list_link;
        char _M_client_data[_ALIGN];    /* The client sees this.        */
  };
d84 1
a84 3
  // Per instance state
  _Obj* volatile _M_free_list[_NFREELISTS]; 
  _Pthread_alloc_template<__dummy>* _M_next; 	// Free list link
d87 1
a87 1
	return (((__bytes) + _ALIGN-1) & ~(_ALIGN - 1));
d90 1
a90 1
	return (((__bytes) + _ALIGN-1)/_ALIGN - 1);
d93 1
a93 6
  // Returns an object of size __n, and optionally adds to size __n free list.
  void* refill(size_t __n);
  // Allocates __a chunk for nobjs of size size.  nobjs may be reduced
  // if it is inconvenient to allocate the requested number.
  static char* _S_chunk_alloc(size_t __size, int& __nobjs);

d97 2
a98 2
  static char* _S_start_free;
  static char* _S_end_free;
d100 1
a100 1
  static _Pthread_alloc_template<__dummy>* _S_free_allocators;
d103 12
a114 12
	// Pthread _S_key under which allocator is stored. 
	// Allocator instances that are currently unclaimed by any thread.
  static void _S_destructor(void* instance);
 
	// Function to be called on thread exit to reclaim allocator
	// instance.
  static _Pthread_alloc_template<__dummy>* _S_new_allocator();
	// Return __a recycled or new allocator instance.
  static _Pthread_alloc_template<__dummy>* _S_get_allocator_instance();
	// ensure that the current thread has an associated
	// allocator instance.
  class _Lock {
d116 2
a117 2
	_Lock () { pthread_mutex_lock(&_S_chunk_allocator_lock); }
	~_Lock () { pthread_mutex_unlock(&_S_chunk_allocator_lock); }
a118 2
  friend class _Lock;

d122 2
a123 1
  _Pthread_alloc_template() : _M_next(0)
d125 3
a127 9
    memset((void*)_M_free_list, 0, _NFREELISTS * sizeof(_Obj*));
  }

  /* __n must be > 0	*/
  static void* allocate(size_t __n)
  {
    _Obj* volatile* __my_free_list;
    _Obj* __RESTRICT __result;
    _Pthread_alloc_template<__dummy>* __a;
d129 2
a130 2
    if (__n > _MAX_BYTES) {
	return(malloc(__n));
d133 3
a135 3
        !(__a = (_Pthread_alloc_template<__dummy>*)
		pthread_getspecific(_S_key))) {
	__a = _S_get_allocator_instance();
d137 1
a137 1
    __my_free_list = __a -> _M_free_list + _S_freelist_index(__n);
d140 2
a141 2
    	void* __r = __a -> refill(_S_round_up(__n));
	return __r;
d143 1
a143 1
    *__my_free_list = __result -> _M_free_list_link;
d148 1
a148 1
  static void deallocate(void* __p, size_t __n)
d150 7
a156 7
    _Obj* __q = (_Obj*)__p;
    _Obj* volatile* __my_free_list;
    _Pthread_alloc_template<__dummy>* __a;

    if (__n > _MAX_BYTES) {
	free(p);
	return;
d159 3
a161 3
        !(__a = (_Pthread_alloc_template<__dummy>*)
		pthread_getspecific(_S_key))) {
	__a = _S_get_allocator_instance();
d163 2
a164 2
    __my_free_list = __a->_M_free_list + _S_freelist_index(__n);
    __q -> _M_free_list_link = *__my_free_list;
d168 1
a168 1
  static void* reallocate(void* __p, size_t __old_sz, size_t __new_sz);
d172 1
a172 1
typedef _Pthread_alloc_template<false> _Pthread_alloc;
d175 2
a176 2
template <bool __dummy>
void _Pthread_alloc_template<__dummy>::_S_destructor(void* __instance)
d178 5
a182 4
    _Pthread_alloc_template<__dummy>* __a =
	(_Pthread_alloc_template<__dummy>*)__instance;
    __a -> _M_next = _S_free_allocators;
    _S_free_allocators = __a;
d185 10
a194 8
template <bool __dummy>
_Pthread_alloc_template<__dummy>*
_Pthread_alloc_template<__dummy>::_S_new_allocator()
{
    if (0 != _S_free_allocators) {
	_Pthread_alloc_template<__dummy>* __result = _S_free_allocators;
	_S_free_allocators = _S_free_allocators -> _M_next;
	return __result;
d196 1
a196 1
	return new _Pthread_alloc_template<__dummy>;
d200 3
a202 3
template <bool __dummy>
_Pthread_alloc_template<__dummy>*
_Pthread_alloc_template<__dummy>::_S_get_allocator_instance()
d204 3
a206 1
    _Pthread_alloc_template<__dummy>* __result;
d208 4
a211 8
    	/*REFERENCED*/
	_Lock lock_instance;
	if (!_S_key_initialized) {
	    if (pthread_key_create(&_S_key, _S_destructor)) {
		abort();  // failed
	    }
	    _S_key_initialized = true;
	}
d213 1
a213 1
    __result = _S_new_allocator();
d218 6
a223 6
/* We allocate memory in large chunks in order to avoid fragmenting	*/
/* the malloc heap too much.						*/
/* We assume that size is properly aligned.				*/
template <bool __dummy>
char *_Pthread_alloc_template<__dummy>
::_S_chunk_alloc(size_t __size, int& __nobjs)
d226 1
a226 1
    char* __result;
d230 1
a230 1
    _Lock __lock_instance;		// Acquire lock for this routine
d235 3
a237 3
	__result = _S_start_free;
	_S_start_free += __total_bytes;
	return(__result);
d239 5
a243 5
	__nobjs = __bytes_left/__size;
	__total_bytes = __size * __nobjs;
	__result = _S_start_free;
	_S_start_free += __total_bytes;
	return(__result);
d245 28
a272 27
	size_t __bytes_to_get = 
	  2 * __total_bytes + _S_round_up(_S_heap_size >> 4);
	// Try to make use of the left-over piece.
	if (__bytes_left > 0) {
	    _Pthread_alloc_template<__dummy>* __a = 
		(_Pthread_alloc_template<__dummy>*)pthread_getspecific(_S_key);
	    _Obj* volatile* __my_free_list =
			__a->_M_free_list + _S_freelist_index(__bytes_left);

            ((_Obj*)_S_start_free) -> _M_free_list_link = *__my_free_list;
            *__my_free_list = (_Obj*)_S_start_free;
	}
#	ifdef _SGI_SOURCE
	  // Try to get memory that's aligned on something like __a
	  // cache line boundary, so as to avoid parceling out
	  // parts of the same line to different threads and thus
	  // possibly different processors.
	  {
	    const int __cache_line_size = 128;  // probable upper bound
	    __bytes_to_get &= ~(__cache_line_size-1);
	    _S_start_free = (char*)memalign(__cache_line_size, __bytes_to_get); 
	    if (0 == _S_start_free) {
	      _S_start_free = (char*)malloc_alloc::allocate(__bytes_to_get);
	    }
	  }
#	else  /* !SGI_SOURCE */
	  _S_start_free = (char*)malloc_alloc::allocate(__bytes_to_get);
d274 2
a275 2
	_S_heap_size += __bytes_to_get;
	_S_end_free = _S_start_free + __bytes_to_get;
d283 6
a288 6
/* Returns an object of size __n, and optionally adds to size __n free list.*/
/* We assume that __n is properly aligned.				*/
/* We hold the allocation lock.						*/
template <bool __dummy>
void* _Pthread_alloc_template<__dummy>
::refill(size_t __n)
d291 5
a295 5
    char*  __chunk = _S_chunk_alloc(__n, __nobjs);
    _Obj* volatile* __my_free_list;
    _Obj* __result;
    _Obj* __current_obj;
    _Obj* __next_obj;
d299 1
a299 1
	return(__chunk);
d301 2
a302 1
    __my_free_list = _M_free_list + _S_freelist_index(__n);
d304 3
a306 3
    /* Build free list in __chunk */
      __result = (_Obj*)__chunk;
      *__my_free_list = __next_obj = (_Obj*)(__chunk + __n);
d308 8
a315 8
	__current_obj = __next_obj;
	__next_obj = (_Obj*)((char*)__next_obj + __n);
	if (__nobjs - 1 == __i) {
	    __current_obj -> _M_free_list_link = 0;
	    break;
	} else {
	    __current_obj -> _M_free_list_link = __next_obj;
	}
d320 3
a322 3
template <bool __dummy>
void* _Pthread_alloc_template<__dummy>
::reallocate(void* __p, size_t __old_sz, size_t __new_sz)
d327 3
a329 2
    if (__old_sz > _MAX_BYTES && __new_sz > _MAX_BYTES) {
	return(realloc(__p, __new_sz));
d339 3
a341 3
template <bool __dummy>
_Pthread_alloc_template<__dummy>*
_Pthread_alloc_template<__dummy>::_S_free_allocators = 0;
d343 2
a344 2
template <bool __dummy>
pthread_key_t _Pthread_alloc_template<__dummy>::_S_key;
d346 2
a347 2
template <bool __dummy>
bool _Pthread_alloc_template<__dummy>::_S_key_initialized = false;
d349 2
a350 2
template <bool __dummy>
pthread_mutex_t _Pthread_alloc_template<__dummy>::_S_chunk_allocator_lock
d353 2
a354 2
template <bool __dummy>
char* _Pthread_alloc_template<__dummy>
d357 2
a358 2
template <bool __dummy>
char* _Pthread_alloc_template<__dummy>
d361 2
a362 2
template <bool __dummy>
size_t _Pthread_alloc_template<__dummy>
d364 106
@


1.1.1.1
log
@everything renamed
@
text
@@

