| Index: src/ports/SkPurgeableMemoryBlock_android.cpp
|
| diff --git a/src/ports/SkPurgeableMemoryBlock_android.cpp b/src/ports/SkPurgeableMemoryBlock_android.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..7c06b933edecd345f2b5cf83f71ae97b2b1ba3e5
|
| --- /dev/null
|
| +++ b/src/ports/SkPurgeableMemoryBlock_android.cpp
|
| @@ -0,0 +1,117 @@
|
| +/*
|
| + * 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 <sys/mman.h>
|
| +#include <unistd.h>
|
| +
|
| +bool SkPurgeableMemoryBlock::PlatformSupportsPurgeableMemory() {
|
| + return true;
|
| +}
|
| +
|
| +#ifdef SK_DEBUG
|
| +bool SkPurgeableMemoryBlock::PlatformSupportsPurgingAllUnpinnedBlocks() {
|
| + return false;
|
| +}
|
| +
|
| +bool SkPurgeableMemoryBlock::PurgeAllUnpinnedBlocks() {
|
| + return false;
|
| +}
|
| +
|
| +bool SkPurgeableMemoryBlock::purge() {
|
| + SkASSERT(!fPinned);
|
| + if (-1 != fFD) {
|
| + munmap(fAddr, fSize);
|
| + close(fFD);
|
| + fFD = -1;
|
| + fAddr = NULL;
|
| + fSize = 0;
|
| + 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(0)
|
| + , fPinned(false)
|
| + , fFD(-1) {
|
| + size = round_to_page_size(size);
|
| + int fd = ashmem_create_region(NULL, size);
|
| + if (-1 == fd) {
|
| + SkDebugf("ashmem_create_region failed\n");
|
| + return;
|
| + }
|
| +
|
| + int err = ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE);
|
| + if (err != 0) {
|
| + SkDebugf("ashmem_set_prot_region failed\n");
|
| + close(fd);
|
| + return;
|
| + }
|
| +
|
| + void* addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
|
| + if (-1 == (long) addr) {
|
| + SkDebugf("mmap failed\n");
|
| + close(fd);
|
| + return;
|
| + }
|
| + fAddr = addr;
|
| + fSize = size;
|
| + fFD = fd;
|
| + (void) ashmem_pin_region(fd, 0, 0);
|
| + fPinned = true;
|
| +}
|
| +
|
| +SkPurgeableMemoryBlock::~SkPurgeableMemoryBlock() {
|
| + if (-1 != fFD) {
|
| + munmap(fAddr, fSize);
|
| + close(fFD);
|
| + }
|
| +}
|
| +
|
| +SkPurgeableMemoryBlock::PinResult SkPurgeableMemoryBlock::pin() {
|
| + SkASSERT(!fPinned);
|
| + if (-1 != fFD) {
|
| + int pin = ashmem_pin_region(fFD, 0, 0);
|
| + if (ASHMEM_NOT_PURGED == pin) {
|
| + fPinned = true;
|
| + return kRetained_PinResult;
|
| + } else if (ASHMEM_WAS_PURGED == pin) {
|
| + fPinned = true;
|
| + return kUninitialized_PinResult;
|
| + } else {
|
| + // Failed.
|
| + munmap(fAddr, fSize);
|
| + close(fFD);
|
| + fFD = -1;
|
| + fAddr = NULL;
|
| + fSize = 0;
|
| + // Fall through
|
| + }
|
| + }
|
| + return kFailed_PinResult;
|
| +}
|
| +
|
| +void SkPurgeableMemoryBlock::unpin() {
|
| + if (-1 != fFD) {
|
| + ashmem_unpin_region(fFD, 0, 0);
|
| + fPinned = false;
|
| + }
|
| +}
|
| +
|
|
|