1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
|
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/tracing/core/trace_ring_buffer.h"
#include "base/threading/platform_thread.h"
namespace tracing {
namespace v2 {
TraceRingBuffer::TraceRingBuffer(uint8_t* begin, size_t size)
: num_chunks_(size / kChunkSize),
num_chunks_taken_(0),
current_chunk_idx_(0) {
DCHECK_GT(num_chunks_, 0u);
DCHECK_EQ(0ul, reinterpret_cast<uintptr_t>(begin) % sizeof(uintptr_t));
chunks_.reset(new Chunk[num_chunks_]);
uint8_t* chunk_begin = begin;
for (size_t i = 0; i < num_chunks_; ++i) {
chunks_[i].Initialize(chunk_begin);
chunk_begin += kChunkSize;
}
}
TraceRingBuffer::~TraceRingBuffer() {}
TraceRingBuffer::Chunk* TraceRingBuffer::TakeChunk(uint32_t writer_id) {
base::AutoLock lock(lock_);
DCHECK_GT(num_chunks_, 0ul);
DCHECK_LT(current_chunk_idx_, num_chunks_);
for (size_t i = 0; i < num_chunks_; ++i) {
Chunk* chunk = &chunks_[current_chunk_idx_];
current_chunk_idx_ = (current_chunk_idx_ + 1) % num_chunks_;
if (!chunk->is_owned()) {
chunk->Clear();
DCHECK_NE(0u, writer_id);
chunk->set_owner(writer_id);
num_chunks_taken_++;
return chunk;
}
}
// Bankrupcy: there are more threads than chunks. All chunks were in flight.
if (!bankrupcy_chunk_storage_) {
bankrupcy_chunk_storage_.reset(new uint8_t[kChunkSize]);
bankrupcy_chunk_.Initialize(&bankrupcy_chunk_storage_.get()[0]);
}
bankrupcy_chunk_.Clear();
return &bankrupcy_chunk_;
}
void TraceRingBuffer::ReturnChunk(TraceRingBuffer::Chunk* chunk) {
// Returning a chunk without using it is quite odd, very likely a bug.
DCHECK_GT(chunk->used_size(), 0u);
// The caller should never return chunks which are part of a retaining chain.
DCHECK(!chunk->next_in_owner_list());
if (chunk == &bankrupcy_chunk_)
return;
// TODO(primiano): this lock might be removed in favor of acquire/release
// semantics on the two vars below. Check once the reader of these are landed.
base::AutoLock lock(lock_);
chunk->clear_owner();
num_chunks_taken_--;
}
bool TraceRingBuffer::IsBankrupcyChunkForTesting(const Chunk* chunk) const {
return chunk == &bankrupcy_chunk_;
}
size_t TraceRingBuffer::GetNumChunksTaken() const {
base::AutoLock lock(lock_);
return num_chunks_taken_;
}
TraceRingBuffer::Chunk::Chunk()
: begin_(nullptr), owner_(kNoChunkOwner), next_in_owner_list_(nullptr) {}
TraceRingBuffer::Chunk::~Chunk() {}
void TraceRingBuffer::Chunk::Clear() {
set_used_size(0);
set_next_in_owner_list(nullptr);
}
void TraceRingBuffer::Chunk::Initialize(uint8_t* begin) {
DCHECK_EQ(0ul, reinterpret_cast<uintptr_t>(begin) % sizeof(uintptr_t));
begin_ = begin;
}
} // namespace v2
} // namespace tracing
|