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