1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker * Copyright (C) 2007 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker *
4*38e8c45fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker *
8*38e8c45fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker *
10*38e8c45fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker */
16*38e8c45fSAndroid Build Coastguard Worker
17*38e8c45fSAndroid Build Coastguard Worker #define LOG_TAG "MemoryDealer"
18*38e8c45fSAndroid Build Coastguard Worker
19*38e8c45fSAndroid Build Coastguard Worker #include <binder/MemoryDealer.h>
20*38e8c45fSAndroid Build Coastguard Worker #include <binder/IPCThreadState.h>
21*38e8c45fSAndroid Build Coastguard Worker #include <binder/MemoryBase.h>
22*38e8c45fSAndroid Build Coastguard Worker
23*38e8c45fSAndroid Build Coastguard Worker #include <utils/Log.h>
24*38e8c45fSAndroid Build Coastguard Worker #include <utils/SortedVector.h>
25*38e8c45fSAndroid Build Coastguard Worker #include <utils/String8.h>
26*38e8c45fSAndroid Build Coastguard Worker
27*38e8c45fSAndroid Build Coastguard Worker #include <stdint.h>
28*38e8c45fSAndroid Build Coastguard Worker #include <stdio.h>
29*38e8c45fSAndroid Build Coastguard Worker #include <stdlib.h>
30*38e8c45fSAndroid Build Coastguard Worker #include <fcntl.h>
31*38e8c45fSAndroid Build Coastguard Worker #include <unistd.h>
32*38e8c45fSAndroid Build Coastguard Worker #include <errno.h>
33*38e8c45fSAndroid Build Coastguard Worker #include <string.h>
34*38e8c45fSAndroid Build Coastguard Worker
35*38e8c45fSAndroid Build Coastguard Worker #include <sys/stat.h>
36*38e8c45fSAndroid Build Coastguard Worker #include <sys/types.h>
37*38e8c45fSAndroid Build Coastguard Worker #include <sys/mman.h>
38*38e8c45fSAndroid Build Coastguard Worker #include <sys/file.h>
39*38e8c45fSAndroid Build Coastguard Worker
40*38e8c45fSAndroid Build Coastguard Worker namespace android {
41*38e8c45fSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
42*38e8c45fSAndroid Build Coastguard Worker
43*38e8c45fSAndroid Build Coastguard Worker /*
44*38e8c45fSAndroid Build Coastguard Worker * A simple templatized doubly linked-list implementation
45*38e8c45fSAndroid Build Coastguard Worker */
46*38e8c45fSAndroid Build Coastguard Worker
47*38e8c45fSAndroid Build Coastguard Worker template <typename NODE>
48*38e8c45fSAndroid Build Coastguard Worker class LinkedList
49*38e8c45fSAndroid Build Coastguard Worker {
50*38e8c45fSAndroid Build Coastguard Worker NODE* mFirst;
51*38e8c45fSAndroid Build Coastguard Worker NODE* mLast;
52*38e8c45fSAndroid Build Coastguard Worker
53*38e8c45fSAndroid Build Coastguard Worker public:
LinkedList()54*38e8c45fSAndroid Build Coastguard Worker LinkedList() : mFirst(nullptr), mLast(nullptr) { }
isEmpty() const55*38e8c45fSAndroid Build Coastguard Worker bool isEmpty() const { return mFirst == nullptr; }
head() const56*38e8c45fSAndroid Build Coastguard Worker NODE const* head() const { return mFirst; }
head()57*38e8c45fSAndroid Build Coastguard Worker NODE* head() { return mFirst; }
tail() const58*38e8c45fSAndroid Build Coastguard Worker NODE const* tail() const { return mLast; }
tail()59*38e8c45fSAndroid Build Coastguard Worker NODE* tail() { return mLast; }
60*38e8c45fSAndroid Build Coastguard Worker
insertAfter(NODE * node,NODE * newNode)61*38e8c45fSAndroid Build Coastguard Worker void insertAfter(NODE* node, NODE* newNode) {
62*38e8c45fSAndroid Build Coastguard Worker newNode->prev = node;
63*38e8c45fSAndroid Build Coastguard Worker newNode->next = node->next;
64*38e8c45fSAndroid Build Coastguard Worker if (node->next == nullptr) mLast = newNode;
65*38e8c45fSAndroid Build Coastguard Worker else node->next->prev = newNode;
66*38e8c45fSAndroid Build Coastguard Worker node->next = newNode;
67*38e8c45fSAndroid Build Coastguard Worker }
68*38e8c45fSAndroid Build Coastguard Worker
insertBefore(NODE * node,NODE * newNode)69*38e8c45fSAndroid Build Coastguard Worker void insertBefore(NODE* node, NODE* newNode) {
70*38e8c45fSAndroid Build Coastguard Worker newNode->prev = node->prev;
71*38e8c45fSAndroid Build Coastguard Worker newNode->next = node;
72*38e8c45fSAndroid Build Coastguard Worker if (node->prev == nullptr) mFirst = newNode;
73*38e8c45fSAndroid Build Coastguard Worker else node->prev->next = newNode;
74*38e8c45fSAndroid Build Coastguard Worker node->prev = newNode;
75*38e8c45fSAndroid Build Coastguard Worker }
76*38e8c45fSAndroid Build Coastguard Worker
insertHead(NODE * newNode)77*38e8c45fSAndroid Build Coastguard Worker void insertHead(NODE* newNode) {
78*38e8c45fSAndroid Build Coastguard Worker if (mFirst == nullptr) {
79*38e8c45fSAndroid Build Coastguard Worker mFirst = mLast = newNode;
80*38e8c45fSAndroid Build Coastguard Worker newNode->prev = newNode->next = nullptr;
81*38e8c45fSAndroid Build Coastguard Worker } else {
82*38e8c45fSAndroid Build Coastguard Worker newNode->prev = nullptr;
83*38e8c45fSAndroid Build Coastguard Worker newNode->next = mFirst;
84*38e8c45fSAndroid Build Coastguard Worker mFirst->prev = newNode;
85*38e8c45fSAndroid Build Coastguard Worker mFirst = newNode;
86*38e8c45fSAndroid Build Coastguard Worker }
87*38e8c45fSAndroid Build Coastguard Worker }
88*38e8c45fSAndroid Build Coastguard Worker
insertTail(NODE * newNode)89*38e8c45fSAndroid Build Coastguard Worker void insertTail(NODE* newNode) {
90*38e8c45fSAndroid Build Coastguard Worker if (mLast == 0) {
91*38e8c45fSAndroid Build Coastguard Worker insertHead(newNode);
92*38e8c45fSAndroid Build Coastguard Worker } else {
93*38e8c45fSAndroid Build Coastguard Worker newNode->prev = mLast;
94*38e8c45fSAndroid Build Coastguard Worker newNode->next = 0;
95*38e8c45fSAndroid Build Coastguard Worker mLast->next = newNode;
96*38e8c45fSAndroid Build Coastguard Worker mLast = newNode;
97*38e8c45fSAndroid Build Coastguard Worker }
98*38e8c45fSAndroid Build Coastguard Worker }
99*38e8c45fSAndroid Build Coastguard Worker
remove(NODE * node)100*38e8c45fSAndroid Build Coastguard Worker NODE* remove(NODE* node) {
101*38e8c45fSAndroid Build Coastguard Worker if (node->prev == nullptr) mFirst = node->next;
102*38e8c45fSAndroid Build Coastguard Worker else node->prev->next = node->next;
103*38e8c45fSAndroid Build Coastguard Worker if (node->next == nullptr) mLast = node->prev;
104*38e8c45fSAndroid Build Coastguard Worker else node->next->prev = node->prev;
105*38e8c45fSAndroid Build Coastguard Worker return node;
106*38e8c45fSAndroid Build Coastguard Worker }
107*38e8c45fSAndroid Build Coastguard Worker };
108*38e8c45fSAndroid Build Coastguard Worker
109*38e8c45fSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
110*38e8c45fSAndroid Build Coastguard Worker
111*38e8c45fSAndroid Build Coastguard Worker class Allocation : public MemoryBase {
112*38e8c45fSAndroid Build Coastguard Worker public:
113*38e8c45fSAndroid Build Coastguard Worker Allocation(const sp<MemoryDealer>& dealer,
114*38e8c45fSAndroid Build Coastguard Worker const sp<IMemoryHeap>& heap, ssize_t offset, size_t size);
115*38e8c45fSAndroid Build Coastguard Worker virtual ~Allocation();
116*38e8c45fSAndroid Build Coastguard Worker private:
117*38e8c45fSAndroid Build Coastguard Worker sp<MemoryDealer> mDealer;
118*38e8c45fSAndroid Build Coastguard Worker };
119*38e8c45fSAndroid Build Coastguard Worker
120*38e8c45fSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
121*38e8c45fSAndroid Build Coastguard Worker
122*38e8c45fSAndroid Build Coastguard Worker class SimpleBestFitAllocator
123*38e8c45fSAndroid Build Coastguard Worker {
124*38e8c45fSAndroid Build Coastguard Worker enum {
125*38e8c45fSAndroid Build Coastguard Worker PAGE_ALIGNED = 0x00000001
126*38e8c45fSAndroid Build Coastguard Worker };
127*38e8c45fSAndroid Build Coastguard Worker public:
128*38e8c45fSAndroid Build Coastguard Worker explicit SimpleBestFitAllocator(size_t size);
129*38e8c45fSAndroid Build Coastguard Worker ~SimpleBestFitAllocator();
130*38e8c45fSAndroid Build Coastguard Worker
131*38e8c45fSAndroid Build Coastguard Worker size_t allocate(size_t size, uint32_t flags = 0);
132*38e8c45fSAndroid Build Coastguard Worker status_t deallocate(size_t offset);
133*38e8c45fSAndroid Build Coastguard Worker size_t size() const;
134*38e8c45fSAndroid Build Coastguard Worker void dump(const char* what) const;
135*38e8c45fSAndroid Build Coastguard Worker void dump(String8& res, const char* what) const;
136*38e8c45fSAndroid Build Coastguard Worker
getAllocationAlignment()137*38e8c45fSAndroid Build Coastguard Worker static size_t getAllocationAlignment() { return kMemoryAlign; }
138*38e8c45fSAndroid Build Coastguard Worker
139*38e8c45fSAndroid Build Coastguard Worker private:
140*38e8c45fSAndroid Build Coastguard Worker
141*38e8c45fSAndroid Build Coastguard Worker struct chunk_t {
chunk_tandroid::SimpleBestFitAllocator::chunk_t142*38e8c45fSAndroid Build Coastguard Worker chunk_t(size_t start, size_t size)
143*38e8c45fSAndroid Build Coastguard Worker : start(start), size(size), free(1), prev(nullptr), next(nullptr) {
144*38e8c45fSAndroid Build Coastguard Worker }
145*38e8c45fSAndroid Build Coastguard Worker size_t start;
146*38e8c45fSAndroid Build Coastguard Worker size_t size : 28;
147*38e8c45fSAndroid Build Coastguard Worker int free : 4;
148*38e8c45fSAndroid Build Coastguard Worker mutable chunk_t* prev;
149*38e8c45fSAndroid Build Coastguard Worker mutable chunk_t* next;
150*38e8c45fSAndroid Build Coastguard Worker };
151*38e8c45fSAndroid Build Coastguard Worker
152*38e8c45fSAndroid Build Coastguard Worker ssize_t alloc(size_t size, uint32_t flags);
153*38e8c45fSAndroid Build Coastguard Worker chunk_t* dealloc(size_t start);
154*38e8c45fSAndroid Build Coastguard Worker void dump_l(const char* what) const;
155*38e8c45fSAndroid Build Coastguard Worker void dump_l(String8& res, const char* what) const;
156*38e8c45fSAndroid Build Coastguard Worker
157*38e8c45fSAndroid Build Coastguard Worker static const int kMemoryAlign;
158*38e8c45fSAndroid Build Coastguard Worker mutable std::mutex mLock;
159*38e8c45fSAndroid Build Coastguard Worker LinkedList<chunk_t> mList;
160*38e8c45fSAndroid Build Coastguard Worker size_t mHeapSize;
161*38e8c45fSAndroid Build Coastguard Worker };
162*38e8c45fSAndroid Build Coastguard Worker
163*38e8c45fSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
164*38e8c45fSAndroid Build Coastguard Worker
Allocation(const sp<MemoryDealer> & dealer,const sp<IMemoryHeap> & heap,ssize_t offset,size_t size)165*38e8c45fSAndroid Build Coastguard Worker Allocation::Allocation(
166*38e8c45fSAndroid Build Coastguard Worker const sp<MemoryDealer>& dealer,
167*38e8c45fSAndroid Build Coastguard Worker const sp<IMemoryHeap>& heap, ssize_t offset, size_t size)
168*38e8c45fSAndroid Build Coastguard Worker : MemoryBase(heap, offset, size), mDealer(dealer)
169*38e8c45fSAndroid Build Coastguard Worker {
170*38e8c45fSAndroid Build Coastguard Worker #ifndef NDEBUG
171*38e8c45fSAndroid Build Coastguard Worker void* const start_ptr = (void*)(intptr_t(heap->base()) + offset);
172*38e8c45fSAndroid Build Coastguard Worker memset(start_ptr, 0xda, size);
173*38e8c45fSAndroid Build Coastguard Worker #endif
174*38e8c45fSAndroid Build Coastguard Worker }
175*38e8c45fSAndroid Build Coastguard Worker
~Allocation()176*38e8c45fSAndroid Build Coastguard Worker Allocation::~Allocation()
177*38e8c45fSAndroid Build Coastguard Worker {
178*38e8c45fSAndroid Build Coastguard Worker size_t freedOffset = getOffset();
179*38e8c45fSAndroid Build Coastguard Worker size_t freedSize = getSize();
180*38e8c45fSAndroid Build Coastguard Worker if (freedSize) {
181*38e8c45fSAndroid Build Coastguard Worker /* NOTE: it's VERY important to not free allocations of size 0 because
182*38e8c45fSAndroid Build Coastguard Worker * they're special as they don't have any record in the allocator
183*38e8c45fSAndroid Build Coastguard Worker * and could alias some real allocation (their offset is zero). */
184*38e8c45fSAndroid Build Coastguard Worker
185*38e8c45fSAndroid Build Coastguard Worker // keep the size to unmap in excess
186*38e8c45fSAndroid Build Coastguard Worker size_t pagesize = getpagesize();
187*38e8c45fSAndroid Build Coastguard Worker size_t start = freedOffset;
188*38e8c45fSAndroid Build Coastguard Worker size_t end = start + freedSize;
189*38e8c45fSAndroid Build Coastguard Worker start &= ~(pagesize-1);
190*38e8c45fSAndroid Build Coastguard Worker end = (end + pagesize-1) & ~(pagesize-1);
191*38e8c45fSAndroid Build Coastguard Worker
192*38e8c45fSAndroid Build Coastguard Worker // give back to the kernel the pages we don't need
193*38e8c45fSAndroid Build Coastguard Worker size_t free_start = freedOffset;
194*38e8c45fSAndroid Build Coastguard Worker size_t free_end = free_start + freedSize;
195*38e8c45fSAndroid Build Coastguard Worker if (start < free_start)
196*38e8c45fSAndroid Build Coastguard Worker start = free_start;
197*38e8c45fSAndroid Build Coastguard Worker if (end > free_end)
198*38e8c45fSAndroid Build Coastguard Worker end = free_end;
199*38e8c45fSAndroid Build Coastguard Worker start = (start + pagesize-1) & ~(pagesize-1);
200*38e8c45fSAndroid Build Coastguard Worker end &= ~(pagesize-1);
201*38e8c45fSAndroid Build Coastguard Worker
202*38e8c45fSAndroid Build Coastguard Worker if (start < end) {
203*38e8c45fSAndroid Build Coastguard Worker void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + start);
204*38e8c45fSAndroid Build Coastguard Worker size_t size = end-start;
205*38e8c45fSAndroid Build Coastguard Worker
206*38e8c45fSAndroid Build Coastguard Worker #ifndef NDEBUG
207*38e8c45fSAndroid Build Coastguard Worker memset(start_ptr, 0xdf, size);
208*38e8c45fSAndroid Build Coastguard Worker #endif
209*38e8c45fSAndroid Build Coastguard Worker
210*38e8c45fSAndroid Build Coastguard Worker // MADV_REMOVE is not defined on Dapper based Goobuntu
211*38e8c45fSAndroid Build Coastguard Worker #ifdef MADV_REMOVE
212*38e8c45fSAndroid Build Coastguard Worker if (size) {
213*38e8c45fSAndroid Build Coastguard Worker int err = madvise(start_ptr, size, MADV_REMOVE);
214*38e8c45fSAndroid Build Coastguard Worker ALOGW_IF(err, "madvise(%p, %zu, MADV_REMOVE) returned %s",
215*38e8c45fSAndroid Build Coastguard Worker start_ptr, size, err<0 ? strerror(errno) : "Ok");
216*38e8c45fSAndroid Build Coastguard Worker }
217*38e8c45fSAndroid Build Coastguard Worker #endif
218*38e8c45fSAndroid Build Coastguard Worker }
219*38e8c45fSAndroid Build Coastguard Worker
220*38e8c45fSAndroid Build Coastguard Worker // This should be done after madvise(MADV_REMOVE), otherwise madvise()
221*38e8c45fSAndroid Build Coastguard Worker // might kick out the memory region that's allocated and/or written
222*38e8c45fSAndroid Build Coastguard Worker // right after the deallocation.
223*38e8c45fSAndroid Build Coastguard Worker mDealer->deallocate(freedOffset);
224*38e8c45fSAndroid Build Coastguard Worker }
225*38e8c45fSAndroid Build Coastguard Worker }
226*38e8c45fSAndroid Build Coastguard Worker
227*38e8c45fSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
228*38e8c45fSAndroid Build Coastguard Worker
MemoryDealer(size_t size,const char * name,uint32_t flags)229*38e8c45fSAndroid Build Coastguard Worker MemoryDealer::MemoryDealer(size_t size, const char* name, uint32_t flags)
230*38e8c45fSAndroid Build Coastguard Worker : mHeap(sp<MemoryHeapBase>::make(size, flags, name)),
231*38e8c45fSAndroid Build Coastguard Worker mAllocator(new SimpleBestFitAllocator(size)) {}
232*38e8c45fSAndroid Build Coastguard Worker
~MemoryDealer()233*38e8c45fSAndroid Build Coastguard Worker MemoryDealer::~MemoryDealer()
234*38e8c45fSAndroid Build Coastguard Worker {
235*38e8c45fSAndroid Build Coastguard Worker delete mAllocator;
236*38e8c45fSAndroid Build Coastguard Worker }
237*38e8c45fSAndroid Build Coastguard Worker
allocate(size_t size)238*38e8c45fSAndroid Build Coastguard Worker sp<IMemory> MemoryDealer::allocate(size_t size)
239*38e8c45fSAndroid Build Coastguard Worker {
240*38e8c45fSAndroid Build Coastguard Worker sp<IMemory> memory;
241*38e8c45fSAndroid Build Coastguard Worker const ssize_t offset = allocator()->allocate(size);
242*38e8c45fSAndroid Build Coastguard Worker if (offset >= 0) {
243*38e8c45fSAndroid Build Coastguard Worker memory = sp<Allocation>::make(sp<MemoryDealer>::fromExisting(this), heap(), offset, size);
244*38e8c45fSAndroid Build Coastguard Worker }
245*38e8c45fSAndroid Build Coastguard Worker return memory;
246*38e8c45fSAndroid Build Coastguard Worker }
247*38e8c45fSAndroid Build Coastguard Worker
deallocate(size_t offset)248*38e8c45fSAndroid Build Coastguard Worker void MemoryDealer::deallocate(size_t offset)
249*38e8c45fSAndroid Build Coastguard Worker {
250*38e8c45fSAndroid Build Coastguard Worker allocator()->deallocate(offset);
251*38e8c45fSAndroid Build Coastguard Worker }
252*38e8c45fSAndroid Build Coastguard Worker
dump(const char * what) const253*38e8c45fSAndroid Build Coastguard Worker void MemoryDealer::dump(const char* what) const
254*38e8c45fSAndroid Build Coastguard Worker {
255*38e8c45fSAndroid Build Coastguard Worker allocator()->dump(what);
256*38e8c45fSAndroid Build Coastguard Worker }
257*38e8c45fSAndroid Build Coastguard Worker
heap() const258*38e8c45fSAndroid Build Coastguard Worker const sp<IMemoryHeap>& MemoryDealer::heap() const {
259*38e8c45fSAndroid Build Coastguard Worker return mHeap;
260*38e8c45fSAndroid Build Coastguard Worker }
261*38e8c45fSAndroid Build Coastguard Worker
allocator() const262*38e8c45fSAndroid Build Coastguard Worker SimpleBestFitAllocator* MemoryDealer::allocator() const {
263*38e8c45fSAndroid Build Coastguard Worker return mAllocator;
264*38e8c45fSAndroid Build Coastguard Worker }
265*38e8c45fSAndroid Build Coastguard Worker
266*38e8c45fSAndroid Build Coastguard Worker // static
getAllocationAlignment()267*38e8c45fSAndroid Build Coastguard Worker size_t MemoryDealer::getAllocationAlignment()
268*38e8c45fSAndroid Build Coastguard Worker {
269*38e8c45fSAndroid Build Coastguard Worker return SimpleBestFitAllocator::getAllocationAlignment();
270*38e8c45fSAndroid Build Coastguard Worker }
271*38e8c45fSAndroid Build Coastguard Worker
272*38e8c45fSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
273*38e8c45fSAndroid Build Coastguard Worker
274*38e8c45fSAndroid Build Coastguard Worker // align all the memory blocks on a cache-line boundary
275*38e8c45fSAndroid Build Coastguard Worker const int SimpleBestFitAllocator::kMemoryAlign = 32;
276*38e8c45fSAndroid Build Coastguard Worker
SimpleBestFitAllocator(size_t size)277*38e8c45fSAndroid Build Coastguard Worker SimpleBestFitAllocator::SimpleBestFitAllocator(size_t size)
278*38e8c45fSAndroid Build Coastguard Worker {
279*38e8c45fSAndroid Build Coastguard Worker size_t pagesize = getpagesize();
280*38e8c45fSAndroid Build Coastguard Worker mHeapSize = ((size + pagesize-1) & ~(pagesize-1));
281*38e8c45fSAndroid Build Coastguard Worker
282*38e8c45fSAndroid Build Coastguard Worker chunk_t* node = new chunk_t(0, mHeapSize / kMemoryAlign);
283*38e8c45fSAndroid Build Coastguard Worker mList.insertHead(node);
284*38e8c45fSAndroid Build Coastguard Worker }
285*38e8c45fSAndroid Build Coastguard Worker
~SimpleBestFitAllocator()286*38e8c45fSAndroid Build Coastguard Worker SimpleBestFitAllocator::~SimpleBestFitAllocator()
287*38e8c45fSAndroid Build Coastguard Worker {
288*38e8c45fSAndroid Build Coastguard Worker while(!mList.isEmpty()) {
289*38e8c45fSAndroid Build Coastguard Worker chunk_t* removed = mList.remove(mList.head());
290*38e8c45fSAndroid Build Coastguard Worker #ifdef __clang_analyzer__
291*38e8c45fSAndroid Build Coastguard Worker // Clang static analyzer gets confused in this loop
292*38e8c45fSAndroid Build Coastguard Worker // and generates a false positive warning about accessing
293*38e8c45fSAndroid Build Coastguard Worker // memory that is already freed.
294*38e8c45fSAndroid Build Coastguard Worker // Add an "assert" to avoid the confusion.
295*38e8c45fSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(mList.head() == removed);
296*38e8c45fSAndroid Build Coastguard Worker #endif
297*38e8c45fSAndroid Build Coastguard Worker delete removed;
298*38e8c45fSAndroid Build Coastguard Worker }
299*38e8c45fSAndroid Build Coastguard Worker }
300*38e8c45fSAndroid Build Coastguard Worker
size() const301*38e8c45fSAndroid Build Coastguard Worker size_t SimpleBestFitAllocator::size() const
302*38e8c45fSAndroid Build Coastguard Worker {
303*38e8c45fSAndroid Build Coastguard Worker return mHeapSize;
304*38e8c45fSAndroid Build Coastguard Worker }
305*38e8c45fSAndroid Build Coastguard Worker
allocate(size_t size,uint32_t flags)306*38e8c45fSAndroid Build Coastguard Worker size_t SimpleBestFitAllocator::allocate(size_t size, uint32_t flags)
307*38e8c45fSAndroid Build Coastguard Worker {
308*38e8c45fSAndroid Build Coastguard Worker std::unique_lock<std::mutex> _l(mLock);
309*38e8c45fSAndroid Build Coastguard Worker ssize_t offset = alloc(size, flags);
310*38e8c45fSAndroid Build Coastguard Worker return offset;
311*38e8c45fSAndroid Build Coastguard Worker }
312*38e8c45fSAndroid Build Coastguard Worker
deallocate(size_t offset)313*38e8c45fSAndroid Build Coastguard Worker status_t SimpleBestFitAllocator::deallocate(size_t offset)
314*38e8c45fSAndroid Build Coastguard Worker {
315*38e8c45fSAndroid Build Coastguard Worker std::unique_lock<std::mutex> _l(mLock);
316*38e8c45fSAndroid Build Coastguard Worker chunk_t const * const freed = dealloc(offset);
317*38e8c45fSAndroid Build Coastguard Worker if (freed) {
318*38e8c45fSAndroid Build Coastguard Worker return NO_ERROR;
319*38e8c45fSAndroid Build Coastguard Worker }
320*38e8c45fSAndroid Build Coastguard Worker return NAME_NOT_FOUND;
321*38e8c45fSAndroid Build Coastguard Worker }
322*38e8c45fSAndroid Build Coastguard Worker
alloc(size_t size,uint32_t flags)323*38e8c45fSAndroid Build Coastguard Worker ssize_t SimpleBestFitAllocator::alloc(size_t size, uint32_t flags)
324*38e8c45fSAndroid Build Coastguard Worker {
325*38e8c45fSAndroid Build Coastguard Worker if (size == 0) {
326*38e8c45fSAndroid Build Coastguard Worker return 0;
327*38e8c45fSAndroid Build Coastguard Worker }
328*38e8c45fSAndroid Build Coastguard Worker size = (size + kMemoryAlign-1) / kMemoryAlign;
329*38e8c45fSAndroid Build Coastguard Worker chunk_t* free_chunk = nullptr;
330*38e8c45fSAndroid Build Coastguard Worker chunk_t* cur = mList.head();
331*38e8c45fSAndroid Build Coastguard Worker
332*38e8c45fSAndroid Build Coastguard Worker size_t pagesize = getpagesize();
333*38e8c45fSAndroid Build Coastguard Worker while (cur) {
334*38e8c45fSAndroid Build Coastguard Worker int extra = 0;
335*38e8c45fSAndroid Build Coastguard Worker if (flags & PAGE_ALIGNED)
336*38e8c45fSAndroid Build Coastguard Worker extra = ( -cur->start & ((pagesize/kMemoryAlign)-1) ) ;
337*38e8c45fSAndroid Build Coastguard Worker
338*38e8c45fSAndroid Build Coastguard Worker // best fit
339*38e8c45fSAndroid Build Coastguard Worker if (cur->free && (cur->size >= (size+extra))) {
340*38e8c45fSAndroid Build Coastguard Worker if ((!free_chunk) || (cur->size < free_chunk->size)) {
341*38e8c45fSAndroid Build Coastguard Worker free_chunk = cur;
342*38e8c45fSAndroid Build Coastguard Worker }
343*38e8c45fSAndroid Build Coastguard Worker if (cur->size == size) {
344*38e8c45fSAndroid Build Coastguard Worker break;
345*38e8c45fSAndroid Build Coastguard Worker }
346*38e8c45fSAndroid Build Coastguard Worker }
347*38e8c45fSAndroid Build Coastguard Worker cur = cur->next;
348*38e8c45fSAndroid Build Coastguard Worker }
349*38e8c45fSAndroid Build Coastguard Worker
350*38e8c45fSAndroid Build Coastguard Worker if (free_chunk) {
351*38e8c45fSAndroid Build Coastguard Worker const size_t free_size = free_chunk->size;
352*38e8c45fSAndroid Build Coastguard Worker free_chunk->free = 0;
353*38e8c45fSAndroid Build Coastguard Worker free_chunk->size = size;
354*38e8c45fSAndroid Build Coastguard Worker if (free_size > size) {
355*38e8c45fSAndroid Build Coastguard Worker int extra = 0;
356*38e8c45fSAndroid Build Coastguard Worker if (flags & PAGE_ALIGNED)
357*38e8c45fSAndroid Build Coastguard Worker extra = ( -free_chunk->start & ((pagesize/kMemoryAlign)-1) ) ;
358*38e8c45fSAndroid Build Coastguard Worker if (extra) {
359*38e8c45fSAndroid Build Coastguard Worker chunk_t* split = new chunk_t(free_chunk->start, extra);
360*38e8c45fSAndroid Build Coastguard Worker free_chunk->start += extra;
361*38e8c45fSAndroid Build Coastguard Worker mList.insertBefore(free_chunk, split);
362*38e8c45fSAndroid Build Coastguard Worker }
363*38e8c45fSAndroid Build Coastguard Worker
364*38e8c45fSAndroid Build Coastguard Worker ALOGE_IF((flags&PAGE_ALIGNED) &&
365*38e8c45fSAndroid Build Coastguard Worker ((free_chunk->start*kMemoryAlign)&(pagesize-1)),
366*38e8c45fSAndroid Build Coastguard Worker "PAGE_ALIGNED requested, but page is not aligned!!!");
367*38e8c45fSAndroid Build Coastguard Worker
368*38e8c45fSAndroid Build Coastguard Worker const ssize_t tail_free = free_size - (size+extra);
369*38e8c45fSAndroid Build Coastguard Worker if (tail_free > 0) {
370*38e8c45fSAndroid Build Coastguard Worker chunk_t* split = new chunk_t(
371*38e8c45fSAndroid Build Coastguard Worker free_chunk->start + free_chunk->size, tail_free);
372*38e8c45fSAndroid Build Coastguard Worker mList.insertAfter(free_chunk, split);
373*38e8c45fSAndroid Build Coastguard Worker }
374*38e8c45fSAndroid Build Coastguard Worker }
375*38e8c45fSAndroid Build Coastguard Worker return (free_chunk->start)*kMemoryAlign;
376*38e8c45fSAndroid Build Coastguard Worker }
377*38e8c45fSAndroid Build Coastguard Worker return NO_MEMORY;
378*38e8c45fSAndroid Build Coastguard Worker }
379*38e8c45fSAndroid Build Coastguard Worker
dealloc(size_t start)380*38e8c45fSAndroid Build Coastguard Worker SimpleBestFitAllocator::chunk_t* SimpleBestFitAllocator::dealloc(size_t start)
381*38e8c45fSAndroid Build Coastguard Worker {
382*38e8c45fSAndroid Build Coastguard Worker start = start / kMemoryAlign;
383*38e8c45fSAndroid Build Coastguard Worker chunk_t* cur = mList.head();
384*38e8c45fSAndroid Build Coastguard Worker while (cur) {
385*38e8c45fSAndroid Build Coastguard Worker if (cur->start == start) {
386*38e8c45fSAndroid Build Coastguard Worker LOG_FATAL_IF(cur->free,
387*38e8c45fSAndroid Build Coastguard Worker "block at offset 0x%08lX of size 0x%08X already freed",
388*38e8c45fSAndroid Build Coastguard Worker cur->start*kMemoryAlign, cur->size*kMemoryAlign);
389*38e8c45fSAndroid Build Coastguard Worker
390*38e8c45fSAndroid Build Coastguard Worker // merge freed blocks together
391*38e8c45fSAndroid Build Coastguard Worker chunk_t* freed = cur;
392*38e8c45fSAndroid Build Coastguard Worker cur->free = 1;
393*38e8c45fSAndroid Build Coastguard Worker do {
394*38e8c45fSAndroid Build Coastguard Worker chunk_t* const p = cur->prev;
395*38e8c45fSAndroid Build Coastguard Worker chunk_t* const n = cur->next;
396*38e8c45fSAndroid Build Coastguard Worker if (p && (p->free || !cur->size)) {
397*38e8c45fSAndroid Build Coastguard Worker freed = p;
398*38e8c45fSAndroid Build Coastguard Worker p->size += cur->size;
399*38e8c45fSAndroid Build Coastguard Worker mList.remove(cur);
400*38e8c45fSAndroid Build Coastguard Worker delete cur;
401*38e8c45fSAndroid Build Coastguard Worker }
402*38e8c45fSAndroid Build Coastguard Worker cur = n;
403*38e8c45fSAndroid Build Coastguard Worker } while (cur && cur->free);
404*38e8c45fSAndroid Build Coastguard Worker
405*38e8c45fSAndroid Build Coastguard Worker #ifndef NDEBUG
406*38e8c45fSAndroid Build Coastguard Worker if (!freed->free) {
407*38e8c45fSAndroid Build Coastguard Worker dump_l("dealloc (!freed->free)");
408*38e8c45fSAndroid Build Coastguard Worker }
409*38e8c45fSAndroid Build Coastguard Worker #endif
410*38e8c45fSAndroid Build Coastguard Worker LOG_FATAL_IF(!freed->free,
411*38e8c45fSAndroid Build Coastguard Worker "freed block at offset 0x%08lX of size 0x%08X is not free!",
412*38e8c45fSAndroid Build Coastguard Worker freed->start * kMemoryAlign, freed->size * kMemoryAlign);
413*38e8c45fSAndroid Build Coastguard Worker
414*38e8c45fSAndroid Build Coastguard Worker return freed;
415*38e8c45fSAndroid Build Coastguard Worker }
416*38e8c45fSAndroid Build Coastguard Worker cur = cur->next;
417*38e8c45fSAndroid Build Coastguard Worker }
418*38e8c45fSAndroid Build Coastguard Worker return nullptr;
419*38e8c45fSAndroid Build Coastguard Worker }
420*38e8c45fSAndroid Build Coastguard Worker
dump(const char * what) const421*38e8c45fSAndroid Build Coastguard Worker void SimpleBestFitAllocator::dump(const char* what) const
422*38e8c45fSAndroid Build Coastguard Worker {
423*38e8c45fSAndroid Build Coastguard Worker std::unique_lock<std::mutex> _l(mLock);
424*38e8c45fSAndroid Build Coastguard Worker dump_l(what);
425*38e8c45fSAndroid Build Coastguard Worker }
426*38e8c45fSAndroid Build Coastguard Worker
dump_l(const char * what) const427*38e8c45fSAndroid Build Coastguard Worker void SimpleBestFitAllocator::dump_l(const char* what) const
428*38e8c45fSAndroid Build Coastguard Worker {
429*38e8c45fSAndroid Build Coastguard Worker String8 result;
430*38e8c45fSAndroid Build Coastguard Worker dump_l(result, what);
431*38e8c45fSAndroid Build Coastguard Worker ALOGD("%s", result.c_str());
432*38e8c45fSAndroid Build Coastguard Worker }
433*38e8c45fSAndroid Build Coastguard Worker
dump(String8 & result,const char * what) const434*38e8c45fSAndroid Build Coastguard Worker void SimpleBestFitAllocator::dump(String8& result,
435*38e8c45fSAndroid Build Coastguard Worker const char* what) const
436*38e8c45fSAndroid Build Coastguard Worker {
437*38e8c45fSAndroid Build Coastguard Worker std::unique_lock<std::mutex> _l(mLock);
438*38e8c45fSAndroid Build Coastguard Worker dump_l(result, what);
439*38e8c45fSAndroid Build Coastguard Worker }
440*38e8c45fSAndroid Build Coastguard Worker
dump_l(String8 & result,const char * what) const441*38e8c45fSAndroid Build Coastguard Worker void SimpleBestFitAllocator::dump_l(String8& result,
442*38e8c45fSAndroid Build Coastguard Worker const char* what) const
443*38e8c45fSAndroid Build Coastguard Worker {
444*38e8c45fSAndroid Build Coastguard Worker size_t size = 0;
445*38e8c45fSAndroid Build Coastguard Worker int32_t i = 0;
446*38e8c45fSAndroid Build Coastguard Worker chunk_t const* cur = mList.head();
447*38e8c45fSAndroid Build Coastguard Worker
448*38e8c45fSAndroid Build Coastguard Worker const size_t SIZE = 256;
449*38e8c45fSAndroid Build Coastguard Worker char buffer[SIZE];
450*38e8c45fSAndroid Build Coastguard Worker snprintf(buffer, SIZE, " %s (%p, size=%u)\n",
451*38e8c45fSAndroid Build Coastguard Worker what, this, (unsigned int)mHeapSize);
452*38e8c45fSAndroid Build Coastguard Worker
453*38e8c45fSAndroid Build Coastguard Worker result.append(buffer);
454*38e8c45fSAndroid Build Coastguard Worker
455*38e8c45fSAndroid Build Coastguard Worker while (cur) {
456*38e8c45fSAndroid Build Coastguard Worker const char* errs[] = {"", "| link bogus NP",
457*38e8c45fSAndroid Build Coastguard Worker "| link bogus PN", "| link bogus NP+PN" };
458*38e8c45fSAndroid Build Coastguard Worker int np = ((cur->next) && cur->next->prev != cur) ? 1 : 0;
459*38e8c45fSAndroid Build Coastguard Worker int pn = ((cur->prev) && cur->prev->next != cur) ? 2 : 0;
460*38e8c45fSAndroid Build Coastguard Worker
461*38e8c45fSAndroid Build Coastguard Worker snprintf(buffer, SIZE, " %3u: %p | 0x%08X | 0x%08X | %s %s\n",
462*38e8c45fSAndroid Build Coastguard Worker i, cur, int(cur->start*kMemoryAlign),
463*38e8c45fSAndroid Build Coastguard Worker int(cur->size*kMemoryAlign),
464*38e8c45fSAndroid Build Coastguard Worker int(cur->free) ? "F" : "A",
465*38e8c45fSAndroid Build Coastguard Worker errs[np|pn]);
466*38e8c45fSAndroid Build Coastguard Worker
467*38e8c45fSAndroid Build Coastguard Worker result.append(buffer);
468*38e8c45fSAndroid Build Coastguard Worker
469*38e8c45fSAndroid Build Coastguard Worker if (!cur->free)
470*38e8c45fSAndroid Build Coastguard Worker size += cur->size*kMemoryAlign;
471*38e8c45fSAndroid Build Coastguard Worker
472*38e8c45fSAndroid Build Coastguard Worker i++;
473*38e8c45fSAndroid Build Coastguard Worker cur = cur->next;
474*38e8c45fSAndroid Build Coastguard Worker }
475*38e8c45fSAndroid Build Coastguard Worker snprintf(buffer, SIZE,
476*38e8c45fSAndroid Build Coastguard Worker " size allocated: %u (%u KB)\n", int(size), int(size/1024));
477*38e8c45fSAndroid Build Coastguard Worker result.append(buffer);
478*38e8c45fSAndroid Build Coastguard Worker }
479*38e8c45fSAndroid Build Coastguard Worker
480*38e8c45fSAndroid Build Coastguard Worker
481*38e8c45fSAndroid Build Coastguard Worker } // namespace android
482