streambuf.tcc (basic_streambuf::sputbackc): Prefix "this->" to call to pbackfail.
[official-gcc.git] / libstdc++-v3 / include / bits / pthread_allocimpl.h
blob050b2060fc459ce65a30a5a2d17b6c17c533f0cd
1 // POSIX thread-related memory allocation -*- C++ -*-
3 // Copyright (C) 2001 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library. This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 2, or (at your option)
9 // any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License along
17 // with this library; see the file COPYING. If not, write to the Free
18 // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19 // USA.
21 // As a special exception, you may use this file as part of a free software
22 // library without restriction. Specifically, if other files instantiate
23 // templates or use macros or inline functions from this file, or you compile
24 // this file and link it with other files to produce an executable, this
25 // file does not by itself cause the resulting executable to be covered by
26 // the GNU General Public License. This exception does not however
27 // invalidate any other reasons why the executable file might be covered by
28 // the GNU General Public License.
31 * Copyright (c) 1996
32 * Silicon Graphics Computer Systems, Inc.
34 * Permission to use, copy, modify, distribute and sell this software
35 * and its documentation for any purpose is hereby granted without fee,
36 * provided that the above copyright notice appear in all copies and
37 * that both that copyright notice and this permission notice appear
38 * in supporting documentation. Silicon Graphics makes no
39 * representations about the suitability of this software for any
40 * purpose. It is provided "as is" without express or implied warranty.
43 /** @file pthread_allocimpl.h
44 * This is an internal header file, included by other library headers.
45 * You should not attempt to use it directly.
48 #ifndef _CPP_BITS_PTHREAD_ALLOCIMPL_H
49 #define _CPP_BITS_PTHREAD_ALLOCIMPL_H 1
51 // Pthread-specific node allocator.
52 // This is similar to the default allocator, except that free-list
53 // information is kept separately for each thread, avoiding locking.
54 // This should be reasonably fast even in the presence of threads.
55 // The down side is that storage may not be well-utilized.
56 // It is not an error to allocate memory in thread A and deallocate
57 // it in thread B. But this effectively transfers ownership of the memory,
58 // so that it can only be reallocated by thread B. Thus this can effectively
59 // result in a storage leak if it's done on a regular basis.
60 // It can also result in frequent sharing of
61 // cache lines among processors, with potentially serious performance
62 // consequences.
64 #include <bits/c++config.h>
65 #include <cerrno>
66 #include <bits/stl_alloc.h>
67 #ifndef __RESTRICT
68 # define __RESTRICT
69 #endif
71 #include <new>
73 namespace std
76 #define __STL_DATA_ALIGNMENT 8
78 union _Pthread_alloc_obj {
79 union _Pthread_alloc_obj * __free_list_link;
80 char __client_data[__STL_DATA_ALIGNMENT]; /* The client sees this. */
83 // Pthread allocators don't appear to the client to have meaningful
84 // instances. We do in fact need to associate some state with each
85 // thread. That state is represented by
86 // _Pthread_alloc_per_thread_state<_Max_size>.
88 template<size_t _Max_size>
89 struct _Pthread_alloc_per_thread_state {
90 typedef _Pthread_alloc_obj __obj;
91 enum { _S_NFREELISTS = _Max_size/__STL_DATA_ALIGNMENT };
92 _Pthread_alloc_obj* volatile __free_list[_S_NFREELISTS];
93 _Pthread_alloc_per_thread_state<_Max_size> * __next;
94 // Free list link for list of available per thread structures.
95 // When one of these becomes available for reuse due to thread
96 // termination, any objects in its free list remain associated
97 // with it. The whole structure may then be used by a newly
98 // created thread.
99 _Pthread_alloc_per_thread_state() : __next(0)
101 memset((void *)__free_list, 0, (size_t) _S_NFREELISTS * sizeof(__obj *));
103 // Returns an object of size __n, and possibly adds to size n free list.
104 void *_M_refill(size_t __n);
107 // Pthread-specific allocator.
108 // The argument specifies the largest object size allocated from per-thread
109 // free lists. Larger objects are allocated using malloc_alloc.
110 // Max_size must be a power of 2.
111 template <size_t _Max_size = 128>
112 class _Pthread_alloc_template {
114 public: // but only for internal use:
116 typedef _Pthread_alloc_obj __obj;
118 // Allocates a chunk for nobjs of size size. nobjs may be reduced
119 // if it is inconvenient to allocate the requested number.
120 static char *_S_chunk_alloc(size_t __size, int &__nobjs);
122 enum {_S_ALIGN = __STL_DATA_ALIGNMENT};
124 static size_t _S_round_up(size_t __bytes) {
125 return (((__bytes) + (int) _S_ALIGN-1) & ~((int) _S_ALIGN - 1));
127 static size_t _S_freelist_index(size_t __bytes) {
128 return (((__bytes) + (int) _S_ALIGN-1)/(int)_S_ALIGN - 1);
131 private:
132 // Chunk allocation state. And other shared state.
133 // Protected by _S_chunk_allocator_lock.
134 static pthread_mutex_t _S_chunk_allocator_lock;
135 static char *_S_start_free;
136 static char *_S_end_free;
137 static size_t _S_heap_size;
138 static _Pthread_alloc_per_thread_state<_Max_size>* _S_free_per_thread_states;
139 static pthread_key_t _S_key;
140 static bool _S_key_initialized;
141 // Pthread key under which per thread state is stored.
142 // Allocator instances that are currently unclaimed by any thread.
143 static void _S_destructor(void *instance);
144 // Function to be called on thread exit to reclaim per thread
145 // state.
146 static _Pthread_alloc_per_thread_state<_Max_size> *_S_new_per_thread_state();
147 // Return a recycled or new per thread state.
148 static _Pthread_alloc_per_thread_state<_Max_size> *_S_get_per_thread_state();
149 // ensure that the current thread has an associated
150 // per thread state.
151 class _M_lock;
152 friend class _M_lock;
153 class _M_lock {
154 public:
155 _M_lock () { pthread_mutex_lock(&_S_chunk_allocator_lock); }
156 ~_M_lock () { pthread_mutex_unlock(&_S_chunk_allocator_lock); }
159 public:
161 /* n must be > 0 */
162 static void * allocate(size_t __n)
164 __obj * volatile * __my_free_list;
165 __obj * __RESTRICT __result;
166 _Pthread_alloc_per_thread_state<_Max_size>* __a;
168 if (__n > _Max_size) {
169 return(malloc_alloc::allocate(__n));
171 if (!_S_key_initialized ||
172 !(__a = (_Pthread_alloc_per_thread_state<_Max_size>*)
173 pthread_getspecific(_S_key))) {
174 __a = _S_get_per_thread_state();
176 __my_free_list = __a -> __free_list + _S_freelist_index(__n);
177 __result = *__my_free_list;
178 if (__result == 0) {
179 void *__r = __a -> _M_refill(_S_round_up(__n));
180 return __r;
182 *__my_free_list = __result -> __free_list_link;
183 return (__result);
186 /* p may not be 0 */
187 static void deallocate(void *__p, size_t __n)
189 __obj *__q = (__obj *)__p;
190 __obj * volatile * __my_free_list;
191 _Pthread_alloc_per_thread_state<_Max_size>* __a;
193 if (__n > _Max_size) {
194 malloc_alloc::deallocate(__p, __n);
195 return;
197 if (!_S_key_initialized ||
198 !(__a = (_Pthread_alloc_per_thread_state<_Max_size> *)
199 pthread_getspecific(_S_key))) {
200 __a = _S_get_per_thread_state();
202 __my_free_list = __a->__free_list + _S_freelist_index(__n);
203 __q -> __free_list_link = *__my_free_list;
204 *__my_free_list = __q;
207 static void * reallocate(void *__p, size_t __old_sz, size_t __new_sz);
211 typedef _Pthread_alloc_template<> pthread_alloc;
214 template <size_t _Max_size>
215 void _Pthread_alloc_template<_Max_size>::_S_destructor(void * __instance)
217 _M_lock __lock_instance; // Need to acquire lock here.
218 _Pthread_alloc_per_thread_state<_Max_size>* __s =
219 (_Pthread_alloc_per_thread_state<_Max_size> *)__instance;
220 __s -> __next = _S_free_per_thread_states;
221 _S_free_per_thread_states = __s;
224 template <size_t _Max_size>
225 _Pthread_alloc_per_thread_state<_Max_size> *
226 _Pthread_alloc_template<_Max_size>::_S_new_per_thread_state()
228 /* lock already held here. */
229 if (0 != _S_free_per_thread_states) {
230 _Pthread_alloc_per_thread_state<_Max_size> *__result =
231 _S_free_per_thread_states;
232 _S_free_per_thread_states = _S_free_per_thread_states -> __next;
233 return __result;
234 } else {
235 return new _Pthread_alloc_per_thread_state<_Max_size>;
239 template <size_t _Max_size>
240 _Pthread_alloc_per_thread_state<_Max_size> *
241 _Pthread_alloc_template<_Max_size>::_S_get_per_thread_state()
243 /*REFERENCED*/
244 _M_lock __lock_instance; // Need to acquire lock here.
245 int __ret_code;
246 _Pthread_alloc_per_thread_state<_Max_size> * __result;
247 if (!_S_key_initialized) {
248 if (pthread_key_create(&_S_key, _S_destructor)) {
249 std::__throw_bad_alloc(); // defined in funcexcept.h
251 _S_key_initialized = true;
253 __result = _S_new_per_thread_state();
254 __ret_code = pthread_setspecific(_S_key, __result);
255 if (__ret_code) {
256 if (__ret_code == ENOMEM) {
257 std::__throw_bad_alloc();
258 } else {
259 // EINVAL
260 abort();
263 return __result;
266 /* We allocate memory in large chunks in order to avoid fragmenting */
267 /* the malloc heap too much. */
268 /* We assume that size is properly aligned. */
269 template <size_t _Max_size>
270 char *_Pthread_alloc_template<_Max_size>
271 ::_S_chunk_alloc(size_t __size, int &__nobjs)
274 char * __result;
275 size_t __total_bytes;
276 size_t __bytes_left;
277 /*REFERENCED*/
278 _M_lock __lock_instance; // Acquire lock for this routine
280 __total_bytes = __size * __nobjs;
281 __bytes_left = _S_end_free - _S_start_free;
282 if (__bytes_left >= __total_bytes) {
283 __result = _S_start_free;
284 _S_start_free += __total_bytes;
285 return(__result);
286 } else if (__bytes_left >= __size) {
287 __nobjs = __bytes_left/__size;
288 __total_bytes = __size * __nobjs;
289 __result = _S_start_free;
290 _S_start_free += __total_bytes;
291 return(__result);
292 } else {
293 size_t __bytes_to_get =
294 2 * __total_bytes + _S_round_up(_S_heap_size >> 4);
295 // Try to make use of the left-over piece.
296 if (__bytes_left > 0) {
297 _Pthread_alloc_per_thread_state<_Max_size>* __a =
298 (_Pthread_alloc_per_thread_state<_Max_size>*)
299 pthread_getspecific(_S_key);
300 __obj * volatile * __my_free_list =
301 __a->__free_list + _S_freelist_index(__bytes_left);
303 ((__obj *)_S_start_free) -> __free_list_link = *__my_free_list;
304 *__my_free_list = (__obj *)_S_start_free;
306 # ifdef _SGI_SOURCE
307 // Try to get memory that's aligned on something like a
308 // cache line boundary, so as to avoid parceling out
309 // parts of the same line to different threads and thus
310 // possibly different processors.
312 const int __cache_line_size = 128; // probable upper bound
313 __bytes_to_get &= ~(__cache_line_size-1);
314 _S_start_free = (char *)memalign(__cache_line_size, __bytes_to_get);
315 if (0 == _S_start_free) {
316 _S_start_free = (char *)malloc_alloc::allocate(__bytes_to_get);
319 # else /* !SGI_SOURCE */
320 _S_start_free = (char *)malloc_alloc::allocate(__bytes_to_get);
321 # endif
322 _S_heap_size += __bytes_to_get;
323 _S_end_free = _S_start_free + __bytes_to_get;
326 // lock is released here
327 return(_S_chunk_alloc(__size, __nobjs));
331 /* Returns an object of size n, and optionally adds to size n free list.*/
332 /* We assume that n is properly aligned. */
333 /* We hold the allocation lock. */
334 template <size_t _Max_size>
335 void *_Pthread_alloc_per_thread_state<_Max_size>
336 ::_M_refill(size_t __n)
338 int __nobjs = 128;
339 char * __chunk =
340 _Pthread_alloc_template<_Max_size>::_S_chunk_alloc(__n, __nobjs);
341 __obj * volatile * __my_free_list;
342 __obj * __result;
343 __obj * __current_obj, * __next_obj;
344 int __i;
346 if (1 == __nobjs) {
347 return(__chunk);
349 __my_free_list = __free_list
350 + _Pthread_alloc_template<_Max_size>::_S_freelist_index(__n);
352 /* Build free list in chunk */
353 __result = (__obj *)__chunk;
354 *__my_free_list = __next_obj = (__obj *)(__chunk + __n);
355 for (__i = 1; ; __i++) {
356 __current_obj = __next_obj;
357 __next_obj = (__obj *)((char *)__next_obj + __n);
358 if (__nobjs - 1 == __i) {
359 __current_obj -> __free_list_link = 0;
360 break;
361 } else {
362 __current_obj -> __free_list_link = __next_obj;
365 return(__result);
368 template <size_t _Max_size>
369 void *_Pthread_alloc_template<_Max_size>
370 ::reallocate(void *__p, size_t __old_sz, size_t __new_sz)
372 void * __result;
373 size_t __copy_sz;
375 if (__old_sz > _Max_size
376 && __new_sz > _Max_size) {
377 return(realloc(__p, __new_sz));
379 if (_S_round_up(__old_sz) == _S_round_up(__new_sz)) return(__p);
380 __result = allocate(__new_sz);
381 __copy_sz = __new_sz > __old_sz? __old_sz : __new_sz;
382 memcpy(__result, __p, __copy_sz);
383 deallocate(__p, __old_sz);
384 return(__result);
387 template <size_t _Max_size>
388 _Pthread_alloc_per_thread_state<_Max_size> *
389 _Pthread_alloc_template<_Max_size>::_S_free_per_thread_states = 0;
391 template <size_t _Max_size>
392 pthread_key_t _Pthread_alloc_template<_Max_size>::_S_key;
394 template <size_t _Max_size>
395 bool _Pthread_alloc_template<_Max_size>::_S_key_initialized = false;
397 template <size_t _Max_size>
398 pthread_mutex_t _Pthread_alloc_template<_Max_size>::_S_chunk_allocator_lock
399 = PTHREAD_MUTEX_INITIALIZER;
401 template <size_t _Max_size>
402 char *_Pthread_alloc_template<_Max_size>
403 ::_S_start_free = 0;
405 template <size_t _Max_size>
406 char *_Pthread_alloc_template<_Max_size>
407 ::_S_end_free = 0;
409 template <size_t _Max_size>
410 size_t _Pthread_alloc_template<_Max_size>
411 ::_S_heap_size = 0;
414 template <class _Tp>
415 class pthread_allocator {
416 typedef pthread_alloc _S_Alloc; // The underlying allocator.
417 public:
418 typedef size_t size_type;
419 typedef ptrdiff_t difference_type;
420 typedef _Tp* pointer;
421 typedef const _Tp* const_pointer;
422 typedef _Tp& reference;
423 typedef const _Tp& const_reference;
424 typedef _Tp value_type;
426 template <class _NewType> struct rebind {
427 typedef pthread_allocator<_NewType> other;
430 pthread_allocator() throw() {}
431 pthread_allocator(const pthread_allocator& a) throw() {}
432 template <class _OtherType>
433 pthread_allocator(const pthread_allocator<_OtherType>&)
434 throw() {}
435 ~pthread_allocator() throw() {}
437 pointer address(reference __x) const { return &__x; }
438 const_pointer address(const_reference __x) const { return &__x; }
440 // __n is permitted to be 0. The C++ standard says nothing about what
441 // the return value is when __n == 0.
442 _Tp* allocate(size_type __n, const void* = 0) {
443 return __n != 0 ? static_cast<_Tp*>(_S_Alloc::allocate(__n * sizeof(_Tp)))
444 : 0;
447 // p is not permitted to be a null pointer.
448 void deallocate(pointer __p, size_type __n)
449 { _S_Alloc::deallocate(__p, __n * sizeof(_Tp)); }
451 size_type max_size() const throw()
452 { return size_t(-1) / sizeof(_Tp); }
454 void construct(pointer __p, const _Tp& __val) { new(__p) _Tp(__val); }
455 void destroy(pointer _p) { _p->~_Tp(); }
458 template<>
459 class pthread_allocator<void> {
460 public:
461 typedef size_t size_type;
462 typedef ptrdiff_t difference_type;
463 typedef void* pointer;
464 typedef const void* const_pointer;
465 typedef void value_type;
467 template <class _NewType> struct rebind {
468 typedef pthread_allocator<_NewType> other;
472 template <size_t _Max_size>
473 inline bool operator==(const _Pthread_alloc_template<_Max_size>&,
474 const _Pthread_alloc_template<_Max_size>&)
476 return true;
479 template <class _T1, class _T2>
480 inline bool operator==(const pthread_allocator<_T1>&,
481 const pthread_allocator<_T2>& a2)
483 return true;
486 template <class _T1, class _T2>
487 inline bool operator!=(const pthread_allocator<_T1>&,
488 const pthread_allocator<_T2>&)
490 return false;
493 template <class _Tp, size_t _Max_size>
494 struct _Alloc_traits<_Tp, _Pthread_alloc_template<_Max_size> >
496 static const bool _S_instanceless = true;
497 typedef simple_alloc<_Tp, _Pthread_alloc_template<_Max_size> > _Alloc_type;
498 typedef __allocator<_Tp, _Pthread_alloc_template<_Max_size> >
499 allocator_type;
502 template <class _Tp, class _Atype, size_t _Max>
503 struct _Alloc_traits<_Tp, __allocator<_Atype, _Pthread_alloc_template<_Max> > >
505 static const bool _S_instanceless = true;
506 typedef simple_alloc<_Tp, _Pthread_alloc_template<_Max> > _Alloc_type;
507 typedef __allocator<_Tp, _Pthread_alloc_template<_Max> > allocator_type;
510 template <class _Tp, class _Atype>
511 struct _Alloc_traits<_Tp, pthread_allocator<_Atype> >
513 static const bool _S_instanceless = true;
514 typedef simple_alloc<_Tp, _Pthread_alloc_template<> > _Alloc_type;
515 typedef pthread_allocator<_Tp> allocator_type;
519 } // namespace std
521 #endif /* _CPP_BITS_PTHREAD_ALLOCIMPL_H */
523 // Local Variables:
524 // mode:C++
525 // End: