1 /* libs/pixelflinger/codeflinger/CodeCache.cpp 2 ** 3 ** Copyright 2006, The Android Open Source Project 4 ** 5 ** Licensed under the Apache License, Version 2.0 (the "License"); 6 ** you may not use this file except in compliance with the License. 7 ** You may obtain a copy of the License at 8 ** 9 ** http://www.apache.org/licenses/LICENSE-2.0 10 ** 11 ** Unless required by applicable law or agreed to in writing, software 12 ** distributed under the License is distributed on an "AS IS" BASIS, 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 ** See the License for the specific language governing permissions and 15 ** limitations under the License. 16 */ 17 18 #define LOG_TAG "CodeCache" 19 20 #include <assert.h> 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <sys/mman.h> 24 #include <unistd.h> 25 26 #include <cutils/ashmem.h> 27 #include <log/log.h> 28 29 #include "CodeCache.h" 30 31 namespace android { 32 33 // ---------------------------------------------------------------------------- 34 35 #if defined(__arm__) || defined(__aarch64__) 36 #include <unistd.h> 37 #include <errno.h> 38 #endif 39 40 #if defined(__mips__) 41 #include <asm/cachectl.h> 42 #include <errno.h> 43 #endif 44 45 // ---------------------------------------------------------------------------- 46 // ---------------------------------------------------------------------------- 47 48 // A dlmalloc mspace is used to manage the code cache over a mmaped region. 49 #define HAVE_MMAP 0 50 #define HAVE_MREMAP 0 51 #define HAVE_MORECORE 0 52 #define MALLOC_ALIGNMENT 16 53 #define MSPACES 1 54 #define NO_MALLINFO 1 55 #define ONLY_MSPACES 1 56 // Custom heap error handling. 57 #define PROCEED_ON_ERROR 0 58 static void heap_error(const char* msg, const char* function, void* p); 59 #define CORRUPTION_ERROR_ACTION(m) \ 60 heap_error("HEAP MEMORY CORRUPTION", __FUNCTION__, NULL) 61 #define USAGE_ERROR_ACTION(m,p) \ 62 heap_error("ARGUMENT IS INVALID HEAP ADDRESS", __FUNCTION__, p) 63 64 #include "../../../../external/dlmalloc/malloc.c" 65 66 static void heap_error(const char* msg, const char* function, void* p) { 67 ALOG(LOG_FATAL, LOG_TAG, "@@@ ABORTING: CODE FLINGER: %s IN %s addr=%p", 68 msg, function, p); 69 /* So that we can get a memory dump around p */ 70 *((int **) 0xdeadbaad) = (int *) p; 71 } 72 73 // ---------------------------------------------------------------------------- 74 75 static void* gExecutableStore = NULL; 76 static mspace gMspace = NULL; 77 const size_t kMaxCodeCacheCapacity = 1024 * 1024; 78 79 static mspace getMspace() 80 { 81 if (gExecutableStore == NULL) { 82 int fd = ashmem_create_region("CodeFlinger code cache", 83 kMaxCodeCacheCapacity); 84 LOG_ALWAYS_FATAL_IF(fd < 0, 85 "Creating code cache, ashmem_create_region " 86 "failed with error '%s'", strerror(errno)); 87 gExecutableStore = mmap(NULL, kMaxCodeCacheCapacity, 88 PROT_READ | PROT_WRITE | PROT_EXEC, 89 MAP_PRIVATE, fd, 0); 90 LOG_ALWAYS_FATAL_IF(gExecutableStore == MAP_FAILED, 91 "Creating code cache, mmap failed with error " 92 "'%s'", strerror(errno)); 93 close(fd); 94 gMspace = create_mspace_with_base(gExecutableStore, kMaxCodeCacheCapacity, 95 /*locked=*/ false); 96 mspace_set_footprint_limit(gMspace, kMaxCodeCacheCapacity); 97 } 98 return gMspace; 99 } 100 101 Assembly::Assembly(size_t size) 102 : mCount(0), mSize(0) 103 { 104 mBase = (uint32_t*)mspace_malloc(getMspace(), size); 105 LOG_ALWAYS_FATAL_IF(mBase == NULL, 106 "Failed to create Assembly of size %zd in executable " 107 "store of size %zd", size, kMaxCodeCacheCapacity); 108 mSize = size; 109 } 110 111 Assembly::~Assembly() 112 { 113 mspace_free(getMspace(), mBase); 114 } 115 116 void Assembly::incStrong(const void*) const 117 { 118 mCount.fetch_add(1, std::memory_order_relaxed); 119 } 120 121 void Assembly::decStrong(const void*) const 122 { 123 if (mCount.fetch_sub(1, std::memory_order_acq_rel) == 1) { 124 delete this; 125 } 126 } 127 128 ssize_t Assembly::size() const 129 { 130 if (!mBase) return NO_MEMORY; 131 return mSize; 132 } 133 134 uint32_t* Assembly::base() const 135 { 136 return mBase; 137 } 138 139 ssize_t Assembly::resize(size_t newSize) 140 { 141 mBase = (uint32_t*)mspace_realloc(getMspace(), mBase, newSize); 142 LOG_ALWAYS_FATAL_IF(mBase == NULL, 143 "Failed to resize Assembly to %zd in code cache " 144 "of size %zd", newSize, kMaxCodeCacheCapacity); 145 mSize = newSize; 146 return size(); 147 } 148 149 // ---------------------------------------------------------------------------- 150 151 CodeCache::CodeCache(size_t size) 152 : mCacheSize(size), mCacheInUse(0) 153 { 154 pthread_mutex_init(&mLock, 0); 155 } 156 157 CodeCache::~CodeCache() 158 { 159 pthread_mutex_destroy(&mLock); 160 } 161 162 sp<Assembly> CodeCache::lookup(const AssemblyKeyBase& keyBase) const 163 { 164 pthread_mutex_lock(&mLock); 165 sp<Assembly> r; 166 ssize_t index = mCacheData.indexOfKey(key_t(keyBase)); 167 if (index >= 0) { 168 const cache_entry_t& e = mCacheData.valueAt(index); 169 e.when = mWhen++; 170 r = e.entry; 171 } 172 pthread_mutex_unlock(&mLock); 173 return r; 174 } 175 176 int CodeCache::cache( const AssemblyKeyBase& keyBase, 177 const sp<Assembly>& assembly) 178 { 179 pthread_mutex_lock(&mLock); 180 181 const ssize_t assemblySize = assembly->size(); 182 while (mCacheInUse + assemblySize > mCacheSize) { 183 // evict the LRU 184 size_t lru = 0; 185 size_t count = mCacheData.size(); 186 for (size_t i=0 ; i<count ; i++) { 187 const cache_entry_t& e = mCacheData.valueAt(i); 188 if (e.when < mCacheData.valueAt(lru).when) { 189 lru = i; 190 } 191 } 192 const cache_entry_t& e = mCacheData.valueAt(lru); 193 mCacheInUse -= e.entry->size(); 194 mCacheData.removeItemsAt(lru); 195 } 196 197 ssize_t err = mCacheData.add(key_t(keyBase), cache_entry_t(assembly, mWhen)); 198 if (err >= 0) { 199 mCacheInUse += assemblySize; 200 mWhen++; 201 // synchronize caches... 202 char* base = reinterpret_cast<char*>(assembly->base()); 203 char* curr = reinterpret_cast<char*>(base + assembly->size()); 204 __builtin___clear_cache(base, curr); 205 } 206 207 pthread_mutex_unlock(&mLock); 208 return err; 209 } 210 211 // ---------------------------------------------------------------------------- 212 213 }; // namespace android 214