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 \
46 have this interface so please comment the _STLP_USE_PERTHREAD_ALLOC macro \
47 or 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 \
52 STLport 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 
63 struct _Pthread_alloc_per_thread_state;
64 
65 // Pthread-specific allocator.
66 class _STLP_CLASS_DECLSPEC _Pthread_alloc {
67 public: // but only for internal use:
68   typedef _Pthread_alloc_per_thread_state __state_type;
69   typedef char value_type;
70 
71 public:
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 
93 typedef _STLP_PRIV _Pthread_alloc __pthread_alloc;
94 typedef __pthread_alloc pthread_alloc;
95 
96 template <class _Tp>
97 class pthread_allocator : public __stlport_class<pthread_allocator<_Tp> > {
98   typedef pthread_alloc _S_Alloc;          // The underlying allocator.
99 public:
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 
pthread_allocator()114   pthread_allocator() _STLP_NOTHROW {}
pthread_allocator(const pthread_allocator<_Tp> & a)115   pthread_allocator(const pthread_allocator<_Tp>& a) _STLP_NOTHROW {}
116 
117 #if defined (_STLP_MEMBER_TEMPLATES) /* && defined (_STLP_FUNCTION_PARTIAL_ORDER) */
pthread_allocator(const pthread_allocator<_OtherType> &)118   template <class _OtherType> pthread_allocator(const pthread_allocator<_OtherType>&)
119     _STLP_NOTHROW {}
120 #endif
121 
~pthread_allocator()122   ~pthread_allocator() _STLP_NOTHROW {}
123 
address(reference __x)124   pointer address(reference __x) const { return &__x; }
address(const_reference __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 
deallocate(pointer __p,size_type __n)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 
max_size()155   size_type max_size() const _STLP_NOTHROW
156   { return size_t(-1) / sizeof(_Tp); }
157 
construct(pointer __p,const _Tp & __val)158   void construct(pointer __p, const _Tp& __val) { new(__p) _Tp(__val); }
destroy(pointer _p)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    */
166 protected:
167 #endif
allocate(size_type __n,size_type & __allocated_n)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)
_M_swap_workaround(pthread_allocator<_Tp> & __x)185   void _M_swap_workaround(pthread_allocator<_Tp>& __x) {}
186 #endif
187 };
188 
189 _STLP_TEMPLATE_NULL
190 class _STLP_CLASS_DECLSPEC pthread_allocator<void> {
191 public:
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 
204 template <class _T1, class _T2>
205 inline bool operator==(const pthread_allocator<_T1>&,
206                        const pthread_allocator<_T2>& a2)
207 { return true; }
208 
209 #ifdef _STLP_FUNCTION_TMPL_PARTIAL_ORDER
210 template <class _T1, class _T2>
211 inline 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 
219 template <class _Tp, class _Atype>
220 struct _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 
227 template <class _Tp1, class _Tp2>
228 inline pthread_allocator<_Tp2>&
229 __stl_alloc_rebind(pthread_allocator<_Tp1>& __x, const _Tp2*)
230 { return (pthread_allocator<_Tp2>&)__x; }
231 
232 template <class _Tp1, class _Tp2>
233 inline 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 
241 template <class _Tp>
242 struct __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)
256 template <class _Tp>
257 struct __type_traits<pthread_allocator<_Tp> > : _STLP_PRIV __pthread_alloc_type_traits<_Tp> {};
258 #else
259 _STLP_TEMPLATE_NULL
260 struct __type_traits<pthread_allocator<char> > : _STLP_PRIV __pthread_alloc_type_traits<char> {};
261 #  if defined (_STLP_HAS_WCHAR_T)
262 _STLP_TEMPLATE_NULL
263 struct __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
267 struct __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 
276 template <class _Tp>
277 class per_thread_allocator {
278   typedef pthread_alloc _S_Alloc;          // The underlying allocator.
279   typedef pthread_alloc::__state_type __state_type;
280 public:
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    */
352 protected:
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
373 class _STLP_CLASS_DECLSPEC per_thread_allocator<void> {
374 public:
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 
387 template <class _T1, class _T2>
388 inline 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
393 template <class _T1, class _T2>
394 inline 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 
402 template <class _Tp, class _Atype>
403 struct _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 
410 template <class _Tp1, class _Tp2>
411 inline per_thread_allocator<_Tp2>&
412 __stl_alloc_rebind(per_thread_allocator<_Tp1>& __x, const _Tp2*)
413 { return (per_thread_allocator<_Tp2>&)__x; }
414 
415 template <class _Tp1, class _Tp2>
416 inline 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 
424 template <class _Tp>
425 struct __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)
439 template <class _Tp>
440 struct __type_traits<per_thread_allocator<_Tp> > : _STLP_PRIV __perthread_alloc_type_traits<_Tp> {};
441 #else
442 _STLP_TEMPLATE_NULL
443 struct __type_traits<per_thread_allocator<char> > : _STLP_PRIV __perthread_alloc_type_traits<char> {};
444 #  if defined (_STLP_HAS_WCHAR_T)
445 _STLP_TEMPLATE_NULL
446 struct __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
450 struct __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