Home | History | Annotate | Download | only in ports
      1 /*
      2  * Copyright 2013 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkPurgeableMemoryBlock.h"
      9 
     10 #include "android/ashmem.h"
     11 #include <sys/mman.h>
     12 #include <unistd.h>
     13 
     14 bool SkPurgeableMemoryBlock::IsSupported() {
     15     return true;
     16 }
     17 
     18 #ifdef SK_DEBUG
     19 bool SkPurgeableMemoryBlock::PlatformSupportsPurgingAllUnpinnedBlocks() {
     20     return false;
     21 }
     22 
     23 bool SkPurgeableMemoryBlock::PurgeAllUnpinnedBlocks() {
     24     return false;
     25 }
     26 
     27 bool SkPurgeableMemoryBlock::purge() {
     28     SkASSERT(!fPinned);
     29     if (-1 != fFD) {
     30         ashmem_purge_all_caches(fFD);
     31         return true;
     32     } else {
     33         return false;
     34     }
     35 }
     36 #endif
     37 
     38 // ashmem likes lengths on page boundaries.
     39 static size_t round_to_page_size(size_t size) {
     40     const size_t mask = getpagesize() - 1;
     41     size_t newSize = (size + mask) & ~mask;
     42     return newSize;
     43 }
     44 
     45 SkPurgeableMemoryBlock::SkPurgeableMemoryBlock(size_t size)
     46     : fAddr(NULL)
     47     , fSize(round_to_page_size(size))
     48     , fPinned(false)
     49     , fFD(-1) {
     50 }
     51 
     52 SkPurgeableMemoryBlock::~SkPurgeableMemoryBlock() {
     53     if (-1 != fFD) {
     54         munmap(fAddr, fSize);
     55         close(fFD);
     56     }
     57 }
     58 
     59 void* SkPurgeableMemoryBlock::pin(SkPurgeableMemoryBlock::PinResult* pinResult) {
     60     SkASSERT(!fPinned);
     61     if (-1 == fFD) {
     62         int fd = ashmem_create_region(NULL, fSize);
     63         if (-1 == fd) {
     64             SkDebugf("ashmem_create_region failed\n");
     65             return NULL;
     66         }
     67 
     68         int err = ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE);
     69         if (err != 0) {
     70             SkDebugf("ashmem_set_prot_region failed\n");
     71             close(fd);
     72             return NULL;
     73         }
     74 
     75         void* addr = mmap(NULL, fSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
     76         if (-1 == (long) addr) {
     77             SkDebugf("mmap failed\n");
     78             close(fd);
     79             return NULL;
     80         }
     81         fAddr = addr;
     82         fFD = fd;
     83         (void) ashmem_pin_region(fd, 0, 0);
     84         *pinResult = kUninitialized_PinResult;
     85         fPinned = true;
     86     } else {
     87         int pin = ashmem_pin_region(fFD, 0, 0);
     88         if (ASHMEM_NOT_PURGED == pin) {
     89             fPinned = true;
     90             *pinResult = kRetained_PinResult;
     91         } else if (ASHMEM_WAS_PURGED == pin) {
     92             fPinned = true;
     93             *pinResult = kUninitialized_PinResult;
     94         } else {
     95             // Failed.
     96             munmap(fAddr, fSize);
     97             close(fFD);
     98             fFD = -1;
     99             fAddr = NULL;
    100         }
    101     }
    102     return fAddr;
    103 }
    104 
    105 void SkPurgeableMemoryBlock::unpin() {
    106     if (-1 != fFD) {
    107         ashmem_unpin_region(fFD, 0, 0);
    108         fPinned = false;
    109     }
    110 }
    111