diff -r 000000000000 -r 6474c204b198 gfx/skia/trunk/src/ports/SkPurgeableMemoryBlock_android.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gfx/skia/trunk/src/ports/SkPurgeableMemoryBlock_android.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,110 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkPurgeableMemoryBlock.h" + +#include "android/ashmem.h" +#include +#include + +bool SkPurgeableMemoryBlock::IsSupported() { + return true; +} + +#ifdef SK_DEBUG +bool SkPurgeableMemoryBlock::PlatformSupportsPurgingAllUnpinnedBlocks() { + return false; +} + +bool SkPurgeableMemoryBlock::PurgeAllUnpinnedBlocks() { + return false; +} + +bool SkPurgeableMemoryBlock::purge() { + SkASSERT(!fPinned); + if (-1 != fFD) { + ashmem_purge_all_caches(fFD); + return true; + } else { + return false; + } +} +#endif + +// ashmem likes lengths on page boundaries. +static size_t round_to_page_size(size_t size) { + const size_t mask = getpagesize() - 1; + size_t newSize = (size + mask) & ~mask; + return newSize; +} + +SkPurgeableMemoryBlock::SkPurgeableMemoryBlock(size_t size) + : fAddr(NULL) + , fSize(round_to_page_size(size)) + , fPinned(false) + , fFD(-1) { +} + +SkPurgeableMemoryBlock::~SkPurgeableMemoryBlock() { + if (-1 != fFD) { + munmap(fAddr, fSize); + close(fFD); + } +} + +void* SkPurgeableMemoryBlock::pin(SkPurgeableMemoryBlock::PinResult* pinResult) { + SkASSERT(!fPinned); + if (-1 == fFD) { + int fd = ashmem_create_region(NULL, fSize); + if (-1 == fd) { + SkDebugf("ashmem_create_region failed\n"); + return NULL; + } + + int err = ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE); + if (err != 0) { + SkDebugf("ashmem_set_prot_region failed\n"); + close(fd); + return NULL; + } + + void* addr = mmap(NULL, fSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + if (-1 == (long) addr) { + SkDebugf("mmap failed\n"); + close(fd); + return NULL; + } + fAddr = addr; + fFD = fd; + (void) ashmem_pin_region(fd, 0, 0); + *pinResult = kUninitialized_PinResult; + fPinned = true; + } else { + int pin = ashmem_pin_region(fFD, 0, 0); + if (ASHMEM_NOT_PURGED == pin) { + fPinned = true; + *pinResult = kRetained_PinResult; + } else if (ASHMEM_WAS_PURGED == pin) { + fPinned = true; + *pinResult = kUninitialized_PinResult; + } else { + // Failed. + munmap(fAddr, fSize); + close(fFD); + fFD = -1; + fAddr = NULL; + } + } + return fAddr; +} + +void SkPurgeableMemoryBlock::unpin() { + if (-1 != fFD) { + ashmem_unpin_region(fFD, 0, 0); + fPinned = false; + } +}