diff --git a/include/tscore/Allocator.h b/include/tscore/Allocator.h index c03f996ab84..fd5200bb960 100644 --- a/include/tscore/Allocator.h +++ b/include/tscore/Allocator.h @@ -41,6 +41,7 @@ #include #include +#include #include "tscore/ink_queue.h" #include "tscore/ink_defs.h" #include "tscore/ink_resource.h" @@ -108,29 +109,39 @@ class Allocator ink_freelist_madvise_init(&this->fl, name, element_size, chunk_size, alignment, advice); } + // Dummies + void + destroy_if_enabled(void *) + { + } + Allocator & + raw() + { + return *this; + } + protected: InkFreeList *fl; }; /** - Allocator for Class objects. It uses a prototype object to do - fast initialization. Prototype of the template class is created - when the fast allocator is created. This is instantiated with - default (no argument) constructor. Constructor is not called for - the allocated objects. Instead, the prototype is just memory - copied onto the new objects. This is done for performance reasons. + Allocator for Class objects. */ -template class ClassAllocator : public Allocator +template class ClassAllocator : private Allocator { public: - /** Allocates objects of the templated type. */ + using Value_type = C; + static bool const Destruct_on_free = Destruct_on_free_; + + /** Allocates objects of the templated type. Arguments are forwarded to the constructor for the object. */ + template C * - alloc() + alloc(Args &&... args) { void *ptr = ink_freelist_new(this->fl); - memcpy(ptr, (void *)&this->proto.typeObject, sizeof(C)); + ::new (ptr) C(std::forward(args)...); return (C *)ptr; } @@ -142,82 +153,47 @@ template class ClassAllocator : public Allocator void free(C *ptr) { + destroy_if_enabled(ptr); + ink_freelist_free(this->fl, ptr); } /** - Deallocates objects of the templated type. - - @param head pointer to be freed. - @param tail pointer to be freed. - @param num_item of blocks to be freed. - */ - void - free_bulk(C *head, C *tail, size_t num_item) - { - ink_freelist_free_bulk(this->fl, head, tail, num_item); - } + Create a new class specific ClassAllocator. - /** - Allocate objects of the templated type via the inherited interface - using void pointers. + @param name some identifying name, used for mem tracking purposes. + @param chunk_size number of units to be allocated if free pool is empty. + @param alignment of objects must be a power of 2. */ - void * - alloc_void() + ClassAllocator(const char *name, unsigned int chunk_size = 128, unsigned int alignment = 16) { - return (void *)alloc(); + ink_freelist_init(&this->fl, name, RND16(sizeof(C)), chunk_size, RND16(alignment)); } - /** - Deallocate objects of the templated type via the inherited - interface using void pointers. - - @param ptr pointer to be freed. - */ - void - free_void(void *ptr) + Allocator & + raw() { - free((C *)ptr); + return *this; } - /** - Deallocate objects of the templated type via the inherited - interface using void pointers. - - @param head pointer to be freed. - @param tail pointer to be freed. - @param num_item of blocks. - */ void - free_void_bulk(void *head, void *tail, size_t num_item) + destroy_if_enabled(C *ptr) { - free_bulk((C *)head, (C *)tail, num_item); - } - - /** - Create a new class specific ClassAllocator. - - @param name some identifying name, used for mem tracking purposes. - @param chunk_size number of units to be allocated if free pool is empty. - @param alignment of objects must be a power of 2. - */ - ClassAllocator(const char *name, unsigned int chunk_size = 128, unsigned int alignment = 16) - { - ::new ((void *)&proto.typeObject) C(); - ink_freelist_init(&this->fl, name, RND16(sizeof(C)), chunk_size, RND16(alignment)); + if (Destruct_on_free) { + ptr->~C(); + } } - struct { - uint8_t typeObject[sizeof(C)]; - int64_t space_holder = 0; - } proto; + // Ensure that C is big enough to hold a void pointer (when it's stored in the free list as raw memory). + // + static_assert(sizeof(C) >= sizeof(void *), "Can not allocate instances of this class using ClassAllocator"); }; -template class TrackerClassAllocator : public ClassAllocator +template class TrackerClassAllocator : public ClassAllocator { public: TrackerClassAllocator(const char *name, unsigned int chunk_size = 128, unsigned int alignment = 16) - : ClassAllocator(name, chunk_size, alignment), allocations(0), trackerLock(PTHREAD_MUTEX_INITIALIZER) + : ClassAllocator(name, chunk_size, alignment), allocations(0), trackerLock(PTHREAD_MUTEX_INITIALIZER) { } @@ -226,7 +202,7 @@ template class TrackerClassAllocator : public ClassAllocator { void *callstack[3]; int frames = backtrace(callstack, 3); - C *ptr = ClassAllocator::alloc(); + C *ptr = ClassAllocator::alloc(); const void *symbol = nullptr; if (frames == 3 && callstack[2] != nullptr) { @@ -252,7 +228,7 @@ template class TrackerClassAllocator : public ClassAllocator reverse_lookup.erase(it); } ink_mutex_release(&trackerLock); - ClassAllocator::free(ptr); + ClassAllocator::free(ptr); } private: diff --git a/iocore/cache/P_CacheInternal.h b/iocore/cache/P_CacheInternal.h index 3e05f2cdcf9..70f670537d8 100644 --- a/iocore/cache/P_CacheInternal.h +++ b/iocore/cache/P_CacheInternal.h @@ -422,7 +422,7 @@ struct CacheVC : public CacheVConnection { Ptr blocks; // data available to write Ptr writer_buf; - OpenDirEntry *od; + OpenDirEntry *od = nullptr; AIOCallbackInternal io; int alternate_index = CACHE_ALT_INDEX_DEFAULT; // preferred position in vector LINK(CacheVC, opendir_link); diff --git a/iocore/eventsystem/I_ProxyAllocator.h b/iocore/eventsystem/I_ProxyAllocator.h index a5edd125fd0..346591d91d2 100644 --- a/iocore/eventsystem/I_ProxyAllocator.h +++ b/iocore/eventsystem/I_ProxyAllocator.h @@ -30,6 +30,9 @@ *****************************************************************************/ #pragma once +#include +#include + #include "tscore/ink_platform.h" class EThread; @@ -45,84 +48,51 @@ struct ProxyAllocator { ProxyAllocator() {} }; -template -inline C * -thread_alloc(ClassAllocator &a, ProxyAllocator &l) +template +typename CAlloc::Value_type * +thread_alloc(CAlloc &a, ProxyAllocator &l, Args &&... args) { if (!cmd_disable_pfreelist && l.freelist) { - C *v = (C *)l.freelist; - l.freelist = *(C **)l.freelist; + void *v = l.freelist; + l.freelist = *reinterpret_cast(l.freelist); --(l.allocated); - *(void **)v = *(void **)&a.proto.typeObject; - return v; + ::new (v) typename CAlloc::Value_type(std::forward(args)...); + return static_cast(v); } - return a.alloc(); + return a.alloc(std::forward(args)...); } -template -inline C * -thread_alloc_init(ClassAllocator &a, ProxyAllocator &l) -{ - if (!cmd_disable_pfreelist && l.freelist) { - C *v = (C *)l.freelist; - l.freelist = *(C **)l.freelist; - --(l.allocated); - memcpy((void *)v, (void *)&a.proto.typeObject, sizeof(C)); - return v; - } - return a.alloc(); -} +class Allocator; -template -inline void -thread_free(ClassAllocator &a, C *p) -{ - a.free(p); -} +void *thread_alloc(Allocator &a, ProxyAllocator &l); +void thread_freeup(Allocator &a, ProxyAllocator &l); -static inline void -thread_free(Allocator &a, void *p) -{ - a.free_void(p); -} +#if 1 -template -inline void -thread_freeup(ClassAllocator &a, ProxyAllocator &l) -{ - C *head = (C *)l.freelist; - C *tail = (C *)l.freelist; - size_t count = 0; - while (l.freelist && l.allocated > thread_freelist_low_watermark) { - tail = (C *)l.freelist; - l.freelist = *(C **)l.freelist; - --(l.allocated); - ++count; - } +// Potentially empty varaiable arguments -- non-standard GCC way +// +#define THREAD_ALLOC(_a, _t, ...) thread_alloc(::_a, _t->_a, ##__VA_ARGS__) +#define THREAD_ALLOC_INIT(_a, _t, ...) thread_alloc(::_a, _t->_a, ##__VA_ARGS__) - if (unlikely(count == 1)) { - a.free(tail); - } else if (count > 0) { - a.free_bulk(head, tail, count); - } +#else - ink_assert(l.allocated >= thread_freelist_low_watermark); -} +// Potentially empty varaiable arguments -- Standard C++20 way +// +#define THREAD_ALLOC(_a, _t, ...) thread_alloc(::_a, _t->_a __VA_OPT__(, ) __VA_ARGS__) +#define THREAD_ALLOC_INIT(_a, _t, ...) thread_alloc(::_a, _t->_a __VA_OPT__(, ) __VA_ARGS__) -void *thread_alloc(Allocator &a, ProxyAllocator &l); -void thread_freeup(Allocator &a, ProxyAllocator &l); +#endif -#define THREAD_ALLOC(_a, _t) thread_alloc(::_a, _t->_a) -#define THREAD_ALLOC_INIT(_a, _t) thread_alloc_init(::_a, _t->_a) #define THREAD_FREE(_p, _a, _t) \ - if (!cmd_disable_pfreelist) { \ - do { \ + do { \ + ::_a.destroy_if_enabled(_p); \ + if (!cmd_disable_pfreelist) { \ *(char **)_p = (char *)_t->_a.freelist; \ _t->_a.freelist = _p; \ _t->_a.allocated++; \ if (_t->_a.allocated > thread_freelist_high_watermark) \ - thread_freeup(::_a, _t->_a); \ - } while (0); \ - } else { \ - thread_free(::_a, _p); \ - } + thread_freeup(::_a.raw(), _t->_a); \ + } else { \ + ::_a.raw().free_void(_p); \ + } \ + } while (0)