| Index: content/renderer/devtools/lock_free_circular_queue.h
|
| diff --git a/content/renderer/devtools/lock_free_circular_queue.h b/content/renderer/devtools/lock_free_circular_queue.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..dfa780bb5e7bd44111da366c446c73ac3df37689
|
| --- /dev/null
|
| +++ b/content/renderer/devtools/lock_free_circular_queue.h
|
| @@ -0,0 +1,135 @@
|
| +// Copyright 2015 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.
|
| +
|
| +#ifndef CONTENT_RENDERER_DEVTOOLS_LOCK_FREE_CIRCULAR_QUEUE_H_
|
| +#define CONTENT_RENDERER_DEVTOOLS_LOCK_FREE_CIRCULAR_QUEUE_H_
|
| +
|
| +#include "base/atomicops.h"
|
| +#include "base/memory/aligned_memory.h"
|
| +
|
| +#define CACHELINE_ALIGNED ALIGNAS(64)
|
| +
|
| +namespace content {
|
| +
|
| +MSVC_PUSH_DISABLE_WARNING(4324) // structure was padded due to align
|
| +
|
| +// Lock-free cache-friendly sampling circular queue for large
|
| +// records. Intended for fast transfer of large records between a
|
| +// single producer and a single consumer. If the queue is full,
|
| +// StartEnqueue will return nullptr. The queue is designed with
|
| +// a goal in mind to evade cache lines thrashing by preventing
|
| +// simultaneous reads and writes to adjanced memory locations.
|
| +template <typename T, unsigned Length>
|
| +class LockFreeCircularQueue {
|
| + public:
|
| + // Executed on the application thread.
|
| + LockFreeCircularQueue();
|
| + ~LockFreeCircularQueue();
|
| +
|
| + // StartEnqueue returns a pointer to a memory location for storing the next
|
| + // record or nullptr if all entries are full at the moment.
|
| + T* StartEnqueue();
|
| + // Notifies the queue that the producer has complete writing data into the
|
| + // memory returned by StartEnqueue and it can be passed to the consumer.
|
| + void FinishEnqueue();
|
| +
|
| + // Executed on the consumer (analyzer) thread.
|
| + // Retrieves, but does not remove, the head of this queue, returning nullptr
|
| + // if this queue is empty. After the record had been read by a consumer,
|
| + // Remove must be called.
|
| + T* Peek();
|
| + void Remove();
|
| +
|
| + // The class fields have stricter alignment requirements than a normal new
|
| + // can fulfil, so we need to provide our own new/delete here.
|
| + void* operator new(size_t size);
|
| + void operator delete(void* ptr);
|
| +
|
| + private:
|
| + // Reserved values for the entry marker.
|
| + enum {
|
| + kEmpty, // Marks clean (processed) entries.
|
| + kFull // Marks entries already filled by the producer but not yet
|
| + // completely processed by the consumer.
|
| + };
|
| +
|
| + struct CACHELINE_ALIGNED Entry {
|
| + Entry() : marker(kEmpty) {}
|
| + T record;
|
| + base::subtle::Atomic32 marker;
|
| + };
|
| +
|
| + Entry* Next(Entry* entry);
|
| +
|
| + Entry buffer_[Length];
|
| + CACHELINE_ALIGNED Entry* enqueue_pos_;
|
| + CACHELINE_ALIGNED Entry* dequeue_pos_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(LockFreeCircularQueue);
|
| +};
|
| +
|
| +MSVC_POP_WARNING()
|
| +
|
| +template <typename T, unsigned L>
|
| +LockFreeCircularQueue<T, L>::LockFreeCircularQueue()
|
| + : enqueue_pos_(buffer_), dequeue_pos_(buffer_) {
|
| +}
|
| +
|
| +template <typename T, unsigned L>
|
| +LockFreeCircularQueue<T, L>::~LockFreeCircularQueue() {
|
| +}
|
| +
|
| +template <typename T, unsigned L>
|
| +T* LockFreeCircularQueue<T, L>::Peek() {
|
| + base::subtle::MemoryBarrier();
|
| + if (base::subtle::Acquire_Load(&dequeue_pos_->marker) == kFull) {
|
| + return &dequeue_pos_->record;
|
| + }
|
| + return nullptr;
|
| +}
|
| +
|
| +template <typename T, unsigned L>
|
| +void LockFreeCircularQueue<T, L>::Remove() {
|
| + base::subtle::Release_Store(&dequeue_pos_->marker, kEmpty);
|
| + dequeue_pos_ = Next(dequeue_pos_);
|
| +}
|
| +
|
| +template <typename T, unsigned L>
|
| +T* LockFreeCircularQueue<T, L>::StartEnqueue() {
|
| + base::subtle::MemoryBarrier();
|
| + if (base::subtle::Acquire_Load(&enqueue_pos_->marker) == kEmpty) {
|
| + return &enqueue_pos_->record;
|
| + }
|
| + return nullptr;
|
| +}
|
| +
|
| +template <typename T, unsigned L>
|
| +void LockFreeCircularQueue<T, L>::FinishEnqueue() {
|
| + base::subtle::Release_Store(&enqueue_pos_->marker, kFull);
|
| + enqueue_pos_ = Next(enqueue_pos_);
|
| +}
|
| +
|
| +template <typename T, unsigned L>
|
| +typename LockFreeCircularQueue<T, L>::Entry* LockFreeCircularQueue<T, L>::Next(
|
| + Entry* entry) {
|
| + Entry* next = entry + 1;
|
| + if (next == &buffer_[L])
|
| + return buffer_;
|
| + return next;
|
| +}
|
| +
|
| +template <typename T, unsigned L>
|
| +void* LockFreeCircularQueue<T, L>::operator new(size_t size) {
|
| + typedef LockFreeCircularQueue<T, L> QueueTypeAlias;
|
| + return base::AlignedAlloc(size, ALIGNOF(QueueTypeAlias));
|
| +}
|
| +
|
| +template <typename T, unsigned L>
|
| +void LockFreeCircularQueue<T, L>::operator delete(void* ptr) {
|
| + base::AlignedFree(ptr);
|
| +}
|
| +
|
| +} // namespace content
|
| +
|
| +#endif // CONTENT_RENDERER_DEVTOOLS_LOCK_FREE_CIRCULAR_QUEUE_H_
|
|
|