OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #ifndef MOJO_SERVICES_MEDIA_COMMON_CPP_FIFO_ALLOCATOR_H_ | |
6 #define MOJO_SERVICES_MEDIA_COMMON_CPP_FIFO_ALLOCATOR_H_ | |
7 | |
8 #include <cstdint> | |
9 | |
10 namespace mojo { | |
11 namespace media { | |
12 | |
13 // FifoAllocator implements heap semantics on a single contiguous buffer using | |
14 // a strategy that is especially suited to streaming. Allocations can vary in | |
15 // size, but the expectation is that regions will be released in roughly the | |
16 // order they were allocated (hence 'Fifo'). It's important that FifoAllocator | |
17 // be used in this way. FifoAllocator can deal with regions that don't get | |
18 // released in the order they were allocated, but they can potentially fragment | |
19 // the buffer and impact performance. | |
20 // | |
21 // FifoAllocator doesn't actually deal with any particular region of memory. It | |
22 // simply does the bookkeeping regarding how a buffer of a given size is | |
23 // allocated into regions. | |
24 // | |
25 // DESIGN: | |
26 // | |
27 // FifoAllocator maintains an ordered list of regions that partition the buffer. | |
28 // Some regions are allocated and some are free. Free regions are always | |
29 // coalesced, so there are no two adjacent free regions. Allocated regions are | |
30 // not coalesced. There is always at least one free region. | |
31 // | |
32 // One free region is distinguished as the 'active' region. New allocations are | |
33 // taken from the front of the active region. If the active region is too small | |
34 // to accommodate a requested allocation, FifoAllocator walks the list looking | |
35 // for an unallocated region that's large enough. The old active region becomes | |
36 // an unused scrap that is recovered when the active region catches up to it | |
37 // again. In some cases, the active region has a length of zero. | |
38 // | |
39 // The allocation strategy that emerges from all this is well-suited to many | |
40 // streaming scenarios in which packets vary in size. If packets are of | |
41 // consistent size, this strategy will still work, but is overkill given that | |
42 // a fixed set of regions can be preallocated from the buffer. | |
43 // | |
44 // An internal region structure is employed to represent the list of regions. | |
45 // FifoAllocator keeps unused region structures in a lookaside and never deletes | |
46 // them until the FifoAllocator is deleted. This could cause a large number of | |
47 // region structures to sit unused if the number of regions ever gets large. | |
48 // This is generally not an issue for the streaming scenarios for which the | |
49 // class is intended. | |
50 // | |
51 // Deallocations (releases) employ a sequential search for a matching | |
52 // region. The search is done starting immediately after the active region, so | |
53 // it typically finds the desired region immediately. If the number of regions | |
54 // is very large and deallocation is frequently done out of order, the | |
55 // sequential searches may be a performance issue. | |
56 class FifoAllocator { | |
57 public: | |
58 // Returned by AllocatedRegion when the requested allocation cannot be | |
59 // performed. | |
60 static const uint64_t kNullOffset = 0xffffffffffffffff; | |
johngro
2015/12/05 00:45:55
std::numeric_limits<uint64_t>::max()
You will nee
dalesat
2015/12/07 18:30:20
Done.
| |
61 | |
62 FifoAllocator(uint64_t size); | |
63 | |
64 ~FifoAllocator(); | |
65 | |
66 // Returns the size of the entire buffer as determined by the call to the | |
67 // constructor or the most recent call to Reset. | |
68 uint64_t size() { | |
69 return size_; | |
70 } | |
71 | |
72 // Resets the buffer manager to its initial state (no regions allocated) | |
73 // with a new buffer size. Also deletes all the regions in the lookaside. | |
74 void Reset(uint64_t size); | |
75 | |
76 // Allocates a region and returns its offset or kNullOffset if the allocation | |
77 // could not be performed. | |
78 uint64_t AllocateRegion(uint64_t size); | |
79 | |
80 // Releases a previously-allocated region. | |
81 void ReleaseRegion(uint64_t size, uint64_t offset); | |
82 | |
83 private: | |
84 // List element to track allocated and free regions. | |
85 struct Region { | |
86 bool allocated; | |
87 uint64_t size; | |
88 uint64_t offset; | |
89 | |
90 // Intrusive list pointers. | |
91 Region* prev; | |
92 Region* next; | |
93 }; | |
94 | |
95 // Releases the specified region if it's found between begin (inclusive) and | |
96 // end (exclusive). | |
97 bool Release(uint64_t size, uint64_t offset, Region* begin, Region* end); | |
98 | |
99 // Advances the active region to one that's at least the specified size. | |
100 // Returns false if none could be found. | |
101 bool AdvanceActive(uint64_t size); | |
102 | |
103 // Does the above for the interval between begin (inclusive) and end | |
104 // (exclusive). | |
105 bool AdvanceActive(uint64_t size, Region* begin, Region* end); | |
106 | |
107 // Inserts a zero-sized region after active_ and makes that the active region. | |
108 void MakeActivePlaceholder(); | |
109 | |
110 // Deletes a list of regions by following their next pointers. | |
111 void DeleteFrontToBack(Region* region); | |
112 | |
113 // Removes a region from the list. | |
114 void remove(Region* region); | |
115 | |
116 // Inserts a region into the list before the specified region. | |
117 void insert_before(Region* region, Region* before_this); | |
118 | |
119 // gets a free region structure, checking the lookaside first. | |
120 Region* get_free(bool allocated, uint64_t size, uint64_t offset); | |
121 | |
122 // Saves a unused region structure to the lookaside. | |
123 void put_free(Region* region) { | |
124 region->next = free_; | |
125 free_ = region; | |
126 } | |
127 | |
128 // Total size of the buffer to be managed. The sum of the sizes of all the | |
129 // regions in the list should equal size_. | |
130 uint64_t size_; | |
131 | |
132 // Doubly-linked intrusive list of current regions in offset order. | |
133 Region* front_; | |
134 Region* back_; | |
135 | |
136 // Lookaside for free region objects. | |
137 Region* free_; | |
138 | |
139 // Unallocated region from which allocations are currently being made. | |
140 Region* active_; | |
141 }; | |
142 | |
143 } // namespace media | |
144 } // namespace mojo | |
145 | |
146 #endif // MOJO_SERVICES_MEDIA_COMMON_CPP_FIFO_ALLOCATOR_H_ | |
OLD | NEW |