2009-03-04 11:32:55 +08:00
|
|
|
/* libs/pixelflinger/codeflinger/CodeCache.cpp
|
|
|
|
**
|
|
|
|
** Copyright 2006, The Android Open Source Project
|
|
|
|
**
|
|
|
|
** Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
** you may not use this file except in compliance with the License.
|
|
|
|
** You may obtain a copy of the License at
|
|
|
|
**
|
|
|
|
** http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
**
|
|
|
|
** Unless required by applicable law or agreed to in writing, software
|
|
|
|
** distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
** See the License for the specific language governing permissions and
|
|
|
|
** limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2010-05-07 06:05:52 +08:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/mman.h>
|
2009-03-04 11:32:55 +08:00
|
|
|
|
|
|
|
#include <cutils/log.h>
|
|
|
|
#include <cutils/atomic.h>
|
|
|
|
|
|
|
|
#include "codeflinger/CodeCache.h"
|
|
|
|
|
|
|
|
namespace android {
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
#if defined(__arm__)
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
Assembly::Assembly(size_t size)
|
|
|
|
: mCount(1), mSize(0)
|
|
|
|
{
|
2010-05-07 06:05:52 +08:00
|
|
|
mBase = (uint32_t*)mspace_malloc(getMspace(), size);
|
|
|
|
mSize = size;
|
|
|
|
ensureMbaseExecutable();
|
2009-03-04 11:32:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Assembly::~Assembly()
|
|
|
|
{
|
2010-05-07 06:05:52 +08:00
|
|
|
mspace_free(getMspace(), mBase);
|
2009-03-04 11:32:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Assembly::incStrong(const void*) const
|
|
|
|
{
|
|
|
|
android_atomic_inc(&mCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Assembly::decStrong(const void*) const
|
|
|
|
{
|
|
|
|
if (android_atomic_dec(&mCount) == 1) {
|
|
|
|
delete this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t Assembly::size() const
|
|
|
|
{
|
|
|
|
if (!mBase) return NO_MEMORY;
|
|
|
|
return mSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t* Assembly::base() const
|
|
|
|
{
|
|
|
|
return mBase;
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t Assembly::resize(size_t newSize)
|
|
|
|
{
|
2010-05-07 06:05:52 +08:00
|
|
|
mBase = (uint32_t*)mspace_realloc(getMspace(), mBase, newSize);
|
2009-03-04 11:32:55 +08:00
|
|
|
mSize = newSize;
|
2010-05-07 06:05:52 +08:00
|
|
|
ensureMbaseExecutable();
|
2009-03-04 11:32:55 +08:00
|
|
|
return size();
|
|
|
|
}
|
|
|
|
|
2010-05-07 06:05:52 +08:00
|
|
|
mspace Assembly::getMspace()
|
|
|
|
{
|
|
|
|
static mspace msp = create_contiguous_mspace(2 * 1024, 1024 * 1024, /*locked=*/ false);
|
|
|
|
return msp;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Assembly::ensureMbaseExecutable()
|
|
|
|
{
|
|
|
|
long pagesize = sysconf(_SC_PAGESIZE);
|
|
|
|
long pagemask = ~(pagesize - 1); // assumes pagesize is a power of 2
|
|
|
|
|
|
|
|
uint32_t* pageStart = (uint32_t*) (((uintptr_t) mBase) & pagemask);
|
2010-10-15 05:29:00 +08:00
|
|
|
size_t adjustedLength = (mBase - pageStart) * sizeof(uint32_t) + mSize;
|
2010-05-07 06:05:52 +08:00
|
|
|
|
|
|
|
if (mBase && mprotect(pageStart, adjustedLength, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) {
|
|
|
|
mspace_free(getMspace(), mBase);
|
|
|
|
mBase = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-04 11:32:55 +08:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
CodeCache::CodeCache(size_t size)
|
|
|
|
: mCacheSize(size), mCacheInUse(0)
|
|
|
|
{
|
|
|
|
pthread_mutex_init(&mLock, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
CodeCache::~CodeCache()
|
|
|
|
{
|
|
|
|
pthread_mutex_destroy(&mLock);
|
|
|
|
}
|
|
|
|
|
|
|
|
sp<Assembly> CodeCache::lookup(const AssemblyKeyBase& keyBase) const
|
|
|
|
{
|
|
|
|
pthread_mutex_lock(&mLock);
|
|
|
|
sp<Assembly> r;
|
|
|
|
ssize_t index = mCacheData.indexOfKey(key_t(keyBase));
|
|
|
|
if (index >= 0) {
|
|
|
|
const cache_entry_t& e = mCacheData.valueAt(index);
|
|
|
|
e.when = mWhen++;
|
|
|
|
r = e.entry;
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&mLock);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
int CodeCache::cache( const AssemblyKeyBase& keyBase,
|
|
|
|
const sp<Assembly>& assembly)
|
|
|
|
{
|
|
|
|
pthread_mutex_lock(&mLock);
|
|
|
|
|
|
|
|
const ssize_t assemblySize = assembly->size();
|
|
|
|
while (mCacheInUse + assemblySize > mCacheSize) {
|
|
|
|
// evict the LRU
|
|
|
|
size_t lru = 0;
|
|
|
|
size_t count = mCacheData.size();
|
|
|
|
for (size_t i=0 ; i<count ; i++) {
|
|
|
|
const cache_entry_t& e = mCacheData.valueAt(i);
|
|
|
|
if (e.when < mCacheData.valueAt(lru).when) {
|
|
|
|
lru = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const cache_entry_t& e = mCacheData.valueAt(lru);
|
|
|
|
mCacheInUse -= e.entry->size();
|
|
|
|
mCacheData.removeItemsAt(lru);
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t err = mCacheData.add(key_t(keyBase), cache_entry_t(assembly, mWhen));
|
|
|
|
if (err >= 0) {
|
|
|
|
mCacheInUse += assemblySize;
|
|
|
|
mWhen++;
|
|
|
|
// synchronize caches...
|
|
|
|
#if defined(__arm__)
|
|
|
|
const long base = long(assembly->base());
|
|
|
|
const long curr = base + long(assembly->size());
|
|
|
|
err = cacheflush(base, curr, 0);
|
|
|
|
LOGE_IF(err, "__ARM_NR_cacheflush error %s\n",
|
|
|
|
strerror(errno));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&mLock);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
}; // namespace android
|