diff -r e1b950c65cb4 -r 837f303aceeb epoc32/include/stdapis/stlportv5/stl/_pthread_alloc.h --- a/epoc32/include/stdapis/stlportv5/stl/_pthread_alloc.h Wed Mar 31 12:27:01 2010 +0100 +++ b/epoc32/include/stdapis/stlportv5/stl/_pthread_alloc.h Wed Mar 31 12:33:34 2010 +0100 @@ -9,13 +9,13 @@ * Copyright (c) 1997 * Moscow Center for SPARC Technology * - * Copyright (c) 1999 + * Copyright (c) 1999 * Boris Fomitchev * * This material is provided "as is", with absolutely no warranty expressed * or implied. Any use is at your own risk. * - * Permission to use or copy this software for any purpose is hereby granted + * Permission to use or copy this software for any purpose is hereby granted * without fee, provided the above notices are retained on all copies. * Permission to modify the code and to distribute modified code is granted, * provided the above notices are retained, and a notice that the code was @@ -26,225 +26,75 @@ #ifndef _STLP_PTHREAD_ALLOC_H #define _STLP_PTHREAD_ALLOC_H -// Pthread-specific node allocator. -// This is similar to the default allocator, except that free-list -// information is kept separately for each thread, avoiding locking. -// This should be reasonably fast even in the presence of threads. -// The down side is that storage may not be well-utilized. -// It is not an error to allocate memory in thread A and deallocate -// it in thread B. But this effectively transfers ownership of the memory, -// so that it can only be reallocated by thread B. Thus this can effectively -// result in a storage leak if it's done on a regular basis. -// It can also result in frequent sharing of -// cache lines among processors, with potentially serious performance -// consequences. +/* + * Pthread-specific node allocator. + * This is similar to the default allocator, except that free-list + * information is kept separately for each thread, avoiding locking. + * This should be reasonably fast even in the presence of threads. + * The down side is that storage may not be well-utilized. + * It is not an error to allocate memory in thread A and deallocate + * it in thread B. But this effectively transfers ownership of the memory, + * so that it can only be reallocated by thread B. Thus this can effectively + * result in a storage leak if it's done on a regular basis. + * It can also result in frequent sharing of + * cache lines among processors, with potentially serious performance + * consequences. + */ -#include +#if !defined (_STLP_PTHREADS) +# error POSIX specific allocator implementation. Your system do not seems to \ +have this interface so please comment the _STLP_USE_PERTHREAD_ALLOC macro \ +or report to the STLport forum. +#endif + +#if defined (_STLP_USE_NO_IOSTREAMS) +# error You cannot use per thread allocator implementation without building \ +STLport libraries. +#endif #ifndef _STLP_INTERNAL_ALLOC_H -#include -#endif - -#ifndef __RESTRICT -# define __RESTRICT +# include #endif _STLP_BEGIN_NAMESPACE -#define _STLP_DATA_ALIGNMENT 8 +_STLP_MOVE_TO_PRIV_NAMESPACE -union _Pthread_alloc_obj { - union _Pthread_alloc_obj * __free_list_link; - char __client_data[_STLP_DATA_ALIGNMENT]; /* The client sees this. */ -}; - -// Pthread allocators don't appear to the client to have meaningful -// instances. We do in fact need to associate some state with each -// thread. That state is represented by -// _Pthread_alloc_per_thread_state<_Max_size>. - -template -struct _Pthread_alloc_per_thread_state { - typedef _Pthread_alloc_obj __obj; - enum { _S_NFREELISTS = _Max_size/_STLP_DATA_ALIGNMENT }; - - // Free list link for list of available per thread structures. - // When one of these becomes available for reuse due to thread - // termination, any objects in its free list remain associated - // with it. The whole structure may then be used by a newly - // created thread. - _Pthread_alloc_per_thread_state() : __next(0) - { - memset((void *)__free_list, 0, (size_t)_S_NFREELISTS * sizeof(__obj *)); - } - // Returns an object of size __n, and possibly adds to size n free list. - void *_M_refill(size_t __n); - - _Pthread_alloc_obj* volatile __free_list[_S_NFREELISTS]; - _Pthread_alloc_per_thread_state<_Max_size> * __next; - // this data member is only to be used by per_thread_allocator, which returns memory to the originating thread. - _STLP_mutex _M_lock; - - }; +struct _Pthread_alloc_per_thread_state; // Pthread-specific allocator. -// The argument specifies the largest object size allocated from per-thread -// free lists. Larger objects are allocated using malloc_alloc. -// Max_size must be a power of 2. -template < __DFL_NON_TYPE_PARAM(size_t, _Max_size, _MAX_BYTES) > -class _Pthread_alloc { - +class _STLP_CLASS_DECLSPEC _Pthread_alloc { public: // but only for internal use: - - typedef _Pthread_alloc_obj __obj; - typedef _Pthread_alloc_per_thread_state<_Max_size> __state_type; + typedef _Pthread_alloc_per_thread_state __state_type; typedef char value_type; - // Allocates a chunk for nobjs of size size. nobjs may be reduced - // if it is inconvenient to allocate the requested number. - static char *_S_chunk_alloc(size_t __size, size_t &__nobjs); - - enum {_S_ALIGN = _STLP_DATA_ALIGNMENT}; - - static size_t _S_round_up(size_t __bytes) { - return (((__bytes) + (int)_S_ALIGN-1) & ~((int)_S_ALIGN - 1)); - } - static size_t _S_freelist_index(size_t __bytes) { - return (((__bytes) + (int)_S_ALIGN-1)/(int)_S_ALIGN - 1); - } - -private: - // Chunk allocation state. And other shared state. - // Protected by _S_chunk_allocator_lock. - static _STLP_mutex_base _S_chunk_allocator_lock; - static char *_S_start_free; - static char *_S_end_free; - static size_t _S_heap_size; - static _Pthread_alloc_per_thread_state<_Max_size>* _S_free_per_thread_states; - static pthread_key_t _S_key; - static bool _S_key_initialized; - // Pthread key under which per thread state is stored. - // Allocator instances that are currently unclaimed by any thread. - static void _S_destructor(void *instance); - // Function to be called on thread exit to reclaim per thread - // state. - static _Pthread_alloc_per_thread_state<_Max_size> *_S_new_per_thread_state(); public: - // Return a recycled or new per thread state. - static _Pthread_alloc_per_thread_state<_Max_size> *_S_get_per_thread_state(); -private: - // ensure that the current thread has an associated - // per thread state. - class _M_lock; - friend class _M_lock; - class _M_lock { - public: - _M_lock () { _S_chunk_allocator_lock._M_acquire_lock(); } - ~_M_lock () { _S_chunk_allocator_lock._M_release_lock(); } - }; - -public: + // Return a recycled or new per thread state. + static __state_type * _STLP_CALL _S_get_per_thread_state(); /* n must be > 0 */ - static void * allocate(size_t __n) - { - __obj * volatile * __my_free_list; - __obj * __RESTRICT __result; - __state_type* __a; - - if (__n > _Max_size) { - return(__malloc_alloc<0>::allocate(__n)); - } - - __a = _S_get_per_thread_state(); - - __my_free_list = __a -> __free_list + _S_freelist_index(__n); - __result = *__my_free_list; - if (__result == 0) { - void *__r = __a -> _M_refill(_S_round_up(__n)); - return __r; - } - *__my_free_list = __result -> __free_list_link; - return (__result); - }; + static void * _STLP_CALL allocate(size_t& __n); /* p may not be 0 */ - static void deallocate(void *__p, size_t __n) - { - __obj *__q = (__obj *)__p; - __obj * volatile * __my_free_list; - __state_type* __a; - - if (__n > _Max_size) { - __malloc_alloc<0>::deallocate(__p, __n); - return; - } - - __a = _S_get_per_thread_state(); - - __my_free_list = __a->__free_list + _S_freelist_index(__n); - __q -> __free_list_link = *__my_free_list; - *__my_free_list = __q; - } + static void _STLP_CALL deallocate(void *__p, size_t __n); // boris : versions for per_thread_allocator /* n must be > 0 */ - static void * allocate(size_t __n, __state_type* __a) - { - __obj * volatile * __my_free_list; - __obj * __RESTRICT __result; - - if (__n > _Max_size) { - return(__malloc_alloc<0>::allocate(__n)); - } - - // boris : here, we have to lock per thread state, as we may be getting memory from - // different thread pool. - _STLP_mutex_lock __lock(__a->_M_lock); - - __my_free_list = __a -> __free_list + _S_freelist_index(__n); - __result = *__my_free_list; - if (__result == 0) { - void *__r = __a -> _M_refill(_S_round_up(__n)); - return __r; - } - *__my_free_list = __result -> __free_list_link; - return (__result); - }; + static void * _STLP_CALL allocate(size_t& __n, __state_type* __a); /* p may not be 0 */ - static void deallocate(void *__p, size_t __n, __state_type* __a) - { - __obj *__q = (__obj *)__p; - __obj * volatile * __my_free_list; + static void _STLP_CALL deallocate(void *__p, size_t __n, __state_type* __a); - if (__n > _Max_size) { - __malloc_alloc<0>::deallocate(__p, __n); - return; - } + static void * _STLP_CALL reallocate(void *__p, size_t __old_sz, size_t& __new_sz); +}; - // boris : here, we have to lock per thread state, as we may be returning memory from - // different thread. - _STLP_mutex_lock __lock(__a->_M_lock); +_STLP_MOVE_TO_STD_NAMESPACE - __my_free_list = __a->__free_list + _S_freelist_index(__n); - __q -> __free_list_link = *__my_free_list; - *__my_free_list = __q; - } - - static void * reallocate(void *__p, size_t __old_sz, size_t __new_sz); - -} ; - -# if defined (_STLP_USE_TEMPLATE_EXPORT) -_STLP_EXPORT_TEMPLATE_CLASS _Pthread_alloc<_MAX_BYTES>; -# endif - -typedef _Pthread_alloc<_MAX_BYTES> __pthread_alloc; +typedef _STLP_PRIV _Pthread_alloc __pthread_alloc; typedef __pthread_alloc pthread_alloc; template -class pthread_allocator { +class pthread_allocator : public __stlport_class > { typedef pthread_alloc _S_Alloc; // The underlying allocator. public: typedef size_t size_type; @@ -266,7 +116,7 @@ #if defined (_STLP_MEMBER_TEMPLATES) /* && defined (_STLP_FUNCTION_PARTIAL_ORDER) */ template pthread_allocator(const pthread_allocator<_OtherType>&) - _STLP_NOTHROW {} + _STLP_NOTHROW {} #endif ~pthread_allocator() _STLP_NOTHROW {} @@ -277,19 +127,64 @@ // __n is permitted to be 0. The C++ standard says nothing about what // the return value is when __n == 0. _Tp* allocate(size_type __n, const void* = 0) { - return __n != 0 ? __STATIC_CAST(_Tp*,_S_Alloc::allocate(__n * sizeof(_Tp))) - : 0; + if (__n > max_size()) { + __THROW_BAD_ALLOC; + } + if (__n != 0) { + size_type __buf_size = __n * sizeof(value_type); + _Tp* __ret = __REINTERPRET_CAST(value_type*, _S_Alloc::allocate(__buf_size)); +#if defined (_STLP_DEBUG_UNINITIALIZED) && !defined (_STLP_DEBUG_ALLOC) + if (__ret != 0) { + memset((char*)__ret, _STLP_SHRED_BYTE, __buf_size); + } +#endif + return __ret; + } + else + return 0; } - // p is not permitted to be a null pointer. - void deallocate(pointer __p, size_type __n) - { _S_Alloc::deallocate(__p, __n * sizeof(_Tp)); } + void deallocate(pointer __p, size_type __n) { + _STLP_ASSERT( (__p == 0) == (__n == 0) ) + if (__p != 0) { +#if defined (_STLP_DEBUG_UNINITIALIZED) && !defined (_STLP_DEBUG_ALLOC) + memset((char*)__p, _STLP_SHRED_BYTE, __n * sizeof(value_type)); +#endif + _S_Alloc::deallocate(__p, __n * sizeof(value_type)); + } + } - size_type max_size() const _STLP_NOTHROW - { return size_t(-1) / sizeof(_Tp); } + size_type max_size() const _STLP_NOTHROW + { return size_t(-1) / sizeof(_Tp); } void construct(pointer __p, const _Tp& __val) { _STLP_PLACEMENT_NEW (__p) _Tp(__val); } void destroy(pointer _p) { _p->~_Tp(); } + +#if defined (_STLP_NO_EXTENSIONS) + /* STLport extension giving rounded size of an allocated memory buffer + * This method do not have to be part of a user defined allocator implementation + * and won't even be called if such a function was granted. + */ +protected: +#endif + _Tp* allocate(size_type __n, size_type& __allocated_n) { + if (__n > max_size()) { + __THROW_BAD_ALLOC; + } + if (__n != 0) { + size_type __buf_size = __n * sizeof(value_type); + _Tp* __ret = __REINTERPRET_CAST(value_type*, _S_Alloc::allocate(__buf_size)); +#if defined (_STLP_DEBUG_UNINITIALIZED) && !defined (_STLP_DEBUG_ALLOC) + if (__ret != 0) { + memset((char*)__ret, _STLP_SHRED_BYTE, __buf_size); + } +#endif + __allocated_n = __buf_size / sizeof(value_type); + return __ret; + } + else + return 0; + } }; _STLP_TEMPLATE_NULL @@ -309,58 +204,79 @@ template inline bool operator==(const pthread_allocator<_T1>&, - const pthread_allocator<_T2>& a2) -{ - return true; -} + const pthread_allocator<_T2>& a2) +{ return true; } #ifdef _STLP_FUNCTION_TMPL_PARTIAL_ORDER template inline bool operator!=(const pthread_allocator<_T1>&, const pthread_allocator<_T2>&) -{ - return false; -} +{ return false; } #endif -#ifdef _STLP_CLASS_PARTIAL_SPECIALIZATION +#if defined (_STLP_CLASS_PARTIAL_SPECIALIZATION) -# ifdef _STLP_USE_RAW_SGI_ALLOCATORS -template -struct _Alloc_traits<_Tp, _Pthread_alloc<_Max_size> > -{ - typedef __allocator<_Tp, _Pthread_alloc<_Max_size> > - allocator_type; -}; -# endif +# if defined (_STLP_USE_RAW_SGI_ALLOCATORS) +template +struct _Alloc_traits<_Tp, _Pthread_alloc> +{ typedef __allocator<_Tp, _Pthread_alloc> allocator_type; }; +# endif template struct _Alloc_traits<_Tp, pthread_allocator<_Atype> > -{ - typedef pthread_allocator<_Tp> allocator_type; -}; +{ typedef pthread_allocator<_Tp> allocator_type; }; #endif -#if !defined (_STLP_USE_NESTED_TCLASS_THROUGHT_TPARAM) +#if defined (_STLP_DONT_SUPPORT_REBIND_MEMBER_TEMPLATE) template inline pthread_allocator<_Tp2>& -__stl_alloc_rebind(pthread_allocator<_Tp1>& __x, const _Tp2*) { - return (pthread_allocator<_Tp2>&)__x; -} +__stl_alloc_rebind(pthread_allocator<_Tp1>& __x, const _Tp2*) +{ return (pthread_allocator<_Tp2>&)__x; } template inline pthread_allocator<_Tp2> -__stl_alloc_create(pthread_allocator<_Tp1>&, const _Tp2*) { - return pthread_allocator<_Tp2>(); -} +__stl_alloc_create(pthread_allocator<_Tp1>&, const _Tp2*) +{ return pthread_allocator<_Tp2>(); } -#endif /* _STLP_USE_NESTED_TCLASS_THROUGHT_TPARAM */ +#endif + +_STLP_MOVE_TO_PRIV_NAMESPACE + +template +struct __pthread_alloc_type_traits { + typedef typename _IsSTLportClass >::_Ret _STLportAlloc; + //The default allocator implementation which is recognize thanks to the + //__stlport_class inheritance is a stateless object so: + typedef _STLportAlloc has_trivial_default_constructor; + typedef _STLportAlloc has_trivial_copy_constructor; + typedef _STLportAlloc has_trivial_assignment_operator; + typedef _STLportAlloc has_trivial_destructor; + typedef _STLportAlloc is_POD_type; +}; + +_STLP_MOVE_TO_STD_NAMESPACE + +#if defined (_STLP_CLASS_PARTIAL_SPECIALIZATION) +template +struct __type_traits > : _STLP_PRIV __pthread_alloc_type_traits<_Tp> {}; +#else +_STLP_TEMPLATE_NULL +struct __type_traits > : _STLP_PRIV __pthread_alloc_type_traits {}; +# if defined (_STLP_HAS_WCHAR_T) +_STLP_TEMPLATE_NULL +struct __type_traits > : _STLP_PRIV __pthread_alloc_type_traits {}; +# endif +# if defined (_STLP_USE_PTR_SPECIALIZATIONS) +_STLP_TEMPLATE_NULL +struct __type_traits > : _STLP_PRIV __pthread_alloc_type_traits {}; +# endif +#endif // -// per_thread_allocator<> : this allocator always return memory to the same thread +// per_thread_allocator<> : this allocator always return memory to the same thread // it was allocated from. // @@ -383,14 +299,14 @@ }; #endif - per_thread_allocator() _STLP_NOTHROW { + per_thread_allocator() _STLP_NOTHROW { _M_state = _S_Alloc::_S_get_per_thread_state(); } per_thread_allocator(const per_thread_allocator<_Tp>& __a) _STLP_NOTHROW : _M_state(__a._M_state){} #if defined (_STLP_MEMBER_TEMPLATES) /* && defined (_STLP_FUNCTION_PARTIAL_ORDER) */ template per_thread_allocator(const per_thread_allocator<_OtherType>& __a) - _STLP_NOTHROW : _M_state(__a._M_state) {} + _STLP_NOTHROW : _M_state(__a._M_state) {} #endif ~per_thread_allocator() _STLP_NOTHROW {} @@ -401,21 +317,67 @@ // __n is permitted to be 0. The C++ standard says nothing about what // the return value is when __n == 0. _Tp* allocate(size_type __n, const void* = 0) { - return __n != 0 ? __STATIC_CAST(_Tp*,_S_Alloc::allocate(__n * sizeof(_Tp), _M_state)): 0; + if (__n > max_size()) { + __THROW_BAD_ALLOC; + } + if (__n != 0) { + size_type __buf_size = __n * sizeof(value_type); + _Tp* __ret = __REINTERPRET_CAST(_Tp*, _S_Alloc::allocate(__buf_size, _M_state)); +#if defined (_STLP_DEBUG_UNINITIALIZED) && !defined (_STLP_DEBUG_ALLOC) + if (__ret != 0) { + memset((char*)__ret, _STLP_SHRED_BYTE, __buf_size); + } +#endif + return __ret; + } + else + return 0; } - // p is not permitted to be a null pointer. - void deallocate(pointer __p, size_type __n) - { _S_Alloc::deallocate(__p, __n * sizeof(_Tp), _M_state); } + void deallocate(pointer __p, size_type __n) { + _STLP_ASSERT( (__p == 0) == (__n == 0) ) + if (__p != 0) { +#if defined (_STLP_DEBUG_UNINITIALIZED) && !defined (_STLP_DEBUG_ALLOC) + memset((char*)__p, _STLP_SHRED_BYTE, __n * sizeof(value_type)); +#endif + _S_Alloc::deallocate(__p, __n * sizeof(value_type), _M_state); + } + } - size_type max_size() const _STLP_NOTHROW - { return size_t(-1) / sizeof(_Tp); } + size_type max_size() const _STLP_NOTHROW + { return size_t(-1) / sizeof(_Tp); } void construct(pointer __p, const _Tp& __val) { _STLP_PLACEMENT_NEW (__p) _Tp(__val); } void destroy(pointer _p) { _p->~_Tp(); } // state is being kept here __state_type* _M_state; + +#if defined (_STLP_NO_EXTENSIONS) + /* STLport extension giving rounded size of an allocated memory buffer + * This method do not have to be part of a user defined allocator implementation + * and won't even be called if such a function was granted. + */ +protected: +#endif + _Tp* allocate(size_type __n, size_type& __allocated_n) { + if (__n > max_size()) { + __THROW_BAD_ALLOC; + } + if (__n != 0) { + size_type __buf_size = __n * sizeof(value_type); + _Tp* __ret = __REINTERPRET_CAST(value_type*, _S_Alloc::allocate(__buf_size, _M_state)); +#if defined (_STLP_DEBUG_UNINITIALIZED) && !defined (_STLP_DEBUG_ALLOC) + if (__ret != 0) { + memset((char*)__ret, _STLP_SHRED_BYTE, __buf_size); + } +#endif + __allocated_n = __buf_size / sizeof(value_type); + return __ret; + } + else + return 0; + } }; _STLP_TEMPLATE_NULL @@ -435,53 +397,74 @@ template inline bool operator==(const per_thread_allocator<_T1>& __a1, - const per_thread_allocator<_T2>& __a2) -{ - return __a1._M_state == __a2._M_state; -} + const per_thread_allocator<_T2>& __a2) +{ return __a1._M_state == __a2._M_state; } #ifdef _STLP_FUNCTION_TMPL_PARTIAL_ORDER template inline bool operator!=(const per_thread_allocator<_T1>& __a1, const per_thread_allocator<_T2>& __a2) -{ - return __a1._M_state != __a2._M_state; -} +{ return __a1._M_state != __a2._M_state; } #endif -#ifdef _STLP_CLASS_PARTIAL_SPECIALIZATION +#if defined (_STLP_CLASS_PARTIAL_SPECIALIZATION) template struct _Alloc_traits<_Tp, per_thread_allocator<_Atype> > -{ - typedef per_thread_allocator<_Tp> allocator_type; -}; +{ typedef per_thread_allocator<_Tp> allocator_type; }; #endif -#if !defined (_STLP_USE_NESTED_TCLASS_THROUGHT_TPARAM) +#if defined (_STLP_DONT_SUPPORT_REBIND_MEMBER_TEMPLATE) template inline per_thread_allocator<_Tp2>& -__stl_alloc_rebind(per_thread_allocator<_Tp1>& __x, const _Tp2*) { - return (per_thread_allocator<_Tp2>&)__x; -} +__stl_alloc_rebind(per_thread_allocator<_Tp1>& __x, const _Tp2*) +{ return (per_thread_allocator<_Tp2>&)__x; } template inline per_thread_allocator<_Tp2> -__stl_alloc_create(per_thread_allocator<_Tp1>&, const _Tp2*) { - return per_thread_allocator<_Tp2>(); -} +__stl_alloc_create(per_thread_allocator<_Tp1>&, const _Tp2*) +{ return per_thread_allocator<_Tp2>(); } -#endif /* _STLP_USE_NESTED_TCLASS_THROUGHT_TPARAM */ +#endif /* _STLP_DONT_SUPPORT_REBIND_MEMBER_TEMPLATE */ + +_STLP_MOVE_TO_PRIV_NAMESPACE + +template +struct __perthread_alloc_type_traits { + typedef typename _IsSTLportClass >::_Ret _STLportAlloc; + //The default allocator implementation which is recognize thanks to the + //__stlport_class inheritance is a stateless object so: + typedef __false_type has_trivial_default_constructor; + typedef _STLportAlloc has_trivial_copy_constructor; + typedef _STLportAlloc has_trivial_assignment_operator; + typedef _STLportAlloc has_trivial_destructor; + typedef __false_type is_POD_type; +}; + +_STLP_MOVE_TO_STD_NAMESPACE + +#if defined (_STLP_CLASS_PARTIAL_SPECIALIZATION) +template +struct __type_traits > : _STLP_PRIV __perthread_alloc_type_traits<_Tp> {}; +#else +_STLP_TEMPLATE_NULL +struct __type_traits > : _STLP_PRIV __perthread_alloc_type_traits {}; +# if defined (_STLP_HAS_WCHAR_T) +_STLP_TEMPLATE_NULL +struct __type_traits > : _STLP_PRIV __perthread_alloc_type_traits {}; +# endif +# if defined (_STLP_USE_PTR_SPECIALIZATIONS) +_STLP_TEMPLATE_NULL +struct __type_traits > : _STLP_PRIV __perthread_alloc_type_traits {}; +# endif +#endif + _STLP_END_NAMESPACE -# if defined (_STLP_EXPOSE_GLOBALS_IMPLEMENTATION) && !defined (_STLP_LINK_TIME_INSTANTIATION) -# include -# endif - #endif /* _STLP_PTHREAD_ALLOC */ // Local Variables: