📄 stl_alloc.h
字号:
static char *end_free; static size_t heap_size;# ifdef __STL_SGI_THREADS static volatile unsigned long __node_allocator_lock; static void __lock(volatile unsigned long *); static inline void __unlock(volatile unsigned long *);# endif# ifdef __STL_PTHREADS static pthread_mutex_t __node_allocator_lock;# endif# ifdef __STL_WIN32THREADS static CRITICAL_SECTION __node_allocator_lock; static bool __node_allocator_lock_initialized; public: __default_alloc_template() { // This assumes the first constructor is called before threads // are started. if (!__node_allocator_lock_initialized) { InitializeCriticalSection(&__node_allocator_lock); __node_allocator_lock_initialized = true; } } private:# endif class lock { public: lock() { __NODE_ALLOCATOR_LOCK; } ~lock() { __NODE_ALLOCATOR_UNLOCK; } }; friend class lock;public: /* n must be > 0 */ static void * allocate(size_t n) { obj * __VOLATILE * my_free_list; obj * __RESTRICT result; if (n > (size_t) __MAX_BYTES) { return(malloc_alloc::allocate(n)); } my_free_list = free_list + FREELIST_INDEX(n); // Acquire the lock here with a constructor call. // This ensures that it is released in exit or during stack // unwinding.# ifndef _NOTHREADS /*REFERENCED*/ lock lock_instance;# endif result = *my_free_list; if (result == 0) { void *r = refill(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; if (n > (size_t) __MAX_BYTES) { malloc_alloc::deallocate(p, n); return; } my_free_list = free_list + FREELIST_INDEX(n); // acquire lock# ifndef _NOTHREADS /*REFERENCED*/ lock lock_instance;# endif /* _NOTHREADS */ q -> free_list_link = *my_free_list; *my_free_list = q; // lock is released here } static void * reallocate(void *p, size_t old_sz, size_t new_sz);} ;typedef __default_alloc_template<__NODE_ALLOCATOR_THREADS, 0> alloc;typedef __default_alloc_template<false, 0> single_client_alloc;/* We allocate memory in large chunks in order to avoid fragmenting *//* the malloc heap too much. *//* We assume that size is properly aligned. *//* We hold the allocation lock. */template <bool threads, int inst>char*__default_alloc_template<threads, inst>::chunk_alloc(size_t size, int& nobjs){ char * result; size_t total_bytes = size * nobjs; size_t bytes_left = end_free - start_free; if (bytes_left >= total_bytes) { result = start_free; start_free += total_bytes; return(result); } else if (bytes_left >= size) { nobjs = bytes_left/size; total_bytes = size * nobjs; result = start_free; start_free += total_bytes; return(result); } else { size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4); // Try to make use of the left-over piece. if (bytes_left > 0) { obj * __VOLATILE * my_free_list = free_list + FREELIST_INDEX(bytes_left); ((obj *)start_free) -> free_list_link = *my_free_list; *my_free_list = (obj *)start_free; } start_free = (char *)malloc(bytes_to_get); if (0 == start_free) { int i; obj * __VOLATILE * my_free_list, *p; // Try to make do with what we have. That can't // hurt. We do not try smaller requests, since that tends // to result in disaster on multi-process machines. for (i = size; i <= __MAX_BYTES; i += __ALIGN) { my_free_list = free_list + FREELIST_INDEX(i); p = *my_free_list; if (0 != p) { *my_free_list = p -> free_list_link; start_free = (char *)p; end_free = start_free + i; return(chunk_alloc(size, nobjs)); // Any leftover piece will eventually make it to the // right free list. } } end_free = 0; // In case of exception. start_free = (char *)malloc_alloc::allocate(bytes_to_get); // This should either throw an // exception or remedy the situation. Thus we assume it // succeeded. } heap_size += bytes_to_get; end_free = start_free + bytes_to_get; return(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 <bool threads, int inst>void* __default_alloc_template<threads, inst>::refill(size_t n){ int nobjs = 20; char * chunk = 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 + 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 <bool threads, int inst>void*__default_alloc_template<threads, inst>::reallocate(void *p, size_t old_sz, size_t new_sz){ void * result; size_t copy_sz; if (old_sz > (size_t) __MAX_BYTES && new_sz > (size_t) __MAX_BYTES) { return(realloc(p, new_sz)); } if (ROUND_UP(old_sz) == 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);}#ifdef __STL_PTHREADS template <bool threads, int inst> pthread_mutex_t __default_alloc_template<threads, inst>::__node_allocator_lock = PTHREAD_MUTEX_INITIALIZER;#endif#ifdef __STL_WIN32THREADS template <bool threads, int inst> CRITICAL_SECTION __default_alloc_template<threads, inst>::__node_allocator_lock; template <bool threads, int inst> bool __default_alloc_template<threads, inst>::__node_allocator_lock_initialized = false;#endif#ifdef __STL_SGI_THREADS__STL_END_NAMESPACE#include <mutex.h>#include <time.h>__STL_BEGIN_NAMESPACE// Somewhat generic lock implementations. We need only test-and-set// and some way to sleep. These should work with both SGI pthreads// and sproc threads. They may be useful on other systems.template <bool threads, int inst>volatile unsigned long__default_alloc_template<threads, inst>::__node_allocator_lock = 0;#if __mips < 3 || !(defined (_ABIN32) || defined(_ABI64)) || defined(__GNUC__)# define __test_and_set(l,v) test_and_set(l,v)#endiftemplate <bool threads, int inst>void __default_alloc_template<threads, inst>::__lock(volatile unsigned long *lock){ const unsigned low_spin_max = 30; // spin cycles if we suspect uniprocessor const unsigned high_spin_max = 1000; // spin cycles for multiprocessor static unsigned spin_max = low_spin_max; unsigned my_spin_max; static unsigned last_spins = 0; unsigned my_last_spins; static struct timespec ts = {0, 1000}; unsigned junk;# define __ALLOC_PAUSE junk *= junk; junk *= junk; junk *= junk; junk *= junk int i; if (!__test_and_set((unsigned long *)lock, 1)) { return; } my_spin_max = spin_max; my_last_spins = last_spins; for (i = 0; i < my_spin_max; i++) { if (i < my_last_spins/2 || *lock) { __ALLOC_PAUSE; continue; } if (!__test_and_set((unsigned long *)lock, 1)) { // got it! // Spinning worked. Thus we're probably not being scheduled // against the other process with which we were contending. // Thus it makes sense to spin longer the next time. last_spins = i; spin_max = high_spin_max; return; } } // We are probably being scheduled against the other process. Sleep. spin_max = low_spin_max; for (;;) { if (!__test_and_set((unsigned long *)lock, 1)) { return; } nanosleep(&ts, 0); }}template <bool threads, int inst>inline void__default_alloc_template<threads, inst>::__unlock(volatile unsigned long *lock){# if defined(__GNUC__) && __mips >= 3 asm("sync"); *lock = 0;# elif __mips >= 3 && (defined (_ABIN32) || defined(_ABI64)) __lock_release(lock);# else *lock = 0; // This is not sufficient on many multiprocessors, since // writes to protected variables and the lock may be reordered.# endif}#endiftemplate <bool threads, int inst>char *__default_alloc_template<threads, inst>::start_free = 0;template <bool threads, int inst>char *__default_alloc_template<threads, inst>::end_free = 0;template <bool threads, int inst>size_t __default_alloc_template<threads, inst>::heap_size = 0;template <bool threads, int inst>__default_alloc_template<threads, inst>::obj * __VOLATILE__default_alloc_template<threads, inst> ::free_list[# ifdef __SUNPRO_CC __NFREELISTS# else __default_alloc_template<threads, inst>::__NFREELISTS# endif] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };// The 16 zeros are necessary to make version 4.1 of the SunPro// compiler happy. Otherwise it appears to allocate too little// space for the array.# ifdef __STL_WIN32THREADS // Create one to get critical section initialized. // We do this onece per file, but only the first constructor // does anything. static alloc __node_allocator_dummy_instance;# endif#endif /* ! __USE_MALLOC */#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)#pragma reset woff 1174#endif__STL_END_NAMESPACE#undef __PRIVATE#endif /* __SGI_STL_INTERNAL_ALLOC_H */// Local Variables:// mode:C++// End:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -