MCPcopy Create free account
hub / github.com/cameron314/concurrentqueue / MOODYCAMEL_NO_TSAN enqueue_bulk

Function MOODYCAMEL_NO_TSAN enqueue_bulk

concurrentqueue.h:2077–2251  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

2075
2076 template<AllocationMode allocMode, typename It>
2077 bool MOODYCAMEL_NO_TSAN enqueue_bulk(It itemFirst, size_t count)
2078 {
2079 // First, we need to make sure we have enough room to enqueue all of the elements;
2080 // this means pre-allocating blocks and putting them in the block index (but only if
2081 // all the allocations succeeded).
2082 index_t startTailIndex = this->tailIndex.load(std::memory_order_relaxed);
2083 auto startBlock = this->tailBlock;
2084 auto originalBlockIndexFront = pr_blockIndexFront;
2085 auto originalBlockIndexSlotsUsed = pr_blockIndexSlotsUsed;
2086
2087 Block* firstAllocatedBlock = nullptr;
2088
2089 // Figure out how many blocks we'll need to allocate, and do so
2090 size_t blockBaseDiff = ((startTailIndex + count - 1) & ~static_cast<index_t>(BLOCK_SIZE - 1)) - ((startTailIndex - 1) & ~static_cast<index_t>(BLOCK_SIZE - 1));
2091 index_t currentTailIndex = (startTailIndex - 1) & ~static_cast<index_t>(BLOCK_SIZE - 1);
2092 if (blockBaseDiff > 0) {
2093 // Allocate as many blocks as possible from ahead
2094 while (blockBaseDiff > 0 && this->tailBlock != nullptr && this->tailBlock->next != firstAllocatedBlock && this->tailBlock->next->ConcurrentQueue::Block::template is_empty<explicit_context>()) {
2095 blockBaseDiff -= static_cast<index_t>(BLOCK_SIZE);
2096 currentTailIndex += static_cast<index_t>(BLOCK_SIZE);
2097
2098 this->tailBlock = this->tailBlock->next;
2099 firstAllocatedBlock = firstAllocatedBlock == nullptr ? this->tailBlock : firstAllocatedBlock;
2100
2101 auto& entry = blockIndex.load(std::memory_order_relaxed)->entries[pr_blockIndexFront];
2102 entry.base = currentTailIndex;
2103 entry.block = this->tailBlock;
2104 pr_blockIndexFront = (pr_blockIndexFront + 1) & (pr_blockIndexSize - 1);
2105 }
2106
2107 // Now allocate as many blocks as necessary from the block pool
2108 while (blockBaseDiff > 0) {
2109 blockBaseDiff -= static_cast<index_t>(BLOCK_SIZE);
2110 currentTailIndex += static_cast<index_t>(BLOCK_SIZE);
2111
2112 auto head = this->headIndex.load(std::memory_order_relaxed);
2113 assert(!details::circular_less_than<index_t>(currentTailIndex, head));
2114 bool full = !details::circular_less_than<index_t>(head, currentTailIndex + BLOCK_SIZE) || (MAX_SUBQUEUE_SIZE != details::const_numeric_max<size_t>::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head));
2115 if (pr_blockIndexRaw == nullptr || pr_blockIndexSlotsUsed == pr_blockIndexSize || full) {
2116 MOODYCAMEL_CONSTEXPR_IF (allocMode == CannotAlloc) {
2117 // Failed to allocate, undo changes (but keep injected blocks)
2118 pr_blockIndexFront = originalBlockIndexFront;
2119 pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed;
2120 this->tailBlock = startBlock == nullptr ? firstAllocatedBlock : startBlock;
2121 return false;
2122 }
2123 else if (full || !new_block_index(originalBlockIndexSlotsUsed)) {
2124 // Failed to allocate, undo changes (but keep injected blocks)
2125 pr_blockIndexFront = originalBlockIndexFront;
2126 pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed;
2127 this->tailBlock = startBlock == nullptr ? firstAllocatedBlock : startBlock;
2128 return false;
2129 }
2130
2131 // pr_blockIndexFront is updated inside new_block_index, so we need to
2132 // update our fallback value too (since we keep the new index even if we
2133 // later fail)
2134 originalBlockIndexFront = originalBlockIndexSlotsUsed;

Callers

nothing calls this directly

Calls 6

assertClass · 0.85
MOODYCAMEL_CONSTEXPR_IFFunction · 0.85
new_block_indexFunction · 0.85
whileFunction · 0.85
deref_noexceptFunction · 0.85
loadMethod · 0.45

Tested by

no test coverage detected