| Index: mojo/services/media/common/cpp/fifo_allocator.h
|
| diff --git a/mojo/services/media/common/cpp/fifo_allocator.h b/mojo/services/media/common/cpp/fifo_allocator.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..538223e9b169c4d53242eefbf70f8930567ae42a
|
| --- /dev/null
|
| +++ b/mojo/services/media/common/cpp/fifo_allocator.h
|
| @@ -0,0 +1,147 @@
|
| +// 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 MOJO_SERVICES_MEDIA_COMMON_CPP_FIFO_ALLOCATOR_H_
|
| +#define MOJO_SERVICES_MEDIA_COMMON_CPP_FIFO_ALLOCATOR_H_
|
| +
|
| +#include <cstdint>
|
| +#include <limits>
|
| +
|
| +namespace mojo {
|
| +namespace media {
|
| +
|
| +// FifoAllocator implements heap semantics on a single contiguous buffer using
|
| +// a strategy that is especially suited to streaming. Allocations can vary in
|
| +// size, but the expectation is that regions will be released in roughly the
|
| +// order they were allocated (hence 'Fifo'). It's important that FifoAllocator
|
| +// be used in this way. FifoAllocator can deal with regions that don't get
|
| +// released in the order they were allocated, but they can potentially fragment
|
| +// the buffer and impact performance.
|
| +//
|
| +// FifoAllocator doesn't actually deal with any particular region of memory. It
|
| +// simply does the bookkeeping regarding how a buffer of a given size is
|
| +// allocated into regions.
|
| +//
|
| +// DESIGN:
|
| +//
|
| +// FifoAllocator maintains an ordered list of regions that partition the buffer.
|
| +// Some regions are allocated and some are free. Free regions are always
|
| +// coalesced, so there are no two adjacent free regions. Allocated regions are
|
| +// not coalesced. There is always at least one free region.
|
| +//
|
| +// One free region is distinguished as the 'active' region. New allocations are
|
| +// taken from the front of the active region. If the active region is too small
|
| +// to accommodate a requested allocation, FifoAllocator walks the list looking
|
| +// for an unallocated region that's large enough. The old active region becomes
|
| +// an unused scrap that is recovered when the active region catches up to it
|
| +// again. In some cases, the active region has a length of zero.
|
| +//
|
| +// The allocation strategy that emerges from all this is well-suited to many
|
| +// streaming scenarios in which packets vary in size. If packets are of
|
| +// consistent size, this strategy will still work, but is overkill given that
|
| +// a fixed set of regions can be preallocated from the buffer.
|
| +//
|
| +// An internal region structure is employed to represent the list of regions.
|
| +// FifoAllocator keeps unused region structures in a lookaside and never deletes
|
| +// them until the FifoAllocator is deleted. This could cause a large number of
|
| +// region structures to sit unused if the number of regions ever gets large.
|
| +// This is generally not an issue for the streaming scenarios for which the
|
| +// class is intended.
|
| +//
|
| +// Deallocations (releases) employ a sequential search for a matching
|
| +// region. The search is done starting immediately after the active region, so
|
| +// it typically finds the desired region immediately. If the number of regions
|
| +// is very large and deallocation is frequently done out of order, the
|
| +// sequential searches may be a performance issue.
|
| +class FifoAllocator {
|
| + public:
|
| + // Returned by AllocatedRegion when the requested allocation cannot be
|
| + // performed.
|
| + static const uint64_t kNullOffset = std::numeric_limits<uint64_t>::max();
|
| +
|
| + FifoAllocator(uint64_t size);
|
| +
|
| + ~FifoAllocator();
|
| +
|
| + // Returns the size of the entire buffer as determined by the call to the
|
| + // constructor or the most recent call to Reset.
|
| + uint64_t size() const {
|
| + return size_;
|
| + }
|
| +
|
| + // Resets the buffer manager to its initial state (no regions allocated)
|
| + // with a new buffer size. Also deletes all the regions in the lookaside.
|
| + void Reset(uint64_t size);
|
| +
|
| + // Allocates a region and returns its offset or kNullOffset if the allocation
|
| + // could not be performed.
|
| + uint64_t AllocateRegion(uint64_t size);
|
| +
|
| + // Releases a previously-allocated region.
|
| + void ReleaseRegion(uint64_t size, uint64_t offset);
|
| +
|
| + private:
|
| + // List element to track allocated and free regions.
|
| + struct Region {
|
| + bool allocated;
|
| + uint64_t size;
|
| + uint64_t offset;
|
| +
|
| + // Intrusive list pointers.
|
| + Region* prev;
|
| + Region* next;
|
| + };
|
| +
|
| + // Releases the specified region if it's found between begin (inclusive) and
|
| + // end (exclusive).
|
| + bool Release(uint64_t size, uint64_t offset, Region* begin, Region* end);
|
| +
|
| + // Advances the active region to one that's at least the specified size.
|
| + // Returns false if none could be found.
|
| + bool AdvanceActive(uint64_t size);
|
| +
|
| + // Does the above for the interval between begin (inclusive) and end
|
| + // (exclusive).
|
| + bool AdvanceActive(uint64_t size, Region* begin, Region* end);
|
| +
|
| + // Inserts a zero-sized region after active_ and makes that the active region.
|
| + void MakeActivePlaceholder();
|
| +
|
| + // Deletes a list of regions by following their next pointers.
|
| + void DeleteFrontToBack(Region* region);
|
| +
|
| + // Removes a region from the list.
|
| + void remove(Region* region);
|
| +
|
| + // Inserts a region into the list before the specified region.
|
| + void insert_before(Region* region, Region* before_this);
|
| +
|
| + // gets a free region structure, checking the lookaside first.
|
| + Region* get_free(bool allocated, uint64_t size, uint64_t offset);
|
| +
|
| + // Saves a unused region structure to the lookaside.
|
| + void put_free(Region* region) {
|
| + region->next = free_;
|
| + free_ = region;
|
| + }
|
| +
|
| + // Total size of the buffer to be managed. The sum of the sizes of all the
|
| + // regions in the list should equal size_.
|
| + uint64_t size_;
|
| +
|
| + // Doubly-linked intrusive list of current regions in offset order.
|
| + Region* front_;
|
| + Region* back_;
|
| +
|
| + // Lookaside for free region objects.
|
| + Region* free_;
|
| +
|
| + // Unallocated region from which allocations are currently being made.
|
| + Region* active_;
|
| +};
|
| +
|
| +} // namespace media
|
| +} // namespace mojo
|
| +
|
| +#endif // MOJO_SERVICES_MEDIA_COMMON_CPP_FIFO_ALLOCATOR_H_
|
|
|