OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkAshmemImageCache.h" | 8 #include "SkAshmemImageCache.h" |
9 #include "SkThread.h" | 9 #include "SkThread.h" |
10 | 10 |
(...skipping 16 matching lines...) Expand all Loading... |
27 return &gCache; | 27 return &gCache; |
28 } | 28 } |
29 | 29 |
30 #ifdef SK_DEBUG | 30 #ifdef SK_DEBUG |
31 SkAshmemImageCache::~SkAshmemImageCache() { | 31 SkAshmemImageCache::~SkAshmemImageCache() { |
32 SkASSERT(fRecs.count() == 0); | 32 SkASSERT(fRecs.count() == 0); |
33 } | 33 } |
34 #endif | 34 #endif |
35 | 35 |
36 // ashmem likes lengths on page boundaries. | 36 // ashmem likes lengths on page boundaries. |
37 static size_t roundToPageSize(size_t size) { | 37 static size_t round_to_page_size(size_t size) { |
38 const size_t mask = getpagesize() - 1; | 38 const size_t mask = getpagesize() - 1; |
39 size_t newSize = (size + mask) & ~mask; | 39 size_t newSize = (size + mask) & ~mask; |
40 return newSize; | 40 return newSize; |
41 } | 41 } |
42 | 42 |
43 void* SkAshmemImageCache::allocAndPinCache(size_t bytes, intptr_t* ID) { | 43 void* SkAshmemImageCache::allocAndPinCache(size_t bytes, intptr_t* ID) { |
44 SkASSERT(ID != NULL); | 44 SkASSERT(ID != NULL); |
45 | 45 |
46 SkAutoMutexAcquire ac(&gAshmemMutex); | 46 SkAutoMutexAcquire ac(&gAshmemMutex); |
47 | 47 |
48 if (*ID != SkImageCache::UNINITIALIZED_ID) { | |
49 // This rec was previously allocated, but pinCache subsequently | |
50 // failed. | |
51 AshmemRec* pRec = reinterpret_cast<AshmemRec*>(*ID); | |
52 SkASSERT(roundToPageSize(bytes) == pRec->fSize); | |
53 SkASSERT(pRec->fFD != -1); | |
54 (void) ashmem_pin_region(pRec->fFD, 0, 0); | |
55 #ifdef SK_DEBUG | |
56 pRec->fPinned = true; | |
57 #endif | |
58 return pRec->fAddr; | |
59 } | |
60 | |
61 AshmemRec rec; | 48 AshmemRec rec; |
62 rec.fSize = roundToPageSize(bytes); | 49 rec.fSize = round_to_page_size(bytes); |
63 | 50 |
64 rec.fFD = ashmem_create_region(NULL, rec.fSize); | 51 rec.fFD = ashmem_create_region(NULL, rec.fSize); |
65 if (-1 == rec.fFD) { | 52 if (-1 == rec.fFD) { |
66 SkDebugf("ashmem_create_region failed\n"); | 53 SkDebugf("ashmem_create_region failed\n"); |
67 return NULL; | 54 return NULL; |
68 } | 55 } |
69 int err = ashmem_set_prot_region(rec.fFD, PROT_READ | PROT_WRITE); | 56 int err = ashmem_set_prot_region(rec.fFD, PROT_READ | PROT_WRITE); |
70 if (err != 0) { | 57 if (err != 0) { |
71 SkDebugf("ashmem_set_prot_region failed\n"); | 58 SkDebugf("ashmem_set_prot_region failed\n"); |
72 close(rec.fFD); | 59 close(rec.fFD); |
(...skipping 12 matching lines...) Expand all Loading... |
85 // In release mode, we do not keep a pointer to this object. It will be dest
royed | 72 // In release mode, we do not keep a pointer to this object. It will be dest
royed |
86 // either when pinCache returns NULL or when throwAwayCache is called. | 73 // either when pinCache returns NULL or when throwAwayCache is called. |
87 AshmemRec* pRec = SkNEW_ARGS(AshmemRec, (rec)); | 74 AshmemRec* pRec = SkNEW_ARGS(AshmemRec, (rec)); |
88 *ID = reinterpret_cast<intptr_t>(pRec); | 75 *ID = reinterpret_cast<intptr_t>(pRec); |
89 #ifdef SK_DEBUG | 76 #ifdef SK_DEBUG |
90 this->appendRec(pRec); | 77 this->appendRec(pRec); |
91 #endif | 78 #endif |
92 return rec.fAddr; | 79 return rec.fAddr; |
93 } | 80 } |
94 | 81 |
95 void* SkAshmemImageCache::pinCache(intptr_t ID) { | 82 void* SkAshmemImageCache::pinCache(intptr_t ID, PurgeStatus* status) { |
| 83 SkASSERT(ID != SkImageCache::UNINITIALIZED_ID); |
| 84 SkASSERT(status != NULL); |
96 SkAutoMutexAcquire ac(&gAshmemMutex); | 85 SkAutoMutexAcquire ac(&gAshmemMutex); |
97 AshmemRec* rec = reinterpret_cast<AshmemRec*>(ID); | 86 AshmemRec* rec = reinterpret_cast<AshmemRec*>(ID); |
98 const int fd = rec->fFD; | 87 const int fd = rec->fFD; |
99 int pin = ashmem_pin_region(fd, 0, 0); | 88 int pin = ashmem_pin_region(fd, 0, 0); |
100 if (ASHMEM_NOT_PURGED == pin) { | 89 if (ASHMEM_NOT_PURGED == pin) { |
| 90 *status = SkImageCache::kNotPurged_PurgeStatus; |
| 91 } else if (ASHMEM_WAS_PURGED == pin) { |
| 92 *status = SkImageCache::kPurged_PurgeStatus; |
| 93 } else { |
| 94 this->throwAwayCacheInternal(ID); |
| 95 return NULL; |
| 96 } |
101 #ifdef SK_DEBUG | 97 #ifdef SK_DEBUG |
102 rec->fPinned = true; | 98 rec->fPinned = true; |
103 #endif | 99 #endif |
104 return rec->fAddr; | 100 return rec->fAddr; |
105 } | |
106 ashmem_unpin_region(fd, 0, 0); | |
107 return NULL; | |
108 } | 101 } |
109 | 102 |
110 void SkAshmemImageCache::releaseCache(intptr_t ID) { | 103 void SkAshmemImageCache::releaseCache(intptr_t ID) { |
111 SkAutoMutexAcquire ac(&gAshmemMutex); | 104 SkAutoMutexAcquire ac(&gAshmemMutex); |
112 AshmemRec* rec = reinterpret_cast<AshmemRec*>(ID); | 105 AshmemRec* rec = reinterpret_cast<AshmemRec*>(ID); |
113 ashmem_unpin_region(rec->fFD, 0, 0); | 106 ashmem_unpin_region(rec->fFD, 0, 0); |
114 #ifdef SK_DEBUG | 107 #ifdef SK_DEBUG |
115 rec->fPinned = false; | 108 rec->fPinned = false; |
116 #endif | 109 #endif |
117 } | 110 } |
118 | 111 |
119 void SkAshmemImageCache::throwAwayCache(intptr_t ID) { | 112 void SkAshmemImageCache::throwAwayCache(intptr_t ID) { |
120 SkAutoMutexAcquire ac(&gAshmemMutex); | 113 SkAutoMutexAcquire ac(&gAshmemMutex); |
| 114 this->throwAwayCacheInternal(ID); |
| 115 } |
| 116 |
| 117 void SkAshmemImageCache::throwAwayCacheInternal(intptr_t ID) { |
| 118 if (SkImageCache::UNINITIALIZED_ID == ID) { |
| 119 return; |
| 120 } |
121 AshmemRec* rec = reinterpret_cast<AshmemRec*>(ID); | 121 AshmemRec* rec = reinterpret_cast<AshmemRec*>(ID); |
122 munmap(rec->fAddr, rec->fSize); | 122 if (rec->fFD != -1) { |
123 close(rec->fFD); | 123 munmap(rec->fAddr, rec->fSize); |
| 124 close(rec->fFD); |
| 125 } |
124 #ifdef SK_DEBUG | 126 #ifdef SK_DEBUG |
125 SkASSERT(!rec->fPinned); | 127 SkASSERT(!rec->fPinned); |
126 int index = this->findRec(rec); | 128 int index = this->findRec(rec); |
127 SkASSERT(index >= 0); | 129 SkASSERT(index >= 0); |
128 fRecs.remove(index); | 130 fRecs.remove(index); |
129 #endif | 131 #endif |
130 SkDELETE(rec); | 132 SkDELETE(rec); |
131 } | 133 } |
132 | 134 |
133 #ifdef SK_DEBUG | 135 #ifdef SK_DEBUG |
134 void SkAshmemImageCache::appendRec(SkAshmemImageCache::AshmemRec* rec) { | 136 void SkAshmemImageCache::appendRec(SkAshmemImageCache::AshmemRec* rec) { |
135 int index = this->findRec(rec); | 137 int index = this->findRec(rec); |
136 // Should not already exist. | 138 // Should not already exist. |
137 SkASSERT(index < 0); | 139 SkASSERT(index < 0); |
138 fRecs.insert(~index, 1, &rec); | 140 fRecs.insert(~index, 1, &rec); |
139 } | 141 } |
140 | 142 |
141 int SkAshmemImageCache::AshmemRec::Compare(const SkAshmemImageCache::AshmemRec*
a, | 143 int SkAshmemImageCache::AshmemRec::Compare(const SkAshmemImageCache::AshmemRec*
a, |
142 const SkAshmemImageCache::AshmemRec*
b) { | 144 const SkAshmemImageCache::AshmemRec*
b) { |
143 return reinterpret_cast<intptr_t>(a) - reinterpret_cast<intptr_t>(b); | 145 return reinterpret_cast<intptr_t>(a) - reinterpret_cast<intptr_t>(b); |
144 } | 146 } |
145 | 147 |
146 int SkAshmemImageCache::findRec(const SkAshmemImageCache::AshmemRec* rec) const
{ | 148 int SkAshmemImageCache::findRec(const SkAshmemImageCache::AshmemRec* rec) const
{ |
147 return SkTSearch<AshmemRec>((const AshmemRec**)fRecs.begin(), fRecs.count(),
rec, | 149 return SkTSearch<AshmemRec>((const AshmemRec**)fRecs.begin(), fRecs.count(),
rec, |
148 sizeof(intptr_t), AshmemRec::Compare); | 150 sizeof(intptr_t), AshmemRec::Compare); |
149 } | 151 } |
150 | 152 |
151 SkImageCache::CacheStatus SkAshmemImageCache::getCacheStatus(intptr_t ID) const
{ | 153 SkImageCache::PinStatus SkAshmemImageCache::getPinStatus(intptr_t ID) const { |
152 SkAutoMutexAcquire ac(&gAshmemMutex); | 154 SkAutoMutexAcquire ac(&gAshmemMutex); |
153 AshmemRec* rec = reinterpret_cast<AshmemRec*>(ID); | 155 AshmemRec* rec = reinterpret_cast<AshmemRec*>(ID); |
| 156 // findRec searches purely based on the value of ID. If rec has already been
deleted, it will |
| 157 // not be in the array. rec will only be accessed if it has not been deleted
. |
154 int index = this->findRec(rec); | 158 int index = this->findRec(rec); |
155 if (index < 0) { | 159 if (index < 0) { |
156 return SkImageCache::kThrownAway_CacheStatus; | 160 return SkImageCache::kThrownAway_PinStatus; |
157 } | 161 } |
158 return rec->fPinned ? SkImageCache::kPinned_CacheStatus | 162 return rec->fPinned ? SkImageCache::kPinned_PinStatus |
159 : SkImageCache::kUnpinned_CacheStatus; | 163 : SkImageCache::kNeedsPin_PinStatus; |
| 164 } |
| 165 |
| 166 void SkAshmemImageCache::purgeAllCaches() { |
| 167 SkAutoMutexAcquire ac(&gAshmemMutex); |
| 168 // FIXME: How to use the ashmem API to do this? |
| 169 for (int i = 0; i < fRecs.count(); i++) { |
| 170 AshmemRec* rec = fRecs.getAt(i); |
| 171 if (!rec->fPinned) { |
| 172 munmap(rec->fAddr, rec->fSize); |
| 173 close(rec->fFD); |
| 174 rec->fFD = -1; |
| 175 rec->fAddr = NULL; |
| 176 rec->fSize = 0; |
| 177 } |
| 178 } |
160 } | 179 } |
161 #endif | 180 #endif |
OLD | NEW |