1/*
2 *
3 * Copyright (c) 1994
4 * Hewlett-Packard Company
5 *
6 * Copyright (c) 1996,1997
7 * Silicon Graphics Computer Systems, Inc.
8 *
9 * Copyright (c) 1997
10 * Moscow Center for SPARC Technology
11 *
12 * Copyright (c) 1999
13 * Boris Fomitchev
14 *
15 * This material is provided "as is", with absolutely no warranty expressed
16 * or implied. Any use is at your own risk.
17 *
18 * Permission to use or copy this software for any purpose is hereby granted
19 * without fee, provided the above notices are retained on all copies.
20 * Permission to modify the code and to distribute modified code is granted,
21 * provided the above notices are retained, and a notice that the code was
22 * modified is included with the above copyright notice.
23 *
24 */
25
26#ifndef _STLP_PTHREAD_ALLOC_H
27#define _STLP_PTHREAD_ALLOC_H
28
29/*
30 * Pthread-specific node allocator.
31 * This is similar to the default allocator, except that free-list
32 * information is kept separately for each thread, avoiding locking.
33 * This should be reasonably fast even in the presence of threads.
34 * The down side is that storage may not be well-utilized.
35 * It is not an error to allocate memory in thread A and deallocate
36 * it in thread B.  But this effectively transfers ownership of the memory,
37 * so that it can only be reallocated by thread B.  Thus this can effectively
38 * result in a storage leak if it's done on a regular basis.
39 * It can also result in frequent sharing of
40 * cache lines among processors, with potentially serious performance
41 * consequences.
42 */
43
44#if !defined (_STLP_PTHREADS)
45#  error POSIX specific allocator implementation. Your system do not seems to \
46have this interface so please comment the _STLP_USE_PERTHREAD_ALLOC macro \
47or report to the STLport forum.
48#endif
49
50#if defined (_STLP_USE_NO_IOSTREAMS)
51#  error You cannot use per thread allocator implementation without building \
52STLport libraries.
53#endif
54
55#ifndef _STLP_INTERNAL_ALLOC_H
56#  include <stl/_alloc.h>
57#endif
58
59_STLP_BEGIN_NAMESPACE
60
61_STLP_MOVE_TO_PRIV_NAMESPACE
62
63struct _Pthread_alloc_per_thread_state;
64
65// Pthread-specific allocator.
66class _STLP_CLASS_DECLSPEC _Pthread_alloc {
67public: // but only for internal use:
68  typedef _Pthread_alloc_per_thread_state __state_type;
69  typedef char value_type;
70
71public:
72  // Return a recycled or new per thread state.
73  static __state_type * _STLP_CALL _S_get_per_thread_state();
74
75  /* n must be > 0      */
76  static void * _STLP_CALL allocate(size_t& __n);
77
78  /* p may not be 0 */
79  static void _STLP_CALL deallocate(void *__p, size_t __n);
80
81  // boris : versions for per_thread_allocator
82  /* n must be > 0      */
83  static void * _STLP_CALL allocate(size_t& __n, __state_type* __a);
84
85  /* p may not be 0 */
86  static void _STLP_CALL deallocate(void *__p, size_t __n, __state_type* __a);
87
88  static void * _STLP_CALL reallocate(void *__p, size_t __old_sz, size_t& __new_sz);
89};
90
91_STLP_MOVE_TO_STD_NAMESPACE
92
93typedef _STLP_PRIV _Pthread_alloc __pthread_alloc;
94typedef __pthread_alloc pthread_alloc;
95
96template <class _Tp>
97class pthread_allocator : public __stlport_class<pthread_allocator<_Tp> > {
98  typedef pthread_alloc _S_Alloc;          // The underlying allocator.
99public:
100  typedef size_t     size_type;
101  typedef ptrdiff_t  difference_type;
102  typedef _Tp*       pointer;
103  typedef const _Tp* const_pointer;
104  typedef _Tp&       reference;
105  typedef const _Tp& const_reference;
106  typedef _Tp        value_type;
107
108#ifdef _STLP_MEMBER_TEMPLATE_CLASSES
109  template <class _NewType> struct rebind {
110    typedef pthread_allocator<_NewType> other;
111  };
112#endif
113
114  pthread_allocator() _STLP_NOTHROW {}
115  pthread_allocator(const pthread_allocator<_Tp>& a) _STLP_NOTHROW {}
116
117#if defined (_STLP_MEMBER_TEMPLATES) /* && defined (_STLP_FUNCTION_PARTIAL_ORDER) */
118  template <class _OtherType> pthread_allocator(const pthread_allocator<_OtherType>&)
119    _STLP_NOTHROW {}
120#endif
121
122  ~pthread_allocator() _STLP_NOTHROW {}
123
124  pointer address(reference __x) const { return &__x; }
125  const_pointer address(const_reference __x) const { return &__x; }
126
127  // __n is permitted to be 0.  The C++ standard says nothing about what
128  // the return value is when __n == 0.
129  _Tp* allocate(size_type __n, const void* = 0) {
130    if (__n > max_size()) {
131      _STLP_THROW_BAD_ALLOC;
132    }
133    if (__n != 0) {
134      size_type __buf_size = __n * sizeof(value_type);
135      _Tp* __ret = __REINTERPRET_CAST(value_type*, _S_Alloc::allocate(__buf_size));
136#if defined (_STLP_DEBUG_UNINITIALIZED) && !defined (_STLP_DEBUG_ALLOC)
137      memset((char*)__ret, _STLP_SHRED_BYTE, __buf_size);
138#endif
139      return __ret;
140    }
141    else
142      return 0;
143  }
144
145  void deallocate(pointer __p, size_type __n) {
146    _STLP_ASSERT( (__p == 0) == (__n == 0) )
147    if (__p != 0) {
148#if defined (_STLP_DEBUG_UNINITIALIZED) && !defined (_STLP_DEBUG_ALLOC)
149      memset((char*)__p, _STLP_SHRED_BYTE, __n * sizeof(value_type));
150#endif
151      _S_Alloc::deallocate(__p, __n * sizeof(value_type));
152    }
153  }
154
155  size_type max_size() const _STLP_NOTHROW
156  { return size_t(-1) / sizeof(_Tp); }
157
158  void construct(pointer __p, const _Tp& __val) { new(__p) _Tp(__val); }
159  void destroy(pointer _p) { _p->~_Tp(); }
160
161#if defined (_STLP_NO_EXTENSIONS)
162  /* STLport extension giving rounded size of an allocated memory buffer
163   * This method do not have to be part of a user defined allocator implementation
164   * and won't even be called if such a function was granted.
165   */
166protected:
167#endif
168  _Tp* allocate(size_type __n, size_type& __allocated_n) {
169    if (__n > max_size()) {
170      _STLP_THROW_BAD_ALLOC;
171    }
172    if (__n != 0) {
173      size_type __buf_size = __n * sizeof(value_type);
174      _Tp* __ret = __REINTERPRET_CAST(value_type*, _S_Alloc::allocate(__buf_size));
175#if defined (_STLP_DEBUG_UNINITIALIZED) && !defined (_STLP_DEBUG_ALLOC)
176      memset((char*)__ret, _STLP_SHRED_BYTE, __buf_size);
177#endif
178      __allocated_n = __buf_size / sizeof(value_type);
179      return __ret;
180    }
181    else
182      return 0;
183  }
184#if defined (_STLP_USE_PARTIAL_SPEC_WORKAROUND) && !defined (_STLP_FUNCTION_TMPL_PARTIAL_ORDER)
185  void _M_swap_workaround(pthread_allocator<_Tp>& __x) {}
186#endif
187};
188
189_STLP_TEMPLATE_NULL
190class _STLP_CLASS_DECLSPEC pthread_allocator<void> {
191public:
192  typedef size_t      size_type;
193  typedef ptrdiff_t   difference_type;
194  typedef void*       pointer;
195  typedef const void* const_pointer;
196  typedef void        value_type;
197#ifdef _STLP_MEMBER_TEMPLATE_CLASSES
198  template <class _NewType> struct rebind {
199    typedef pthread_allocator<_NewType> other;
200  };
201#endif
202};
203
204template <class _T1, class _T2>
205inline bool operator==(const pthread_allocator<_T1>&,
206                       const pthread_allocator<_T2>& a2)
207{ return true; }
208
209#ifdef _STLP_FUNCTION_TMPL_PARTIAL_ORDER
210template <class _T1, class _T2>
211inline bool operator!=(const pthread_allocator<_T1>&,
212                       const pthread_allocator<_T2>&)
213{ return false; }
214#endif
215
216
217#if defined (_STLP_CLASS_PARTIAL_SPECIALIZATION)
218
219template <class _Tp, class _Atype>
220struct _Alloc_traits<_Tp, pthread_allocator<_Atype> >
221{ typedef pthread_allocator<_Tp> allocator_type; };
222
223#endif
224
225#if defined (_STLP_DONT_SUPPORT_REBIND_MEMBER_TEMPLATE)
226
227template <class _Tp1, class _Tp2>
228inline pthread_allocator<_Tp2>&
229__stl_alloc_rebind(pthread_allocator<_Tp1>& __x, const _Tp2*)
230{ return (pthread_allocator<_Tp2>&)__x; }
231
232template <class _Tp1, class _Tp2>
233inline pthread_allocator<_Tp2>
234__stl_alloc_create(pthread_allocator<_Tp1>&, const _Tp2*)
235{ return pthread_allocator<_Tp2>(); }
236
237#endif
238
239_STLP_MOVE_TO_PRIV_NAMESPACE
240
241template <class _Tp>
242struct __pthread_alloc_type_traits {
243  typedef typename _IsSTLportClass<pthread_allocator<_Tp> >::_Ret _STLportAlloc;
244  //The default allocator implementation which is recognize thanks to the
245  //__stlport_class inheritance is a stateless object so:
246  typedef _STLportAlloc has_trivial_default_constructor;
247  typedef _STLportAlloc has_trivial_copy_constructor;
248  typedef _STLportAlloc has_trivial_assignment_operator;
249  typedef _STLportAlloc has_trivial_destructor;
250  typedef _STLportAlloc is_POD_type;
251};
252
253_STLP_MOVE_TO_STD_NAMESPACE
254
255#if defined (_STLP_CLASS_PARTIAL_SPECIALIZATION)
256template <class _Tp>
257struct __type_traits<pthread_allocator<_Tp> > : _STLP_PRIV __pthread_alloc_type_traits<_Tp> {};
258#else
259_STLP_TEMPLATE_NULL
260struct __type_traits<pthread_allocator<char> > : _STLP_PRIV __pthread_alloc_type_traits<char> {};
261#  if defined (_STLP_HAS_WCHAR_T)
262_STLP_TEMPLATE_NULL
263struct __type_traits<pthread_allocator<wchar_t> > : _STLP_PRIV __pthread_alloc_type_traits<wchar_t> {};
264#  endif
265#  if defined (_STLP_USE_PTR_SPECIALIZATIONS)
266_STLP_TEMPLATE_NULL
267struct __type_traits<pthread_allocator<void*> > : _STLP_PRIV __pthread_alloc_type_traits<void*> {};
268#  endif
269#endif
270
271//
272// per_thread_allocator<> : this allocator always return memory to the same thread
273// it was allocated from.
274//
275
276template <class _Tp>
277class per_thread_allocator {
278  typedef pthread_alloc _S_Alloc;          // The underlying allocator.
279  typedef pthread_alloc::__state_type __state_type;
280public:
281  typedef size_t     size_type;
282  typedef ptrdiff_t  difference_type;
283  typedef _Tp*       pointer;
284  typedef const _Tp* const_pointer;
285  typedef _Tp&       reference;
286  typedef const _Tp& const_reference;
287  typedef _Tp        value_type;
288
289#ifdef _STLP_MEMBER_TEMPLATE_CLASSES
290  template <class _NewType> struct rebind {
291    typedef per_thread_allocator<_NewType> other;
292  };
293#endif
294
295  per_thread_allocator() _STLP_NOTHROW {
296    _M_state = _S_Alloc::_S_get_per_thread_state();
297  }
298  per_thread_allocator(const per_thread_allocator<_Tp>& __a) _STLP_NOTHROW : _M_state(__a._M_state){}
299
300#if defined (_STLP_MEMBER_TEMPLATES) /* && defined (_STLP_FUNCTION_PARTIAL_ORDER) */
301  template <class _OtherType> per_thread_allocator(const per_thread_allocator<_OtherType>& __a)
302    _STLP_NOTHROW : _M_state(__a._M_state) {}
303#endif
304
305  ~per_thread_allocator() _STLP_NOTHROW {}
306
307  pointer address(reference __x) const { return &__x; }
308  const_pointer address(const_reference __x) const { return &__x; }
309
310  // __n is permitted to be 0.  The C++ standard says nothing about what
311  // the return value is when __n == 0.
312  _Tp* allocate(size_type __n, const void* = 0) {
313    if (__n > max_size()) {
314      _STLP_THROW_BAD_ALLOC;
315    }
316    if (__n != 0) {
317      size_type __buf_size = __n * sizeof(value_type);
318      _Tp* __ret = __REINTERPRET_CAST(_Tp*, _S_Alloc::allocate(__buf_size, _M_state));
319#if defined (_STLP_DEBUG_UNINITIALIZED) && !defined (_STLP_DEBUG_ALLOC)
320      memset((char*)__ret, _STLP_SHRED_BYTE, __buf_size);
321#endif
322      return __ret;
323    }
324    else
325      return 0;
326  }
327
328  void deallocate(pointer __p, size_type __n) {
329    _STLP_ASSERT( (__p == 0) == (__n == 0) )
330    if (__p != 0) {
331#if defined (_STLP_DEBUG_UNINITIALIZED) && !defined (_STLP_DEBUG_ALLOC)
332      memset((char*)__p, _STLP_SHRED_BYTE, __n * sizeof(value_type));
333#endif
334      _S_Alloc::deallocate(__p, __n * sizeof(value_type), _M_state);
335    }
336  }
337
338  size_type max_size() const _STLP_NOTHROW
339  { return size_t(-1) / sizeof(_Tp); }
340
341  void construct(pointer __p, const _Tp& __val) { new(__p) _Tp(__val); }
342  void destroy(pointer _p) { _p->~_Tp(); }
343
344  // state is being kept here
345  __state_type* _M_state;
346
347#if defined (_STLP_NO_EXTENSIONS)
348  /* STLport extension giving rounded size of an allocated memory buffer
349   * This method do not have to be part of a user defined allocator implementation
350   * and won't even be called if such a function was granted.
351   */
352protected:
353#endif
354  _Tp* allocate(size_type __n, size_type& __allocated_n) {
355    if (__n > max_size()) {
356      _STLP_THROW_BAD_ALLOC;
357    }
358    if (__n != 0) {
359      size_type __buf_size = __n * sizeof(value_type);
360      _Tp* __ret = __REINTERPRET_CAST(value_type*, _S_Alloc::allocate(__buf_size, _M_state));
361#if defined (_STLP_DEBUG_UNINITIALIZED) && !defined (_STLP_DEBUG_ALLOC)
362      memset((char*)__ret, _STLP_SHRED_BYTE, __buf_size);
363#endif
364      __allocated_n = __buf_size / sizeof(value_type);
365      return __ret;
366    }
367    else
368      return 0;
369  }
370};
371
372_STLP_TEMPLATE_NULL
373class _STLP_CLASS_DECLSPEC per_thread_allocator<void> {
374public:
375  typedef size_t      size_type;
376  typedef ptrdiff_t   difference_type;
377  typedef void*       pointer;
378  typedef const void* const_pointer;
379  typedef void        value_type;
380#ifdef _STLP_MEMBER_TEMPLATE_CLASSES
381  template <class _NewType> struct rebind {
382    typedef per_thread_allocator<_NewType> other;
383  };
384#endif
385};
386
387template <class _T1, class _T2>
388inline bool operator==(const per_thread_allocator<_T1>& __a1,
389                       const per_thread_allocator<_T2>& __a2)
390{ return __a1._M_state == __a2._M_state; }
391
392#ifdef _STLP_FUNCTION_TMPL_PARTIAL_ORDER
393template <class _T1, class _T2>
394inline bool operator!=(const per_thread_allocator<_T1>& __a1,
395                       const per_thread_allocator<_T2>& __a2)
396{ return __a1._M_state != __a2._M_state; }
397#endif
398
399
400#if defined (_STLP_CLASS_PARTIAL_SPECIALIZATION)
401
402template <class _Tp, class _Atype>
403struct _Alloc_traits<_Tp, per_thread_allocator<_Atype> >
404{ typedef per_thread_allocator<_Tp> allocator_type; };
405
406#endif
407
408#if defined (_STLP_DONT_SUPPORT_REBIND_MEMBER_TEMPLATE)
409
410template <class _Tp1, class _Tp2>
411inline per_thread_allocator<_Tp2>&
412__stl_alloc_rebind(per_thread_allocator<_Tp1>& __x, const _Tp2*)
413{ return (per_thread_allocator<_Tp2>&)__x; }
414
415template <class _Tp1, class _Tp2>
416inline per_thread_allocator<_Tp2>
417__stl_alloc_create(per_thread_allocator<_Tp1>&, const _Tp2*)
418{ return per_thread_allocator<_Tp2>(); }
419
420#endif /* _STLP_DONT_SUPPORT_REBIND_MEMBER_TEMPLATE */
421
422_STLP_MOVE_TO_PRIV_NAMESPACE
423
424template <class _Tp>
425struct __perthread_alloc_type_traits {
426  typedef typename _IsSTLportClass<per_thread_allocator<_Tp> >::_Ret _STLportAlloc;
427  //The default allocator implementation which is recognize thanks to the
428  //__stlport_class inheritance is a stateless object so:
429  typedef __false_type has_trivial_default_constructor;
430  typedef _STLportAlloc has_trivial_copy_constructor;
431  typedef _STLportAlloc has_trivial_assignment_operator;
432  typedef _STLportAlloc has_trivial_destructor;
433  typedef __false_type is_POD_type;
434};
435
436_STLP_MOVE_TO_STD_NAMESPACE
437
438#if defined (_STLP_CLASS_PARTIAL_SPECIALIZATION)
439template <class _Tp>
440struct __type_traits<per_thread_allocator<_Tp> > : _STLP_PRIV __perthread_alloc_type_traits<_Tp> {};
441#else
442_STLP_TEMPLATE_NULL
443struct __type_traits<per_thread_allocator<char> > : _STLP_PRIV __perthread_alloc_type_traits<char> {};
444#  if defined (_STLP_HAS_WCHAR_T)
445_STLP_TEMPLATE_NULL
446struct __type_traits<per_thread_allocator<wchar_t> > : _STLP_PRIV __perthread_alloc_type_traits<wchar_t> {};
447#  endif
448#  if defined (_STLP_USE_PTR_SPECIALIZATIONS)
449_STLP_TEMPLATE_NULL
450struct __type_traits<per_thread_allocator<void*> > : _STLP_PRIV __perthread_alloc_type_traits<void*> {};
451#  endif
452#endif
453
454
455_STLP_END_NAMESPACE
456
457#endif /* _STLP_PTHREAD_ALLOC */
458
459// Local Variables:
460// mode:C++
461// End:
462