• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
19 #include <assert.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <sys/mman.h>
24 
25 #include <cutils/ashmem.h>
26 #include <cutils/atomic.h>
27 #define LOG_TAG "CodeCache"
28 #include <cutils/log.h>
29 
30 
31 #include "CodeCache.h"
32 
33 namespace android {
34 
35 // ----------------------------------------------------------------------------
36 
37 #if defined(__arm__)
38 #include <unistd.h>
39 #include <errno.h>
40 #endif
41 
42 #if defined(__mips__)
43 #include <asm/cachectl.h>
44 #include <errno.h>
45 #endif
46 
47 // ----------------------------------------------------------------------------
48 // ----------------------------------------------------------------------------
49 
50 // A dlmalloc mspace is used to manage the code cache over a mmaped region.
51 #define HAVE_MMAP 0
52 #define HAVE_MREMAP 0
53 #define HAVE_MORECORE 0
54 #define MALLOC_ALIGNMENT 16
55 #define MSPACES 1
56 #define NO_MALLINFO 1
57 #define ONLY_MSPACES 1
58 // Custom heap error handling.
59 #define PROCEED_ON_ERROR 0
60 static void heap_error(const char* msg, const char* function, void* p);
61 #define CORRUPTION_ERROR_ACTION(m) \
62     heap_error("HEAP MEMORY CORRUPTION", __FUNCTION__, NULL)
63 #define USAGE_ERROR_ACTION(m,p) \
64     heap_error("ARGUMENT IS INVALID HEAP ADDRESS", __FUNCTION__, p)
65 
66 #include "../../../../bionic/libc/upstream-dlmalloc/malloc.c"
67 
heap_error(const char * msg,const char * function,void * p)68 static void heap_error(const char* msg, const char* function, void* p) {
69     ALOG(LOG_FATAL, LOG_TAG, "@@@ ABORTING: CODE FLINGER: %s IN %s addr=%p",
70          msg, function, p);
71     /* So that we can get a memory dump around p */
72     *((int **) 0xdeadbaad) = (int *) p;
73 }
74 
75 // ----------------------------------------------------------------------------
76 
77 static void* gExecutableStore = NULL;
78 static mspace gMspace = NULL;
79 const size_t kMaxCodeCacheCapacity = 1024 * 1024;
80 
getMspace()81 static mspace getMspace()
82 {
83     if (gExecutableStore == NULL) {
84         int fd = ashmem_create_region("CodeFlinger code cache",
85                                       kMaxCodeCacheCapacity);
86         LOG_ALWAYS_FATAL_IF(fd < 0,
87                             "Creating code cache, ashmem_create_region "
88                             "failed with error '%s'", strerror(errno));
89         gExecutableStore = mmap(NULL, kMaxCodeCacheCapacity,
90                                 PROT_READ | PROT_WRITE | PROT_EXEC,
91                                 MAP_PRIVATE, fd, 0);
92         LOG_ALWAYS_FATAL_IF(gExecutableStore == NULL,
93                             "Creating code cache, mmap failed with error "
94                             "'%s'", strerror(errno));
95         close(fd);
96         gMspace = create_mspace_with_base(gExecutableStore, kMaxCodeCacheCapacity,
97                                           /*locked=*/ false);
98         mspace_set_footprint_limit(gMspace, kMaxCodeCacheCapacity);
99     }
100     return gMspace;
101 }
102 
Assembly(size_t size)103 Assembly::Assembly(size_t size)
104     : mCount(1), mSize(0)
105 {
106     mBase = (uint32_t*)mspace_malloc(getMspace(), size);
107     LOG_ALWAYS_FATAL_IF(mBase == NULL,
108                         "Failed to create Assembly of size %zd in executable "
109                         "store of size %zd", size, kMaxCodeCacheCapacity);
110     mSize = size;
111 }
112 
~Assembly()113 Assembly::~Assembly()
114 {
115     mspace_free(getMspace(), mBase);
116 }
117 
incStrong(const void *) const118 void Assembly::incStrong(const void*) const
119 {
120     android_atomic_inc(&mCount);
121 }
122 
decStrong(const void *) const123 void Assembly::decStrong(const void*) const
124 {
125     if (android_atomic_dec(&mCount) == 1) {
126         delete this;
127     }
128 }
129 
size() const130 ssize_t Assembly::size() const
131 {
132     if (!mBase) return NO_MEMORY;
133     return mSize;
134 }
135 
base() const136 uint32_t* Assembly::base() const
137 {
138     return mBase;
139 }
140 
resize(size_t newSize)141 ssize_t Assembly::resize(size_t newSize)
142 {
143     mBase = (uint32_t*)mspace_realloc(getMspace(), mBase, newSize);
144     LOG_ALWAYS_FATAL_IF(mBase == NULL,
145                         "Failed to resize Assembly to %zd in code cache "
146                         "of size %zd", newSize, kMaxCodeCacheCapacity);
147     mSize = newSize;
148     return size();
149 }
150 
151 // ----------------------------------------------------------------------------
152 
CodeCache(size_t size)153 CodeCache::CodeCache(size_t size)
154     : mCacheSize(size), mCacheInUse(0)
155 {
156     pthread_mutex_init(&mLock, 0);
157 }
158 
~CodeCache()159 CodeCache::~CodeCache()
160 {
161     pthread_mutex_destroy(&mLock);
162 }
163 
lookup(const AssemblyKeyBase & keyBase) const164 sp<Assembly> CodeCache::lookup(const AssemblyKeyBase& keyBase) const
165 {
166     pthread_mutex_lock(&mLock);
167     sp<Assembly> r;
168     ssize_t index = mCacheData.indexOfKey(key_t(keyBase));
169     if (index >= 0) {
170         const cache_entry_t& e = mCacheData.valueAt(index);
171         e.when = mWhen++;
172         r = e.entry;
173     }
174     pthread_mutex_unlock(&mLock);
175     return r;
176 }
177 
cache(const AssemblyKeyBase & keyBase,const sp<Assembly> & assembly)178 int CodeCache::cache(  const AssemblyKeyBase& keyBase,
179                             const sp<Assembly>& assembly)
180 {
181     pthread_mutex_lock(&mLock);
182 
183     const ssize_t assemblySize = assembly->size();
184     while (mCacheInUse + assemblySize > mCacheSize) {
185         // evict the LRU
186         size_t lru = 0;
187         size_t count = mCacheData.size();
188         for (size_t i=0 ; i<count ; i++) {
189             const cache_entry_t& e = mCacheData.valueAt(i);
190             if (e.when < mCacheData.valueAt(lru).when) {
191                 lru = i;
192             }
193         }
194         const cache_entry_t& e = mCacheData.valueAt(lru);
195         mCacheInUse -= e.entry->size();
196         mCacheData.removeItemsAt(lru);
197     }
198 
199     ssize_t err = mCacheData.add(key_t(keyBase), cache_entry_t(assembly, mWhen));
200     if (err >= 0) {
201         mCacheInUse += assemblySize;
202         mWhen++;
203         // synchronize caches...
204 #if defined(__arm__) || defined(__mips__)
205         const long base = long(assembly->base());
206         const long curr = base + long(assembly->size());
207         err = cacheflush(base, curr, 0);
208         ALOGE_IF(err, "cacheflush error %s\n",
209                  strerror(errno));
210 #endif
211     }
212 
213     pthread_mutex_unlock(&mLock);
214     return err;
215 }
216 
217 // ----------------------------------------------------------------------------
218 
219 }; // namespace android
220