OLD | NEW |
| (Empty) |
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 <unistd.h> | |
9 #include <sys/mman.h> | |
10 #include "SkDiscardableMemory.h" | |
11 #include "SkDiscardableMemoryPool.h" | |
12 #include "SkTypes.h" | |
13 #include "android/ashmem.h" | |
14 | |
15 //////////////////////////////////////////////////////////////////////////////// | |
16 namespace { | |
17 /** | |
18 * DiscardableMemory implementation that uses the Android kernel's | |
19 * ashmem (Android shared memory). | |
20 */ | |
21 class SkAshmemDiscardableMemory : public SkDiscardableMemory { | |
22 public: | |
23 SkAshmemDiscardableMemory(int fd, void* address, size_t size); | |
24 virtual ~SkAshmemDiscardableMemory(); | |
25 virtual bool lock() SK_OVERRIDE; | |
26 virtual void* data() SK_OVERRIDE; | |
27 virtual void unlock() SK_OVERRIDE; | |
28 static SkAshmemDiscardableMemory* Create(size_t bytes); | |
29 | |
30 private: | |
31 bool fLocked; | |
32 int fFd; | |
33 void* fMemory; | |
34 const size_t fSize; | |
35 }; | |
36 | |
37 SkAshmemDiscardableMemory::SkAshmemDiscardableMemory(int fd, | |
38 void* address, | |
39 size_t size) | |
40 : fLocked(true) // Ashmem pages are pinned by default. | |
41 , fFd(fd) | |
42 , fMemory(address) | |
43 , fSize(size) { | |
44 SkASSERT(fFd >= 0); | |
45 SkASSERT(fMemory != NULL); | |
46 SkASSERT(fSize > 0); | |
47 } | |
48 | |
49 SkAshmemDiscardableMemory::~SkAshmemDiscardableMemory() { | |
50 SkASSERT(!fLocked); | |
51 if (NULL != fMemory) { | |
52 munmap(fMemory, fSize); | |
53 } | |
54 if (fFd != -1) { | |
55 close(fFd); | |
56 } | |
57 } | |
58 | |
59 bool SkAshmemDiscardableMemory::lock() { | |
60 SkASSERT(!fLocked); | |
61 if (-1 == fFd) { | |
62 fLocked = false; | |
63 return false; | |
64 } | |
65 SkASSERT(fMemory != NULL); | |
66 if (fLocked || (ASHMEM_NOT_PURGED == ashmem_pin_region(fFd, 0, 0))) { | |
67 fLocked = true; | |
68 return true; | |
69 } else { | |
70 munmap(fMemory, fSize); | |
71 fMemory = NULL; | |
72 | |
73 close(fFd); | |
74 fFd = -1; | |
75 fLocked = false; | |
76 return false; | |
77 } | |
78 } | |
79 | |
80 void* SkAshmemDiscardableMemory::data() { | |
81 SkASSERT(fLocked); | |
82 return fLocked ? fMemory : NULL; | |
83 } | |
84 | |
85 void SkAshmemDiscardableMemory::unlock() { | |
86 SkASSERT(fLocked); | |
87 if (fLocked && (fFd != -1)) { | |
88 ashmem_unpin_region(fFd, 0, 0); | |
89 } | |
90 fLocked = false; | |
91 } | |
92 | |
93 SkAshmemDiscardableMemory* SkAshmemDiscardableMemory::Create(size_t bytes) { | |
94 // ashmem likes lengths on page boundaries. | |
95 const size_t mask = getpagesize() - 1; | |
96 size_t size = (bytes + mask) & ~mask; | |
97 | |
98 static const char name[] = "Skia_Ashmem_Discardable_Memory"; | |
99 int fd = ashmem_create_region(name, size); | |
100 if (fd < 0) { | |
101 return NULL; | |
102 } | |
103 if (0 != ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE)) { | |
104 close(fd); | |
105 return NULL; | |
106 } | |
107 void* addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); | |
108 if ((MAP_FAILED == addr) || (NULL == addr)) { | |
109 close(fd); | |
110 return NULL; | |
111 } | |
112 | |
113 return SkNEW_ARGS(SkAshmemDiscardableMemory, (fd, addr, size)); | |
114 } | |
115 } // namespace | |
116 //////////////////////////////////////////////////////////////////////////////// | |
117 | |
118 #ifndef SK_ASHMEM_MINIMUM_MEMORY_SIZE | |
119 // number taken from android/graphics/BitmapFactory.cpp | |
120 #define SK_ASHMEM_MINIMUM_MEMORY_SIZE (32 * 1024) | |
121 #endif // SK_ASHMEM_MINIMUM_MEMORY_SIZE | |
122 SkDiscardableMemory* SkDiscardableMemory::Create(size_t bytes) { | |
123 if (bytes < SK_ASHMEM_MINIMUM_MEMORY_SIZE) { | |
124 return SkGetGlobalDiscardableMemoryPool()->create(bytes); | |
125 } else { | |
126 return SkAshmemDiscardableMemory::Create(bytes); | |
127 } | |
128 } | |
OLD | NEW |