OSDN Git Service

Initial revision
[pf3gnuchains/gcc-fork.git] / libstdc++ / stl / alloc.h
1 /*
2  * Copyright (c) 1996-1997
3  * Silicon Graphics Computer Systems, Inc.
4  *
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.
12  */
13
14 #ifndef __ALLOC_H
15 #define __ALLOC_H
16
17 #include <stl_config.h>
18
19 #ifdef __SUNPRO_CC
20 #  define __PRIVATE public
21    // Extra access restrictions prevent us from really making some things
22    // private.
23 #else
24 #  define __PRIVATE private
25 #endif
26
27 #ifdef __STL_STATIC_TEMPLATE_MEMBER_BUG
28 #  define __USE_MALLOC
29 #endif
30
31
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.
38
39 #if 0
40 #   include <new>
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)
45 #endif
46
47 #ifndef __ALLOC
48 #   define __ALLOC alloc
49 #endif
50 #ifdef __STL_WIN32THREADS
51 #   include <windows.h>
52 //  This must precede stl_config.h
53 #endif
54
55 #include <stddef.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <assert.h>
59 #ifndef __RESTRICT
60 #  define __RESTRICT
61 #endif
62
63 #if !defined(_PTHREADS) && !defined(_NOTHREADS) \
64  && !defined(__STL_SGI_THREADS) && !defined(__STL_WIN32THREADS)
65 #   define _NOTHREADS
66 #endif
67
68 # ifdef _PTHREADS
69     // POSIX Threads
70     // This is dubious, since this is likely to be a high contention
71     // lock.   Performance may not be adequate.
72 #   include <pthread.h>
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
79 # endif
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.
94 #   include <malloc.h>
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
101 # endif
102 # ifdef _NOTHREADS
103 //  Thread-unsafe
104 #   define __NODE_ALLOCATOR_LOCK
105 #   define __NODE_ALLOCATOR_UNLOCK
106 #   define __NODE_ALLOCATOR_THREADS false
107 #   define __VOLATILE
108 # endif
109
110 #if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
111 #pragma set woff 1174
112 #endif
113
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.
120 # else
121     extern void (* __malloc_alloc_oom_handler)();
122 # endif
123 #endif
124
125 template <int inst>
126 class __malloc_alloc_template {
127
128 private:
129
130 static void *oom_malloc(size_t);
131
132 static void *oom_realloc(void *, size_t);
133
134 #ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
135     static void (* __malloc_alloc_oom_handler)();
136 #endif
137
138 public:
139
140 static void * allocate(size_t n)
141 {
142     void *result = malloc(n);
143     if (0 == result) result = oom_malloc(n);
144     return result;
145 }
146
147 static void deallocate(void *p, size_t /* n */)
148 {
149     free(p);
150 }
151
152 static void * reallocate(void *p, size_t /* old_sz */, size_t new_sz)
153 {
154     void * result = realloc(p, new_sz);
155     if (0 == result) result = oom_realloc(p, new_sz);
156     return result;
157 }
158
159 static void (* set_malloc_handler(void (*f)()))()
160 {
161     void (* old)() = __malloc_alloc_oom_handler;
162     __malloc_alloc_oom_handler = f;
163     return(old);
164 }
165
166 };
167
168 // malloc_alloc out-of-memory handling
169
170 #ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
171 template <int inst>
172 void (* __malloc_alloc_template<inst>::__malloc_alloc_oom_handler)() = 0;
173 #endif
174
175 template <int inst>
176 void * __malloc_alloc_template<inst>::oom_malloc(size_t n)
177 {
178     void (* my_malloc_handler)();
179     void *result;
180
181     for (;;) {
182         my_malloc_handler = __malloc_alloc_oom_handler;
183         if (0 == my_malloc_handler) { __THROW_BAD_ALLOC; }
184         (*my_malloc_handler)();
185         result = malloc(n);
186         if (result) return(result);
187     }
188 }
189
190 template <int inst>
191 void * __malloc_alloc_template<inst>::oom_realloc(void *p, size_t n)
192 {
193     void (* my_malloc_handler)();
194     void *result;
195
196     for (;;) {
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);
202     }
203 }
204
205 typedef __malloc_alloc_template<0> malloc_alloc;
206
207 template<class T, class Alloc>
208 class simple_alloc {
209
210 public:
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)); }
219 };
220
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>
227 class debug_alloc {
228
229 private:
230
231 enum {extra = 8};       // Size of space used to store size.  Note
232                         // that this must be large enough to preserve
233                         // alignment.
234
235 public:
236
237 static void * allocate(size_t n)
238 {
239     char *result = (char *)Alloc::allocate(n + extra);
240     *(size_t *)result = n;
241     return result + extra;
242 }
243
244 static void deallocate(void *p, size_t n)
245 {
246     char * real_p = (char *)p - extra;
247     assert(*(size_t *)real_p == n);
248     Alloc::deallocate(real_p, n + extra);
249 }
250
251 static void * reallocate(void *p, size_t old_sz, size_t new_sz)
252 {
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;
259 }
260
261
262 };
263
264
265 # ifdef __USE_MALLOC
266
267 typedef malloc_alloc alloc;
268 typedef malloc_alloc single_client_alloc;
269
270 # else
271
272
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.
278 //
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.
286 //
287
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.
297 #ifdef __SUNPRO_CC
298 // breaks if we make these template class members:
299   enum {__ALIGN = 8};
300   enum {__MAX_BYTES = 128};
301   enum {__NFREELISTS = __MAX_BYTES/__ALIGN};
302 #endif
303
304 template <bool threads, int inst>
305 class __default_alloc_template {
306
307 private:
308   // Really we should use static const int x = N
309   // instead of enum { x = N }, but few compilers accept the former.
310 # ifndef __SUNPRO_CC
311     enum {__ALIGN = 8};
312     enum {__MAX_BYTES = 128};
313     enum {__NFREELISTS = __MAX_BYTES/__ALIGN};
314 # endif
315   static size_t ROUND_UP(size_t bytes) {
316         return (((bytes) + __ALIGN-1) & ~(__ALIGN - 1));
317   }
318 __PRIVATE:
319   union obj {
320         union obj * free_list_link;
321         char client_data[1];    /* The client sees this.        */
322   };
323 private:
324 # ifdef __SUNPRO_CC
325     static obj * __VOLATILE free_list[]; 
326         // Specifying a size results in duplicate def for 4.1
327 # else
328     static obj * __VOLATILE free_list[__NFREELISTS]; 
329 # endif
330   static  size_t FREELIST_INDEX(size_t bytes) {
331         return (((bytes) + __ALIGN-1)/__ALIGN - 1);
332   }
333
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);
339
340   // Chunk allocation state.
341   static char *start_free;
342   static char *end_free;
343   static size_t heap_size;
344
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 *);
349 # endif
350
351 # ifdef _PTHREADS
352     static pthread_mutex_t __node_allocator_lock;
353 # endif
354
355 # ifdef __STL_WIN32THREADS
356     static CRITICAL_SECTION __node_allocator_lock;
357     static bool __node_allocator_lock_initialized;
358
359   public:
360     __default_alloc_template() {
361         // This assumes the first constructor is called before threads
362         // are started.
363         if (!__node_allocator_lock_initialized) {
364             InitializeCriticalSection(&__node_allocator_lock);
365             __node_allocator_lock_initialized = true;
366         }
367     }
368   private:
369 # endif
370
371     class lock {
372         public:
373             lock() { __NODE_ALLOCATOR_LOCK; }
374             ~lock() { __NODE_ALLOCATOR_UNLOCK; }
375     };
376     friend class lock;
377
378 public:
379
380   /* n must be > 0      */
381   static void * allocate(size_t n)
382   {
383     obj * __VOLATILE * my_free_list;
384     obj * __RESTRICT result;
385
386     if (n > __MAX_BYTES) {
387         return(malloc_alloc::allocate(n));
388     }
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
392     // unwinding.
393         /*REFERENCED*/
394         lock lock_instance;
395     result = *my_free_list;
396     if (result == 0) {
397         void *r = refill(ROUND_UP(n));
398         return r;
399     }
400     *my_free_list = result -> free_list_link;
401     return (result);
402   };
403
404   /* p may not be 0 */
405   static void deallocate(void *p, size_t n)
406   {
407     obj *q = (obj *)p;
408     obj * __VOLATILE * my_free_list;
409
410     if (n > __MAX_BYTES) {
411         malloc_alloc::deallocate(p, n);
412         return;
413     }
414     my_free_list = free_list + FREELIST_INDEX(n);
415     // acquire lock
416         /*REFERENCED*/
417         lock lock_instance;
418     q -> free_list_link = *my_free_list;
419     *my_free_list = q;
420     // lock is released here
421   }
422
423   static void * reallocate(void *p, size_t old_sz, size_t new_sz);
424
425 } ;
426
427 typedef __default_alloc_template<__NODE_ALLOCATOR_THREADS, 0> alloc;
428 typedef __default_alloc_template<false, 0> single_client_alloc;
429
430
431
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>
437 char*
438 __default_alloc_template<threads, inst>::chunk_alloc(size_t size, int& nobjs)
439 {
440     char * result;
441     size_t total_bytes = size * nobjs;
442     size_t bytes_left = end_free - start_free;
443
444     if (bytes_left >= total_bytes) {
445         result = start_free;
446         start_free += total_bytes;
447         return(result);
448     } else if (bytes_left >= size) {
449         nobjs = bytes_left/size;
450         total_bytes = size * nobjs;
451         result = start_free;
452         start_free += total_bytes;
453         return(result);
454     } else {
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);
460
461             ((obj *)start_free) -> free_list_link = *my_free_list;
462             *my_free_list = (obj *)start_free;
463         }
464         start_free = (char *)malloc(bytes_to_get);
465         if (0 == start_free) {
466             int i;
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);
473                 p = *my_free_list;
474                 if (0 != p) {
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
480                     // right free list.
481                 }
482             }
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
486             // succeeded.
487         }
488         heap_size += bytes_to_get;
489         end_free = start_free + bytes_to_get;
490         return(chunk_alloc(size, nobjs));
491     }
492 }
493
494
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)
500 {
501     int nobjs = 20;
502     char * chunk = chunk_alloc(n, nobjs);
503     obj * __VOLATILE * my_free_list;
504     obj * result;
505     obj * current_obj, * next_obj;
506     int i;
507
508     if (1 == nobjs) return(chunk);
509     my_free_list = free_list + FREELIST_INDEX(n);
510
511     /* Build free list in chunk */
512       result = (obj *)chunk;
513       *my_free_list = next_obj = (obj *)(chunk + n);
514       for (i = 1; ; i++) {
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;
519             break;
520         } else {
521             current_obj -> free_list_link = next_obj;
522         }
523       }
524     return(result);
525 }
526
527 template <bool threads, int inst>
528 void*
529 __default_alloc_template<threads, inst>::reallocate(void *p,
530                                                     size_t old_sz,
531                                                     size_t new_sz)
532 {
533     void * result;
534     size_t copy_sz;
535
536     if (old_sz > __MAX_BYTES && new_sz > __MAX_BYTES) {
537         return(realloc(p, new_sz));
538     }
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);
544     return(result);
545 }
546
547 #ifdef _PTHREADS
548     template <bool threads, int inst>
549     pthread_mutex_t
550     __default_alloc_template<threads, inst>::__node_allocator_lock
551         = PTHREAD_MUTEX_INITIALIZER;
552 #endif
553
554 #ifdef __STL_WIN32THREADS
555     template <bool threads, int inst> CRITICAL_SECTION
556     __default_alloc_template<threads, inst>::__node_allocator_lock;
557
558     template <bool threads, int inst> bool
559     __default_alloc_template<threads, inst>::__node_allocator_lock_initialized
560         = false;
561 #endif
562
563 #ifdef __STL_SGI_THREADS
564 #include <mutex.h>
565 #include <time.h>
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;
572
573 #if __mips < 3 || !(defined (_ABIN32) || defined(_ABI64)) || defined(__GNUC__)
574 #   define __test_and_set(l,v) test_and_set(l,v)
575 #endif
576
577 template <bool threads, int inst>
578 void 
579 __default_alloc_template<threads, inst>::__lock(volatile unsigned long *lock)
580 {
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};
588     unsigned junk;
589 #   define __ALLOC_PAUSE junk *= junk; junk *= junk; junk *= junk; junk *= junk
590     int i;
591
592     if (!__test_and_set((unsigned long *)lock, 1)) {
593         return;
594     }
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) {
599             __ALLOC_PAUSE;
600             continue;
601         }
602         if (!__test_and_set((unsigned long *)lock, 1)) {
603             // got it!
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.
607             last_spins = i;
608             spin_max = high_spin_max;
609             return;
610         }
611     }
612     // We are probably being scheduled against the other process.  Sleep.
613     spin_max = low_spin_max;
614     for (;;) {
615         if (!__test_and_set((unsigned long *)lock, 1)) {
616             return;
617         }
618         nanosleep(&ts, 0);
619     }
620 }
621
622 template <bool threads, int inst>
623 inline void
624 __default_alloc_template<threads, inst>::__unlock(volatile unsigned long *lock)
625 {
626 #   if defined(__GNUC__) && __mips >= 3
627         asm("sync");
628         *lock = 0;
629 #   elif __mips >= 3 && (defined (_ABIN32) || defined(_ABI64))
630         __lock_release(lock);
631 #   else 
632         *lock = 0;
633         // This is not sufficient on many multiprocessors, since
634         // writes to protected variables and the lock may be reordered.
635 #   endif
636 }
637 #endif
638
639 template <bool threads, int inst>
640 char *__default_alloc_template<threads, inst>::start_free = 0;
641
642 template <bool threads, int inst>
643 char *__default_alloc_template<threads, inst>::end_free = 0;
644
645 template <bool threads, int inst>
646 size_t __default_alloc_template<threads, inst>::heap_size = 0;
647
648 template <bool threads, int inst>
649 __default_alloc_template<threads, inst>::obj * __VOLATILE
650 __default_alloc_template<threads, inst> ::free_list[
651 # ifdef __SUNPRO_CC
652     __NFREELISTS
653 # else
654     __default_alloc_template<threads, inst>::__NFREELISTS
655 # endif
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.
660
661 # ifdef __STL_WIN32THREADS
662   // Create one to get critical section initialized.
663   // We do this onece per file, but only the first constructor
664   // does anything.
665   static alloc __node_allocator_dummy_instance;
666 # endif
667
668 #endif /* ! __USE_MALLOC */
669
670 #if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
671 #pragma reset woff 1174
672 #endif
673
674 #endif /* __NODE_ALLOC_H */