-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix double free and double alloc #1
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -178,14 +178,7 @@ struct ChunkedList | |
*/ | ||
std::atomic< Item * > next_item; | ||
|
||
/* counts the number of alive elements in this chunk. | ||
* Whenever `item_count` reaches zero, the chunk will be deleted. | ||
* `item_count` starts with 1 to keep the chunk at least until | ||
* its full capacity is used. This initial offset is | ||
* compensated by not increasing the count when the last | ||
* element is inserted. | ||
*/ | ||
std::atomic< chunk_offset_t > item_count{ 0 }; | ||
std::atomic< chunk_offset_t > freed_items{ 0 }; | ||
|
||
Chunk( memory::Block blk ) | ||
: first_item( (Item*) blk.ptr ) | ||
|
@@ -424,7 +417,9 @@ 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 ) | ||
|
@@ -438,7 +433,7 @@ struct ChunkedList | |
*/ | ||
void release_chunk( typename memory::AtomicList< Chunk, Allocator >::MutBackwardIterator chunk ) | ||
{ | ||
if( chunk->item_count.fetch_sub(1) == 0 ) | ||
if( chunk->freed_items.fetch_add(1) == T_chunk_size - 1u ) | ||
chunks.erase( chunk ); | ||
} | ||
|
||
|
@@ -451,27 +446,30 @@ struct ChunkedList | |
auto chunk = chunks.rbegin(); | ||
if( chunk != chunks.rend() ) | ||
{ | ||
if( chunk->item_count.fetch_add(1) < T_chunk_size ) | ||
{ | ||
Item * chunk_begin = chunk->first_item; | ||
Item * chunk_end = chunk_begin + T_chunk_size; | ||
Item * next_item = chunk->next_item.fetch_add(1); | ||
Item * chunk_begin = chunk->first_item; | ||
Item * chunk_end = chunk_begin + T_chunk_size; | ||
Item * next_item = chunk->next_item.fetch_add(1); | ||
|
||
if( (uintptr_t)next_item < (uintptr_t)chunk_end ) | ||
if( (uintptr_t)next_item < (uintptr_t)chunk_end ) | ||
{ | ||
*next_item = item; | ||
chunk->last_item ++; | ||
if( (uintptr_t)next_item == (uintptr_t)(chunk_end - 1u)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could be moved to the position before the item is copied to provide faster new memory to other threads. |
||
{ | ||
*next_item = item; | ||
chunk->last_item ++; | ||
return MutBackwardIterator( chunk, next_item ); | ||
// the thread who took the last item of this chunk must allocate | ||
// the next batch of items | ||
chunks.allocate_item(); | ||
} | ||
return MutBackwardIterator( chunk, next_item ); | ||
} | ||
|
||
release_chunk(chunk); | ||
else | ||
chunk->next_item.fetch_sub(1); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. since we increase a 64bit pointer there should be no strong need to add this overflow guard here. |
||
} | ||
else | ||
{ | ||
throw std::runtime_error("chunk_list: invalid state, there should always be at least one chunk available."); | ||
} | ||
|
||
auto prev_chunk = chunks.allocate_item(); | ||
|
||
if( prev_chunk != chunks.rend() ) | ||
release_chunk( prev_chunk ); | ||
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I currently don't know how much the impact is, but this will decrease the speed of task-creation since every task will create four events , each containing a
ChunkedList<EventPtr>
to store the list of outgoing edges, but not all Events will actually have outgoing edges (this is also described in Issue ComputationalRadiationPhysics#42 . Maybe, to avoid this a possible condition for allocating a new chunk would benext_item == chunk_end
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
next_item == chunk_end
I think if you use this more than one thread can create the first chunk. Thats the reason why I added it to the constructor because this was the only point where I was sure that there will be no data race.