CodeCache.cpp revision 8e0e372a388434a0553810e2b958e59a26a6bd96
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/log.h>
26#include <cutils/atomic.h>
27
28#include "codeflinger/CodeCache.h"
29
30namespace android {
31
32// ----------------------------------------------------------------------------
33
34#if defined(__arm__)
35#include <unistd.h>
36#include <errno.h>
37#endif
38
39// ----------------------------------------------------------------------------
40
41Assembly::Assembly(size_t size)
42    : mCount(1), mSize(0)
43{
44    mBase = (uint32_t*)mspace_malloc(getMspace(), size);
45    mSize = size;
46    ensureMbaseExecutable();
47}
48
49Assembly::~Assembly()
50{
51    mspace_free(getMspace(), mBase);
52}
53
54void Assembly::incStrong(const void*) const
55{
56    android_atomic_inc(&mCount);
57}
58
59void Assembly::decStrong(const void*) const
60{
61    if (android_atomic_dec(&mCount) == 1) {
62        delete this;
63    }
64}
65
66ssize_t Assembly::size() const
67{
68    if (!mBase) return NO_MEMORY;
69    return mSize;
70}
71
72uint32_t* Assembly::base() const
73{
74    return mBase;
75}
76
77ssize_t Assembly::resize(size_t newSize)
78{
79    mBase = (uint32_t*)mspace_realloc(getMspace(), mBase, newSize);
80    mSize = newSize;
81    ensureMbaseExecutable();
82    return size();
83}
84
85mspace Assembly::getMspace()
86{
87    static mspace msp = create_contiguous_mspace(2 * 1024, 1024 * 1024, /*locked=*/ false);
88    return msp;
89}
90
91void Assembly::ensureMbaseExecutable()
92{
93    long pagesize = sysconf(_SC_PAGESIZE);
94    long pagemask = ~(pagesize - 1);  // assumes pagesize is a power of 2
95
96    uint32_t* pageStart = (uint32_t*) (((uintptr_t) mBase) & pagemask);
97    size_t adjustedLength = (mBase - pageStart) * sizeof(uint32_t) + mSize;
98
99    if (mBase && mprotect(pageStart, adjustedLength, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) {
100        mspace_free(getMspace(), mBase);
101        mBase = NULL;
102    }
103}
104
105// ----------------------------------------------------------------------------
106
107CodeCache::CodeCache(size_t size)
108    : mCacheSize(size), mCacheInUse(0)
109{
110    pthread_mutex_init(&mLock, 0);
111}
112
113CodeCache::~CodeCache()
114{
115    pthread_mutex_destroy(&mLock);
116}
117
118sp<Assembly> CodeCache::lookup(const AssemblyKeyBase& keyBase) const
119{
120    pthread_mutex_lock(&mLock);
121    sp<Assembly> r;
122    ssize_t index = mCacheData.indexOfKey(key_t(keyBase));
123    if (index >= 0) {
124        const cache_entry_t& e = mCacheData.valueAt(index);
125        e.when = mWhen++;
126        r = e.entry;
127    }
128    pthread_mutex_unlock(&mLock);
129    return r;
130}
131
132int CodeCache::cache(  const AssemblyKeyBase& keyBase,
133                            const sp<Assembly>& assembly)
134{
135    pthread_mutex_lock(&mLock);
136
137    const ssize_t assemblySize = assembly->size();
138    while (mCacheInUse + assemblySize > mCacheSize) {
139        // evict the LRU
140        size_t lru = 0;
141        size_t count = mCacheData.size();
142        for (size_t i=0 ; i<count ; i++) {
143            const cache_entry_t& e = mCacheData.valueAt(i);
144            if (e.when < mCacheData.valueAt(lru).when) {
145                lru = i;
146            }
147        }
148        const cache_entry_t& e = mCacheData.valueAt(lru);
149        mCacheInUse -= e.entry->size();
150        mCacheData.removeItemsAt(lru);
151    }
152
153    ssize_t err = mCacheData.add(key_t(keyBase), cache_entry_t(assembly, mWhen));
154    if (err >= 0) {
155        mCacheInUse += assemblySize;
156        mWhen++;
157        // synchronize caches...
158#if defined(__arm__)
159        const long base = long(assembly->base());
160        const long curr = base + long(assembly->size());
161        err = cacheflush(base, curr, 0);
162        LOGE_IF(err, "__ARM_NR_cacheflush error %s\n",
163                strerror(errno));
164#endif
165    }
166
167    pthread_mutex_unlock(&mLock);
168    return err;
169}
170
171// ----------------------------------------------------------------------------
172
173}; // namespace android
174