2 * Copyright (c) 1996-1997
3 * Silicon Graphics Computer Systems, Inc.
5 * Permission to use, copy, modify, distribute and sell this software
6 * and its documentation for any purpose is hereby granted without fee,
7 * provided that the above copyright notice appear in all copies and
8 * that both that copyright notice and this permission notice appear
9 * in supporting documentation. Silicon Graphics makes no
10 * representations about the suitability of this software for any
11 * purpose. It is provided "as is" without express or implied warranty.
17 #include <stl_config.h>
20 # define __PRIVATE public
21 // Extra access restrictions prevent us from really making some things
24 # define __PRIVATE private
27 #ifdef __STL_STATIC_TEMPLATE_MEMBER_BUG
32 // This implements some standard node allocators. These are
33 // NOT the same as the allocators in the C++ draft standard or in
34 // in the original STL. They do not encapsulate different pointer
35 // types; indeed we assume that there is only one pointer type.
36 // The allocation primitives are intended to allocate individual objects,
37 // not larger arenas as with the original STL allocators.
41 # define __THROW_BAD_ALLOC throw bad_alloc
42 #elif !defined(__THROW_BAD_ALLOC)
43 # include <iostream.h>
44 # define __THROW_BAD_ALLOC cerr << "out of memory" << endl; exit(1)
48 # define __ALLOC alloc
50 #ifdef __STL_WIN32THREADS
52 // This must precede stl_config.h
63 #if !defined(_PTHREADS) && !defined(_NOTHREADS) \
64 && !defined(__STL_SGI_THREADS) && !defined(__STL_WIN32THREADS)
70 // This is dubious, since this is likely to be a high contention
71 // lock. Performance may not be adequate.
73 # define __NODE_ALLOCATOR_LOCK \
74 if (threads) pthread_mutex_lock(&__node_allocator_lock)
75 # define __NODE_ALLOCATOR_UNLOCK \
76 if (threads) pthread_mutex_unlock(&__node_allocator_lock)
77 # define __NODE_ALLOCATOR_THREADS true
78 # define __VOLATILE volatile // Needed at -O3 on SGI
80 # ifdef __STL_WIN32THREADS
81 // The lock needs to be initialized by constructing an allocator
82 // objects of the right type. We do that here explicitly for alloc.
83 # define __NODE_ALLOCATOR_LOCK \
84 EnterCriticalSection(&__node_allocator_lock)
85 # define __NODE_ALLOCATOR_UNLOCK \
86 LeaveCriticalSection(&__node_allocator_lock)
87 # define __NODE_ALLOCATOR_THREADS true
88 # define __VOLATILE volatile // may not be needed
89 # endif /* WIN32THREADS */
90 # ifdef __STL_SGI_THREADS
91 // This should work without threads, with sproc threads, or with
92 // pthreads. It is suboptimal in all cases.
93 // It is unlikely to even compile on nonSGI machines.
95 # define __NODE_ALLOCATOR_LOCK if (threads && __us_rsthread_malloc) \
96 { __lock(&__node_allocator_lock); }
97 # define __NODE_ALLOCATOR_UNLOCK if (threads && __us_rsthread_malloc) \
98 { __unlock(&__node_allocator_lock); }
99 # define __NODE_ALLOCATOR_THREADS true
100 # define __VOLATILE volatile // Needed at -O3 on SGI
104 # define __NODE_ALLOCATOR_LOCK
105 # define __NODE_ALLOCATOR_UNLOCK
106 # define __NODE_ALLOCATOR_THREADS false
110 #if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
111 #pragma set woff 1174
114 // Malloc-based allocator. Typically slower than default alloc below.
115 // Typically thread-safe and more storage efficient.
116 #ifdef __STL_STATIC_TEMPLATE_MEMBER_BUG
117 # ifdef __DECLARE_GLOBALS_HERE
118 void (* __malloc_alloc_oom_handler)() = 0;
119 // g++ 2.7.2 does not handle static template data members.
121 extern void (* __malloc_alloc_oom_handler)();
126 class __malloc_alloc_template {
130 static void *oom_malloc(size_t);
132 static void *oom_realloc(void *, size_t);
134 #ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
135 static void (* __malloc_alloc_oom_handler)();
140 static void * allocate(size_t n)
142 void *result = malloc(n);
143 if (0 == result) result = oom_malloc(n);
147 static void deallocate(void *p, size_t /* n */)
152 static void * reallocate(void *p, size_t /* old_sz */, size_t new_sz)
154 void * result = realloc(p, new_sz);
155 if (0 == result) result = oom_realloc(p, new_sz);
159 static void (* set_malloc_handler(void (*f)()))()
161 void (* old)() = __malloc_alloc_oom_handler;
162 __malloc_alloc_oom_handler = f;
168 // malloc_alloc out-of-memory handling
170 #ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
172 void (* __malloc_alloc_template<inst>::__malloc_alloc_oom_handler)() = 0;
176 void * __malloc_alloc_template<inst>::oom_malloc(size_t n)
178 void (* my_malloc_handler)();
182 my_malloc_handler = __malloc_alloc_oom_handler;
183 if (0 == my_malloc_handler) { __THROW_BAD_ALLOC; }
184 (*my_malloc_handler)();
186 if (result) return(result);
191 void * __malloc_alloc_template<inst>::oom_realloc(void *p, size_t n)
193 void (* my_malloc_handler)();
197 my_malloc_handler = __malloc_alloc_oom_handler;
198 if (0 == my_malloc_handler) { __THROW_BAD_ALLOC; }
199 (*my_malloc_handler)();
200 result = realloc(p, n);
201 if (result) return(result);
205 typedef __malloc_alloc_template<0> malloc_alloc;
207 template<class T, class Alloc>
211 static T *allocate(size_t n)
212 { return 0 == n? 0 : (T*) Alloc::allocate(n * sizeof (T)); }
213 static T *allocate(void)
214 { return (T*) Alloc::allocate(sizeof (T)); }
215 static void deallocate(T *p, size_t n)
216 { if (0 != n) Alloc::deallocate(p, n * sizeof (T)); }
217 static void deallocate(T *p)
218 { Alloc::deallocate(p, sizeof (T)); }
221 // Allocator adaptor to check size arguments for debugging.
222 // Reports errors using assert. Checking can be disabled with
223 // NDEBUG, but it's far better to just use the underlying allocator
224 // instead when no checking is desired.
225 // There is some evidence that this can confuse Purify.
226 template <class Alloc>
231 enum {extra = 8}; // Size of space used to store size. Note
232 // that this must be large enough to preserve
237 static void * allocate(size_t n)
239 char *result = (char *)Alloc::allocate(n + extra);
240 *(size_t *)result = n;
241 return result + extra;
244 static void deallocate(void *p, size_t n)
246 char * real_p = (char *)p - extra;
247 assert(*(size_t *)real_p == n);
248 Alloc::deallocate(real_p, n + extra);
251 static void * reallocate(void *p, size_t old_sz, size_t new_sz)
253 char * real_p = (char *)p - extra;
254 assert(*(size_t *)real_p == old_sz);
255 char * result = (char *)
256 Alloc::reallocate(real_p, old_sz + extra, new_sz + extra);
257 *(size_t *)result = new_sz;
258 return result + extra;
267 typedef malloc_alloc alloc;
268 typedef malloc_alloc single_client_alloc;
273 // Default node allocator.
274 // With a reasonable compiler, this should be roughly as fast as the
275 // original STL class-specific allocators, but with less fragmentation.
276 // Default_alloc_template parameters are experimental and MAY
277 // DISAPPEAR in the future. Clients should just use alloc for now.
279 // Important implementation properties:
280 // 1. If the client request an object of size > __MAX_BYTES, the resulting
281 // object will be obtained directly from malloc.
282 // 2. In all other cases, we allocate an object of size exactly
283 // ROUND_UP(requested_size). Thus the client has enough size
284 // information that we can return the object to the proper free list
285 // without permanently losing part of the object.
288 // The first template parameter specifies whether more than one thread
289 // may use this allocator. It is safe to allocate an object from
290 // one instance of a default_alloc and deallocate it with another
291 // one. This effectively transfers its ownership to the second one.
292 // This may have undesirable effects on reference locality.
293 // The second parameter is unreferenced and serves only to allow the
294 // creation of multiple default_alloc instances.
295 // Node that containers built on different allocator instances have
296 // different types, limiting the utility of this approach.
298 // breaks if we make these template class members:
300 enum {__MAX_BYTES = 128};
301 enum {__NFREELISTS = __MAX_BYTES/__ALIGN};
304 template <bool threads, int inst>
305 class __default_alloc_template {
308 // Really we should use static const int x = N
309 // instead of enum { x = N }, but few compilers accept the former.
312 enum {__MAX_BYTES = 128};
313 enum {__NFREELISTS = __MAX_BYTES/__ALIGN};
315 static size_t ROUND_UP(size_t bytes) {
316 return (((bytes) + __ALIGN-1) & ~(__ALIGN - 1));
320 union obj * free_list_link;
321 char client_data[1]; /* The client sees this. */
325 static obj * __VOLATILE free_list[];
326 // Specifying a size results in duplicate def for 4.1
328 static obj * __VOLATILE free_list[__NFREELISTS];
330 static size_t FREELIST_INDEX(size_t bytes) {
331 return (((bytes) + __ALIGN-1)/__ALIGN - 1);
334 // Returns an object of size n, and optionally adds to size n free list.
335 static void *refill(size_t n);
336 // Allocates a chunk for nobjs of size size. nobjs may be reduced
337 // if it is inconvenient to allocate the requested number.
338 static char *chunk_alloc(size_t size, int &nobjs);
340 // Chunk allocation state.
341 static char *start_free;
342 static char *end_free;
343 static size_t heap_size;
345 # ifdef __STL_SGI_THREADS
346 static volatile unsigned long __node_allocator_lock;
347 static void __lock(volatile unsigned long *);
348 static inline void __unlock(volatile unsigned long *);
352 static pthread_mutex_t __node_allocator_lock;
355 # ifdef __STL_WIN32THREADS
356 static CRITICAL_SECTION __node_allocator_lock;
357 static bool __node_allocator_lock_initialized;
360 __default_alloc_template() {
361 // This assumes the first constructor is called before threads
363 if (!__node_allocator_lock_initialized) {
364 InitializeCriticalSection(&__node_allocator_lock);
365 __node_allocator_lock_initialized = true;
373 lock() { __NODE_ALLOCATOR_LOCK; }
374 ~lock() { __NODE_ALLOCATOR_UNLOCK; }
381 static void * allocate(size_t n)
383 obj * __VOLATILE * my_free_list;
384 obj * __RESTRICT result;
386 if (n > __MAX_BYTES) {
387 return(malloc_alloc::allocate(n));
389 my_free_list = free_list + FREELIST_INDEX(n);
390 // Acquire the lock here with a constructor call.
391 // This ensures that it is released in exit or during stack
395 result = *my_free_list;
397 void *r = refill(ROUND_UP(n));
400 *my_free_list = result -> free_list_link;
405 static void deallocate(void *p, size_t n)
408 obj * __VOLATILE * my_free_list;
410 if (n > __MAX_BYTES) {
411 malloc_alloc::deallocate(p, n);
414 my_free_list = free_list + FREELIST_INDEX(n);
418 q -> free_list_link = *my_free_list;
420 // lock is released here
423 static void * reallocate(void *p, size_t old_sz, size_t new_sz);
427 typedef __default_alloc_template<__NODE_ALLOCATOR_THREADS, 0> alloc;
428 typedef __default_alloc_template<false, 0> single_client_alloc;
432 /* We allocate memory in large chunks in order to avoid fragmenting */
433 /* the malloc heap too much. */
434 /* We assume that size is properly aligned. */
435 /* We hold the allocation lock. */
436 template <bool threads, int inst>
438 __default_alloc_template<threads, inst>::chunk_alloc(size_t size, int& nobjs)
441 size_t total_bytes = size * nobjs;
442 size_t bytes_left = end_free - start_free;
444 if (bytes_left >= total_bytes) {
446 start_free += total_bytes;
448 } else if (bytes_left >= size) {
449 nobjs = bytes_left/size;
450 total_bytes = size * nobjs;
452 start_free += total_bytes;
455 size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4);
456 // Try to make use of the left-over piece.
457 if (bytes_left > 0) {
458 obj * __VOLATILE * my_free_list =
459 free_list + FREELIST_INDEX(bytes_left);
461 ((obj *)start_free) -> free_list_link = *my_free_list;
462 *my_free_list = (obj *)start_free;
464 start_free = (char *)malloc(bytes_to_get);
465 if (0 == start_free) {
467 obj * __VOLATILE * my_free_list, *p;
468 // Try to make do with what we have. That can't
469 // hurt. We do not try smaller requests, since that tends
470 // to result in disaster on multi-process machines.
471 for (i = size; i <= __MAX_BYTES; i += __ALIGN) {
472 my_free_list = free_list + FREELIST_INDEX(i);
475 *my_free_list = p -> free_list_link;
476 start_free = (char *)p;
477 end_free = start_free + i;
478 return(chunk_alloc(size, nobjs));
479 // Any leftover piece will eventually make it to the
483 start_free = (char *)malloc_alloc::allocate(bytes_to_get);
484 // This should either throw an
485 // exception or remedy the situation. Thus we assume it
488 heap_size += bytes_to_get;
489 end_free = start_free + bytes_to_get;
490 return(chunk_alloc(size, nobjs));
495 /* Returns an object of size n, and optionally adds to size n free list.*/
496 /* We assume that n is properly aligned. */
497 /* We hold the allocation lock. */
498 template <bool threads, int inst>
499 void* __default_alloc_template<threads, inst>::refill(size_t n)
502 char * chunk = chunk_alloc(n, nobjs);
503 obj * __VOLATILE * my_free_list;
505 obj * current_obj, * next_obj;
508 if (1 == nobjs) return(chunk);
509 my_free_list = free_list + FREELIST_INDEX(n);
511 /* Build free list in chunk */
512 result = (obj *)chunk;
513 *my_free_list = next_obj = (obj *)(chunk + n);
515 current_obj = next_obj;
516 next_obj = (obj *)((char *)next_obj + n);
517 if (nobjs - 1 == i) {
518 current_obj -> free_list_link = 0;
521 current_obj -> free_list_link = next_obj;
527 template <bool threads, int inst>
529 __default_alloc_template<threads, inst>::reallocate(void *p,
536 if (old_sz > __MAX_BYTES && new_sz > __MAX_BYTES) {
537 return(realloc(p, new_sz));
539 if (ROUND_UP(old_sz) == ROUND_UP(new_sz)) return(p);
540 result = allocate(new_sz);
541 copy_sz = new_sz > old_sz? old_sz : new_sz;
542 memcpy(result, p, copy_sz);
543 deallocate(p, old_sz);
548 template <bool threads, int inst>
550 __default_alloc_template<threads, inst>::__node_allocator_lock
551 = PTHREAD_MUTEX_INITIALIZER;
554 #ifdef __STL_WIN32THREADS
555 template <bool threads, int inst> CRITICAL_SECTION
556 __default_alloc_template<threads, inst>::__node_allocator_lock;
558 template <bool threads, int inst> bool
559 __default_alloc_template<threads, inst>::__node_allocator_lock_initialized
563 #ifdef __STL_SGI_THREADS
566 // Somewhat generic lock implementations. We need only test-and-set
567 // and some way to sleep. These should work with both SGI pthreads
568 // and sproc threads. They may be useful on other systems.
569 template <bool threads, int inst>
570 volatile unsigned long
571 __default_alloc_template<threads, inst>::__node_allocator_lock = 0;
573 #if __mips < 3 || !(defined (_ABIN32) || defined(_ABI64)) || defined(__GNUC__)
574 # define __test_and_set(l,v) test_and_set(l,v)
577 template <bool threads, int inst>
579 __default_alloc_template<threads, inst>::__lock(volatile unsigned long *lock)
581 const unsigned low_spin_max = 30; // spin cycles if we suspect uniprocessor
582 const unsigned high_spin_max = 1000; // spin cycles for multiprocessor
583 static unsigned spin_max = low_spin_max;
584 unsigned my_spin_max;
585 static unsigned last_spins = 0;
586 unsigned my_last_spins;
587 static struct timespec ts = {0, 1000};
589 # define __ALLOC_PAUSE junk *= junk; junk *= junk; junk *= junk; junk *= junk
592 if (!__test_and_set((unsigned long *)lock, 1)) {
595 my_spin_max = spin_max;
596 my_last_spins = last_spins;
597 for (i = 0; i < my_spin_max; i++) {
598 if (i < my_last_spins/2 || *lock) {
602 if (!__test_and_set((unsigned long *)lock, 1)) {
604 // Spinning worked. Thus we're probably not being scheduled
605 // against the other process with which we were contending.
606 // Thus it makes sense to spin longer the next time.
608 spin_max = high_spin_max;
612 // We are probably being scheduled against the other process. Sleep.
613 spin_max = low_spin_max;
615 if (!__test_and_set((unsigned long *)lock, 1)) {
622 template <bool threads, int inst>
624 __default_alloc_template<threads, inst>::__unlock(volatile unsigned long *lock)
626 # if defined(__GNUC__) && __mips >= 3
629 # elif __mips >= 3 && (defined (_ABIN32) || defined(_ABI64))
630 __lock_release(lock);
633 // This is not sufficient on many multiprocessors, since
634 // writes to protected variables and the lock may be reordered.
639 template <bool threads, int inst>
640 char *__default_alloc_template<threads, inst>::start_free = 0;
642 template <bool threads, int inst>
643 char *__default_alloc_template<threads, inst>::end_free = 0;
645 template <bool threads, int inst>
646 size_t __default_alloc_template<threads, inst>::heap_size = 0;
648 template <bool threads, int inst>
649 __default_alloc_template<threads, inst>::obj * __VOLATILE
650 __default_alloc_template<threads, inst> ::free_list[
654 __default_alloc_template<threads, inst>::__NFREELISTS
656 ] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
657 // The 16 zeros are necessary to make version 4.1 of the SunPro
658 // compiler happy. Otherwise it appears to allocate too little
659 // space for the array.
661 # ifdef __STL_WIN32THREADS
662 // Create one to get critical section initialized.
663 // We do this onece per file, but only the first constructor
665 static alloc __node_allocator_dummy_instance;
668 #endif /* ! __USE_MALLOC */
670 #if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
671 #pragma reset woff 1174
674 #endif /* __NODE_ALLOC_H */