Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-02-21 10:15:50

0001 /*
0002     Copyright (c) 2005-2020 Intel Corporation
0003 
0004     Licensed under the Apache License, Version 2.0 (the "License");
0005     you may not use this file except in compliance with the License.
0006     You may obtain a copy of the License at
0007 
0008         http://www.apache.org/licenses/LICENSE-2.0
0009 
0010     Unless required by applicable law or agreed to in writing, software
0011     distributed under the License is distributed on an "AS IS" BASIS,
0012     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013     See the License for the specific language governing permissions and
0014     limitations under the License.
0015 */
0016 
0017 #ifndef __TBB_memory_pool_H
0018 #define __TBB_memory_pool_H
0019 
0020 #if !TBB_PREVIEW_MEMORY_POOL
0021 #error Set TBB_PREVIEW_MEMORY_POOL to include memory_pool.h
0022 #endif
0023 /** @file */
0024 
0025 #include "scalable_allocator.h"
0026 #include <new> // std::bad_alloc
0027 #include <stdexcept> // std::runtime_error, std::invalid_argument
0028 // required in C++03 to construct std::runtime_error and std::invalid_argument
0029 #include <string>
0030 #if __TBB_ALLOCATOR_CONSTRUCT_VARIADIC
0031 #include <utility> // std::forward
0032 #endif
0033 
0034 #if __TBB_EXTRA_DEBUG
0035 #define __TBBMALLOC_ASSERT ASSERT
0036 #else
0037 #define __TBBMALLOC_ASSERT(a,b) ((void)0)
0038 #endif
0039 
0040 namespace tbb {
0041 namespace interface6 {
0042 //! @cond INTERNAL
0043 namespace internal {
0044 
0045 //! Base of thread-safe pool allocator for variable-size requests
0046 class pool_base : tbb::internal::no_copy {
0047     // Pool interface is separate from standard allocator classes because it has
0048     // to maintain internal state, no copy or assignment. Move and swap are possible.
0049 public:
0050     //! Reset pool to reuse its memory (free all objects at once)
0051     void recycle() { rml::pool_reset(my_pool); }
0052 
0053     //! The "malloc" analogue to allocate block of memory of size bytes
0054     void *malloc(size_t size) { return rml::pool_malloc(my_pool, size); }
0055 
0056     //! The "free" analogue to discard a previously allocated piece of memory.
0057     void free(void* ptr) { rml::pool_free(my_pool, ptr); }
0058 
0059     //! The "realloc" analogue complementing pool_malloc.
0060     // Enables some low-level optimization possibilities
0061     void *realloc(void* ptr, size_t size) {
0062         return rml::pool_realloc(my_pool, ptr, size);
0063     }
0064 
0065 protected:
0066     //! destroy pool - must be called in a child class
0067     void destroy() { rml::pool_destroy(my_pool); }
0068 
0069     rml::MemoryPool *my_pool;
0070 };
0071 
0072 } // namespace internal
0073 //! @endcond
0074 
0075 #if _MSC_VER && !defined(__INTEL_COMPILER)
0076     // Workaround for erroneous "unreferenced parameter" warning in method destroy.
0077     #pragma warning (push)
0078     #pragma warning (disable: 4100)
0079 #endif
0080 
0081 //! Meets "allocator" requirements of ISO C++ Standard, Section 20.1.5
0082 /** @ingroup memory_allocation */
0083 template<typename T, typename P = internal::pool_base>
0084 class memory_pool_allocator {
0085 protected:
0086     typedef P pool_type;
0087     pool_type *my_pool;
0088     template<typename U, typename R>
0089     friend class memory_pool_allocator;
0090     template<typename V, typename U, typename R>
0091     friend bool operator==( const memory_pool_allocator<V,R>& a, const memory_pool_allocator<U,R>& b);
0092     template<typename V, typename U, typename R>
0093     friend bool operator!=( const memory_pool_allocator<V,R>& a, const memory_pool_allocator<U,R>& b);
0094 public:
0095     typedef typename tbb::internal::allocator_type<T>::value_type value_type;
0096     typedef value_type* pointer;
0097     typedef const value_type* const_pointer;
0098     typedef value_type& reference;
0099     typedef const value_type& const_reference;
0100     typedef size_t size_type;
0101     typedef ptrdiff_t difference_type;
0102     template<typename U> struct rebind {
0103         typedef memory_pool_allocator<U, P> other;
0104     };
0105 
0106     explicit memory_pool_allocator(pool_type &pool) throw() : my_pool(&pool) {}
0107     memory_pool_allocator(const memory_pool_allocator& src) throw() : my_pool(src.my_pool) {}
0108     template<typename U>
0109     memory_pool_allocator(const memory_pool_allocator<U,P>& src) throw() : my_pool(src.my_pool) {}
0110 
0111     pointer address(reference x) const { return &x; }
0112     const_pointer address(const_reference x) const { return &x; }
0113 
0114     //! Allocate space for n objects.
0115     pointer allocate( size_type n, const void* /*hint*/ = 0) {
0116         pointer p = static_cast<pointer>( my_pool->malloc( n*sizeof(value_type) ) );
0117         if (!p)
0118             tbb::internal::throw_exception(std::bad_alloc());
0119         return p;
0120     }
0121     //! Free previously allocated block of memory.
0122     void deallocate( pointer p, size_type ) {
0123         my_pool->free(p);
0124     }
0125     //! Largest value for which method allocate might succeed.
0126     size_type max_size() const throw() {
0127         size_type max = static_cast<size_type>(-1) / sizeof (value_type);
0128         return (max > 0 ? max : 1);
0129     }
0130     //! Copy-construct value at location pointed to by p.
0131 #if __TBB_ALLOCATOR_CONSTRUCT_VARIADIC
0132     template<typename U, typename... Args>
0133     void construct(U *p, Args&&... args)
0134         { ::new((void *)p) U(std::forward<Args>(args)...); }
0135 #else // __TBB_ALLOCATOR_CONSTRUCT_VARIADIC
0136 #if __TBB_CPP11_RVALUE_REF_PRESENT
0137     void construct( pointer p, value_type&& value ) {::new((void*)(p)) value_type(std::move(value));}
0138 #endif
0139     void construct( pointer p, const value_type& value ) { ::new((void*)(p)) value_type(value); }
0140 #endif // __TBB_ALLOCATOR_CONSTRUCT_VARIADIC
0141 
0142     //! Destroy value at location pointed to by p.
0143     void destroy( pointer p ) { p->~value_type(); }
0144 
0145 };
0146 
0147 #if _MSC_VER && !defined(__INTEL_COMPILER)
0148     #pragma warning (pop)
0149 #endif // warning 4100 is back
0150 
0151 //! Analogous to std::allocator<void>, as defined in ISO C++ Standard, Section 20.4.1
0152 /** @ingroup memory_allocation */
0153 template<typename P>
0154 class memory_pool_allocator<void, P> {
0155 public:
0156     typedef P pool_type;
0157     typedef void* pointer;
0158     typedef const void* const_pointer;
0159     typedef void value_type;
0160     template<typename U> struct rebind {
0161         typedef memory_pool_allocator<U, P> other;
0162     };
0163 
0164     explicit memory_pool_allocator( pool_type &pool) throw() : my_pool(&pool) {}
0165     memory_pool_allocator( const memory_pool_allocator& src) throw() : my_pool(src.my_pool) {}
0166     template<typename U>
0167     memory_pool_allocator(const memory_pool_allocator<U,P>& src) throw() : my_pool(src.my_pool) {}
0168 
0169 protected:
0170     pool_type *my_pool;
0171     template<typename U, typename R>
0172     friend class memory_pool_allocator;
0173     template<typename V, typename U, typename R>
0174     friend bool operator==( const memory_pool_allocator<V,R>& a, const memory_pool_allocator<U,R>& b);
0175     template<typename V, typename U, typename R>
0176     friend bool operator!=( const memory_pool_allocator<V,R>& a, const memory_pool_allocator<U,R>& b);
0177 };
0178 
0179 template<typename T, typename U, typename P>
0180 inline bool operator==( const memory_pool_allocator<T,P>& a, const memory_pool_allocator<U,P>& b) {return a.my_pool==b.my_pool;}
0181 
0182 template<typename T, typename U, typename P>
0183 inline bool operator!=( const memory_pool_allocator<T,P>& a, const memory_pool_allocator<U,P>& b) {return a.my_pool!=b.my_pool;}
0184 
0185 
0186 //! Thread-safe growable pool allocator for variable-size requests
0187 template <typename Alloc>
0188 class memory_pool : public internal::pool_base {
0189     Alloc my_alloc; // TODO: base-class optimization
0190     static void *allocate_request(intptr_t pool_id, size_t & bytes);
0191     static int deallocate_request(intptr_t pool_id, void*, size_t raw_bytes);
0192 
0193 public:
0194     //! construct pool with underlying allocator
0195     explicit memory_pool(const Alloc &src = Alloc());
0196 
0197     //! destroy pool
0198     ~memory_pool() { destroy(); } // call the callbacks first and destroy my_alloc latter
0199 
0200 };
0201 
0202 class fixed_pool : public internal::pool_base {
0203     void *my_buffer;
0204     size_t my_size;
0205     inline static void *allocate_request(intptr_t pool_id, size_t & bytes);
0206 
0207 public:
0208     //! construct pool with underlying allocator
0209     inline fixed_pool(void *buf, size_t size);
0210     //! destroy pool
0211     ~fixed_pool() { destroy(); }
0212 };
0213 
0214 //////////////// Implementation ///////////////
0215 
0216 template <typename Alloc>
0217 memory_pool<Alloc>::memory_pool(const Alloc &src) : my_alloc(src) {
0218     rml::MemPoolPolicy args(allocate_request, deallocate_request,
0219                             sizeof(typename Alloc::value_type));
0220     rml::MemPoolError res = rml::pool_create_v1(intptr_t(this), &args, &my_pool);
0221     if (res!=rml::POOL_OK)
0222         tbb::internal::throw_exception(std::runtime_error("Can't create pool"));
0223 }
0224 template <typename Alloc>
0225 void *memory_pool<Alloc>::allocate_request(intptr_t pool_id, size_t & bytes) {
0226     memory_pool<Alloc> &self = *reinterpret_cast<memory_pool<Alloc>*>(pool_id);
0227     const size_t unit_size = sizeof(typename Alloc::value_type);
0228     __TBBMALLOC_ASSERT( 0 == bytes%unit_size, NULL);
0229     void *ptr;
0230     __TBB_TRY { ptr = self.my_alloc.allocate( bytes/unit_size ); }
0231     __TBB_CATCH(...) { return 0; }
0232     return ptr;
0233 }
0234 #if __TBB_MSVC_UNREACHABLE_CODE_IGNORED
0235     // Workaround for erroneous "unreachable code" warning in the template below.
0236     // Specific for VC++ 17-18 compiler
0237     #pragma warning (push)
0238     #pragma warning (disable: 4702)
0239 #endif
0240 template <typename Alloc>
0241 int memory_pool<Alloc>::deallocate_request(intptr_t pool_id, void* raw_ptr, size_t raw_bytes) {
0242     memory_pool<Alloc> &self = *reinterpret_cast<memory_pool<Alloc>*>(pool_id);
0243     const size_t unit_size = sizeof(typename Alloc::value_type);
0244     __TBBMALLOC_ASSERT( 0 == raw_bytes%unit_size, NULL);
0245     self.my_alloc.deallocate( static_cast<typename Alloc::value_type*>(raw_ptr), raw_bytes/unit_size );
0246     return 0;
0247 }
0248 #if __TBB_MSVC_UNREACHABLE_CODE_IGNORED
0249     #pragma warning (pop)
0250 #endif
0251 inline fixed_pool::fixed_pool(void *buf, size_t size) : my_buffer(buf), my_size(size) {
0252     if (!buf || !size)
0253         // TODO: improve support for mode with exceptions disabled
0254         tbb::internal::throw_exception(std::invalid_argument("Zero in parameter is invalid"));
0255     rml::MemPoolPolicy args(allocate_request, 0, size, /*fixedPool=*/true);
0256     rml::MemPoolError res = rml::pool_create_v1(intptr_t(this), &args, &my_pool);
0257     if (res!=rml::POOL_OK)
0258         tbb::internal::throw_exception(std::runtime_error("Can't create pool"));
0259 }
0260 inline void *fixed_pool::allocate_request(intptr_t pool_id, size_t & bytes) {
0261     fixed_pool &self = *reinterpret_cast<fixed_pool*>(pool_id);
0262     __TBBMALLOC_ASSERT(0 != self.my_size, "The buffer must not be used twice.");
0263     bytes = self.my_size;
0264     self.my_size = 0; // remember that buffer has been used
0265     return self.my_buffer;
0266 }
0267 
0268 } //namespace interface6
0269 using interface6::memory_pool_allocator;
0270 using interface6::memory_pool;
0271 using interface6::fixed_pool;
0272 } //namespace tbb
0273 
0274 #undef __TBBMALLOC_ASSERT
0275 #endif// __TBB_memory_pool_H