xref: /aosp_15_r20/frameworks/native/libs/binder/MemoryDealer.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
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