Home | History | Annotate | Download | only in codeflinger
      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 
     30 namespace android {
     31 
     32 // ----------------------------------------------------------------------------
     33 
     34 #if defined(__arm__)
     35 #include <unistd.h>
     36 #include <errno.h>
     37 #endif
     38 
     39 // ----------------------------------------------------------------------------
     40 
     41 Assembly::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 
     49 Assembly::~Assembly()
     50 {
     51     mspace_free(getMspace(), mBase);
     52 }
     53 
     54 void Assembly::incStrong(const void*) const
     55 {
     56     android_atomic_inc(&mCount);
     57 }
     58 
     59 void Assembly::decStrong(const void*) const
     60 {
     61     if (android_atomic_dec(&mCount) == 1) {
     62         delete this;
     63     }
     64 }
     65 
     66 ssize_t Assembly::size() const
     67 {
     68     if (!mBase) return NO_MEMORY;
     69     return mSize;
     70 }
     71 
     72 uint32_t* Assembly::base() const
     73 {
     74     return mBase;
     75 }
     76 
     77 ssize_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 
     85 mspace Assembly::getMspace()
     86 {
     87     static mspace msp = create_contiguous_mspace(2 * 1024, 1024 * 1024, /*locked=*/ false);
     88     return msp;
     89 }
     90 
     91 void 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 
    107 CodeCache::CodeCache(size_t size)
    108     : mCacheSize(size), mCacheInUse(0)
    109 {
    110     pthread_mutex_init(&mLock, 0);
    111 }
    112 
    113 CodeCache::~CodeCache()
    114 {
    115     pthread_mutex_destroy(&mLock);
    116 }
    117 
    118 sp<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 
    132 int 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