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..f98b0e26268571a41feace21146d9366d584f54b |
--- /dev/null |
+++ b/src/ports/SkPurgeableMemoryBlock_android.cpp |
@@ -0,0 +1,111 @@ |
+/* |
+ * 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::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; |
+ } |
+} |
+ |