Home | History | Annotate | Download | only in OldJIT
      1 /*
      2  * copyright 2010, the android open source project
      3  *
      4  * licensed under the apache license, version 2.0 (the "license");
      5  * you may not use this file except in compliance with the license.
      6  * you may obtain a copy of the license at
      7  *
      8  *     http://www.apache.org/licenses/license-2.0
      9  *
     10  * unless required by applicable law or agreed to in writing, software
     11  * distributed under the license is distributed on an "as is" basis,
     12  * without warranties or conditions of any kind, either express or implied.
     13  * see the license for the specific language governing permissions and
     14  * limitations under the license.
     15  */
     16 
     17 #include "ContextManager.h"
     18 
     19 #include "DebugHelper.h"
     20 
     21 #include <llvm/Support/Mutex.h>
     22 #include <llvm/Support/MutexGuard.h>
     23 
     24 #include <errno.h>
     25 #include <sys/mman.h>
     26 #include <utils/threads.h>
     27 
     28 #include <stddef.h>
     29 #include <string.h>
     30 
     31 
     32 namespace bcc {
     33 
     34 // Starting address for context slots
     35 char * const ContextManager::ContextFixedAddr = BCC_CONTEXT_FIXED_ADDR_;
     36 
     37 // ContextManager singleton object
     38 ContextManager ContextManager::TheContextManager;
     39 
     40 
     41 ContextManager::ContextManager() {
     42   // Initialize context slot occupation table to false
     43   for (size_t i = 0; i < ContextSlotCount; ++i) {
     44     mContextSlotOccupied[i] = false;
     45   }
     46 }
     47 
     48 char *ContextManager::allocateContext() {
     49   {
     50     // Acquire mContextSlotOccupiedLock
     51     llvm::MutexGuard Locked(mContextSlotOccupiedLock);
     52 
     53     // Try to allocate context on the managed context slot.
     54     for (size_t i = 0; i < ContextSlotCount; ++i) {
     55       if (mContextSlotOccupied[i]) {
     56         continue;
     57       }
     58 
     59       void *addr = ContextFixedAddr + ContextSize * i;
     60       void *result = mmap(addr, ContextSize,
     61                           PROT_READ | PROT_WRITE | PROT_EXEC,
     62                           MAP_PRIVATE | MAP_ANON, -1, 0);
     63 
     64       if (result == addr) {
     65         LOGI("Allocate bcc context. addr=%p\n", result);
     66         mContextSlotOccupied[i] = true;
     67         return static_cast<char *>(result);
     68       }
     69 
     70       if (result && result != MAP_FAILED) {
     71         LOGE("Unable to allocate. suggested=%p, result=%p\n", addr, result);
     72         munmap(result, ContextSize);
     73       }
     74 
     75       LOGE("Unable to allocate. addr=%p.  Retry ...\n", addr);
     76     }
     77     // Release mContextSlotOccupiedLock
     78   }
     79 
     80   // No slot available, allocate at arbitary address.
     81   void *result = mmap(0, ContextSize, PROT_READ | PROT_WRITE | PROT_EXEC,
     82                       MAP_PRIVATE | MAP_ANON, -1, 0);
     83 
     84   if (!result || result == MAP_FAILED) {
     85     LOGE("Unable to mmap. (reason: %s)\n", strerror(errno));
     86     return NULL;
     87   }
     88 
     89   LOGI("Allocate bcc context. addr=%p\n", result);
     90   return static_cast<char *>(result);
     91 }
     92 
     93 
     94 char *ContextManager::allocateContext(char *addr,
     95                                       int imageFd, off_t imageOffset) {
     96   // This function should only allocate context when address is an context
     97   // slot address.  And the image offset is aligned to the pagesize.
     98 
     99   if (imageFd < 0) {
    100     LOGE("Invalid file descriptor for bcc context image\n");
    101     return NULL;
    102   }
    103 
    104   unsigned long pagesize = (unsigned long)sysconf(_SC_PAGESIZE);
    105 
    106   if (imageOffset % pagesize > 0) {
    107     LOGE("BCC context image offset is not aligned to page size\n");
    108     return NULL;
    109   }
    110 
    111   ssize_t slot = getSlotIndexFromAddress(addr);
    112   if (slot < 0) {
    113     LOGE("Suggested address is not a bcc context slot address\n");
    114     return NULL;
    115   }
    116 
    117   llvm::MutexGuard Locked(mContextSlotOccupiedLock);
    118   if (mContextSlotOccupied[slot]) {
    119     LOGW("Suggested bcc context slot has been occupied.\n");
    120     return NULL;
    121   }
    122 
    123   // LOGI("addr=%x, imageFd=%d, imageOffset=%x", addr, imageFd, imageOffset);
    124   void *result = mmap(addr, ContextSize,
    125                       PROT_READ | PROT_WRITE | PROT_EXEC,
    126                       MAP_PRIVATE, imageFd, imageOffset);
    127 
    128   if (!result || result == MAP_FAILED) {
    129     LOGE("Unable to allocate. addr=%p\n", addr);
    130     return NULL;
    131   }
    132 
    133   if (result != addr) {
    134     LOGE("Unable to allocate at suggested=%p, result=%p\n", addr, result);
    135     munmap(result, ContextSize);
    136     return NULL;
    137   }
    138 
    139   LOGI("Allocate bcc context. addr=%p\n", addr);
    140   mContextSlotOccupied[slot] = true;
    141   return static_cast<char *>(result);
    142 }
    143 
    144 
    145 void ContextManager::deallocateContext(char *addr) {
    146   if (!addr) {
    147     return;
    148   }
    149 
    150   llvm::MutexGuard Locked(mContextSlotOccupiedLock);
    151 
    152   LOGI("Deallocate bcc context. addr=%p\n", addr);
    153 
    154   // Unmap
    155   if (munmap(addr, ContextSize) < 0) {
    156     LOGE("Unable to unmap. addr=%p (reason: %s)\n", addr, strerror(errno));
    157     return;
    158   }
    159 
    160   // If the address is one of the context slot, then mark such slot
    161   // freely available as well.
    162   ssize_t slot = getSlotIndexFromAddress(addr);
    163   if (slot >= 0) {
    164     // Give the context slot back.
    165     mContextSlotOccupied[slot] = false;
    166   }
    167 }
    168 
    169 
    170 bool ContextManager::isManagingContext(char *addr) const {
    171   ssize_t slot = getSlotIndexFromAddress(addr);
    172 
    173   if (slot < 0) {
    174     return false;
    175   }
    176 
    177   llvm::MutexGuard Locked(mContextSlotOccupiedLock);
    178   return mContextSlotOccupied[slot];
    179 }
    180 
    181 
    182 ssize_t ContextManager::getSlotIndexFromAddress(char *addr) {
    183   if (addr >= ContextFixedAddr) {
    184     size_t offset = (size_t)(addr - ContextFixedAddr);
    185     if (offset % ContextSize == 0) {
    186       size_t slot = offset / ContextSize;
    187       if (slot < ContextSlotCount) {
    188         return slot;
    189       }
    190     }
    191   }
    192   return -1;
    193 }
    194 
    195 
    196 
    197 } // namespace bcc
    198