diff --git a/redGrapes/util/atomic_list.hpp b/redGrapes/util/atomic_list.hpp index e137877b..9a02f17d 100644 --- a/redGrapes/util/atomic_list.hpp +++ b/redGrapes/util/atomic_list.hpp @@ -156,7 +156,9 @@ struct AtomicList return chunk_capacity + get_controlblock_size(); } - /* initializes a new chunk + /* allocate a new item and add it to the list + * + * @{ */ auto allocate_item() { @@ -182,6 +184,26 @@ struct AtomicList return append_item( std::allocate_shared< ItemControlBlock >( chunk_alloc, blk ) ); } + /** allocate the first item if the list is empty + * + * If more than one thread tries to add the first item only one thread will successfully add an item. + */ + bool try_allocate_first_item() + { + TRACE_EVENT("Allocator", "AtomicList::allocate_first_item()"); + StaticAlloc chunk_alloc( this->alloc, get_chunk_allocsize() ); + + // this block will contain the Item-data of ItemControlBlock + memory::Block blk{ + .ptr = (uintptr_t)chunk_alloc.ptr + get_controlblock_size(), + .len = chunk_capacity - get_controlblock_size() + }; + + auto sharedChunk = std::allocate_shared< ItemControlBlock >( chunk_alloc, blk ); + return try_append_first_item( std::move(sharedChunk) ); + } + /** @} */ + template < bool is_const = false > struct BackwardIterator { @@ -297,7 +319,15 @@ struct AtomicList return MutBackwardIterator{ old_head }; } + // append the first head item if not already exists + bool try_append_first_item( std::shared_ptr< ItemControlBlock > new_head ) + { + TRACE_EVENT("Allocator", "AtomicList::append_first_item()"); + std::shared_ptr< ItemControlBlock > expected( nullptr ); + std::shared_ptr< ItemControlBlock > const & desired = new_head; + return std::atomic_compare_exchange_strong( &head, &expected, desired ); + } }; } // namespace memory diff --git a/redGrapes/util/chunked_list.hpp b/redGrapes/util/chunked_list.hpp index b522b0d1..622551fd 100644 --- a/redGrapes/util/chunked_list.hpp +++ b/redGrapes/util/chunked_list.hpp @@ -417,9 +417,7 @@ struct ChunkedList public: ChunkedList( Allocator && alloc ) : chunks( std::move(alloc), T_chunk_size * sizeof(Item) + sizeof(Chunk) ) - { - chunks.allocate_item(); - } + {} ChunkedList( ChunkedList && other ) = default; ChunkedList( Allocator && alloc, ChunkedList const & other ) @@ -467,9 +465,8 @@ struct ChunkedList } else { - throw std::runtime_error("chunk_list: invalid state, there should always be at least one chunk available."); + chunks.try_allocate_first_item(); } - } }