Refine ContextManager

- Add isManagingContext API
- Remove global lock and global variable (use Singleton instead)
- Encapsulate getSlotIndexFromAddress API
- Extract configurable define to Config.h
diff --git a/lib/bcc/CacheReader.cpp b/lib/bcc/CacheReader.cpp
index a820053..7288b19 100644
--- a/lib/bcc/CacheReader.cpp
+++ b/lib/bcc/CacheReader.cpp
@@ -101,7 +101,7 @@
   mFileSize = stfile.st_size;
 
   if (mFileSize < (off_t)sizeof(OBCC_Header) ||
-      mFileSize < (off_t)BCC_CONTEXT_SIZE) {
+      mFileSize < (off_t)ContextManager::ContextSize) {
     LOGE("Cache file is too small to be correct.\n");
     return false;
   }
@@ -215,7 +215,8 @@
 #undef CHECK_SECTION_OFFSET
 
   if (mFileSize < mpHeader->context_offset ||
-      mFileSize < mpHeader->context_offset + BCC_CONTEXT_SIZE) {
+      mFileSize < (off_t)mpHeader->context_offset +
+                  (off_t)ContextManager::ContextSize) {
     LOGE("context section overflow.\n");
     return false;
   }
@@ -410,9 +411,10 @@
 
 
 bool CacheReader::readContext() {
-  mpResult->mContext = allocateContext(mpHeader->context_cached_addr,
-                                      mFile->getFD(),
-                                      mpHeader->context_offset);
+  mpResult->mContext =
+    ContextManager::get().allocateContext(mpHeader->context_cached_addr,
+                                          mFile->getFD(),
+                                          mpHeader->context_offset);
 
   if (!mpResult->mContext) {
     // Unable to allocate at cached address.  Give up.
@@ -431,7 +433,7 @@
   uint32_t sum = mpHeader->context_parity_checksum;
   uint32_t *ptr = reinterpret_cast<uint32_t *>(mpResult->mContext);
 
-  for (size_t i = 0; i < BCC_CONTEXT_SIZE / sizeof(uint32_t); ++i) {
+  for (size_t i = 0; i < ContextManager::ContextSize / sizeof(uint32_t); ++i) {
     sum ^= *ptr++;
   }
 
diff --git a/lib/bcc/CacheWriter.cpp b/lib/bcc/CacheWriter.cpp
index 27ffd6d..b0971ba 100644
--- a/lib/bcc/CacheWriter.cpp
+++ b/lib/bcc/CacheWriter.cpp
@@ -375,7 +375,7 @@
   uint32_t sum = 0;
   uint32_t *ptr = reinterpret_cast<uint32_t *>(mpOwner->getContext());
 
-  for (size_t i = 0; i < BCC_CONTEXT_SIZE / sizeof(uint32_t); ++i) {
+  for (size_t i = 0; i < ContextManager::ContextSize / sizeof(uint32_t); ++i) {
     sum ^= *ptr++;
   }
 
@@ -416,7 +416,8 @@
   WRITE_SECTION_SIMPLE(func_table, mpFuncTableSection);
   WRITE_SECTION_SIMPLE(object_slot_list, mpObjectSlotSection);
 
-  WRITE_SECTION(context, mpHeaderSection->context_offset, BCC_CONTEXT_SIZE,
+  WRITE_SECTION(context, mpHeaderSection->context_offset,
+                ContextManager::ContextSize,
                 mpOwner->getContext());
 
 #undef WRITE_SECTION_SIMPLE
diff --git a/lib/bcc/ContextManager.cpp b/lib/bcc/ContextManager.cpp
index e480480..16fbcf1 100644
--- a/lib/bcc/ContextManager.cpp
+++ b/lib/bcc/ContextManager.cpp
@@ -19,6 +19,9 @@
 
 #include "ContextManager.h"
 
+#include <llvm/System/Mutex.h>
+#include <llvm/Support/MutexGuard.h>
+
 #include <errno.h>
 #include <sys/mman.h>
 #include <utils/threads.h>
@@ -27,63 +30,56 @@
 #include <string.h>
 
 
-namespace {
-  static bool ContextSlotTaken[BCC_CONTEXT_SLOT_COUNT];
-} // namespace anonymous
-
-
 namespace bcc {
 
-static android::Mutex gContextLock;
+// Starting address for context slots
+char * const ContextManager::ContextFixedAddr = BCC_CONTEXT_FIXED_ADDR_;
+
+// ContextManager singleton object
+ContextManager ContextManager::TheContextManager;
 
 
-ssize_t getSlotIndexFromAddress(char *addr) {
-  if (addr >= BCC_CONTEXT_FIXED_ADDR) {
-    size_t offset = (size_t)(addr - BCC_CONTEXT_FIXED_ADDR);
-    if (offset % BCC_CONTEXT_SIZE == 0) {
-      size_t slot = offset / BCC_CONTEXT_SIZE;
-      if (slot < BCC_CONTEXT_SLOT_COUNT) {
-        return slot;
-      }
-    }
+ContextManager::ContextManager() {
+  // Initialize context slot occupation table to false
+  for (size_t i = 0; i < ContextSlotCount; ++i) {
+    mContextSlotOccupied[i] = false;
   }
-  return -1;
 }
 
+char *ContextManager::allocateContext() {
+  {
+    // Acquire mContextSlotOccupiedLock
+    llvm::MutexGuard Locked(mContextSlotOccupiedLock);
 
-char *allocateContext() {
-  android::AutoMutex _l(gContextLock);
+    // Try to allocate context on the managed context slot.
+    for (size_t i = 0; i < ContextSlotCount; ++i) {
+      if (mContextSlotOccupied[i]) {
+        continue;
+      }
 
-  // Try to allocate context on the managed context slot.
-  for (size_t i = 0; i < BCC_CONTEXT_SLOT_COUNT; ++i) {
-    if (ContextSlotTaken[i]) {
-      continue;
+      void *addr = ContextFixedAddr + ContextSize * i;
+      void *result = mmap(addr, ContextSize,
+                          PROT_READ | PROT_WRITE | PROT_EXEC,
+                          MAP_PRIVATE | MAP_ANON, -1, 0);
+
+      if (result == addr) {
+        LOGI("Allocate bcc context. addr=%p\n", result);
+        mContextSlotOccupied[i] = true;
+        return static_cast<char *>(result);
+      }
+
+      if (result && result != MAP_FAILED) {
+        LOGE("Unable to allocate. suggested=%p, result=%p\n", addr, result);
+        munmap(result, ContextSize);
+      }
+
+      LOGE("Unable to allocate. addr=%p.  Retry ...\n", addr);
     }
-
-    // Try to mmap
-    void *addr = BCC_CONTEXT_FIXED_ADDR + BCC_CONTEXT_SIZE * i;
-    void *result = mmap(addr, BCC_CONTEXT_SIZE,
-                        PROT_READ | PROT_WRITE | PROT_EXEC,
-                        MAP_PRIVATE | MAP_ANON, -1, 0);
-
-    if (result == addr) {
-      LOGI("Allocate bcc context. addr=%p\n", result);
-      ContextSlotTaken[i] = true;
-      return static_cast<char *>(result);
-    }
-
-    if (result && result != MAP_FAILED) {
-      LOGE("Unable to allocate. suggested=%p, result=%p\n", addr, result);
-      munmap(result, BCC_CONTEXT_SIZE);
-    }
-
-    LOGE("Unable to allocate. addr=%p.  Retry ...\n", addr);
+    // Release mContextSlotOccupiedLock
   }
 
   // No slot available, allocate at arbitary address.
-
-  void *result = mmap(0, BCC_CONTEXT_SIZE,
-                      PROT_READ | PROT_WRITE | PROT_EXEC,
+  void *result = mmap(0, ContextSize, PROT_READ | PROT_WRITE | PROT_EXEC,
                       MAP_PRIVATE | MAP_ANON, -1, 0);
 
   if (!result || result == MAP_FAILED) {
@@ -92,18 +88,16 @@
   }
 
   LOGI("Allocate bcc context. addr=%p\n", result);
-  return (char *)result;
+  return static_cast<char *>(result);
 }
 
 
-char *allocateContext(char *addr, int imageFd, off_t imageOffset) {
-  android::AutoMutex _l(gContextLock);
-
+char *ContextManager::allocateContext(char *addr,
+                                      int imageFd, off_t imageOffset) {
   // This function should only allocate context when address is an context
   // slot address.  And the image offset is aligned to the pagesize.
 
   if (imageFd < 0) {
-    // Invalid file descriptor.
     LOGE("Invalid file descriptor for bcc context image\n");
     return NULL;
   }
@@ -121,13 +115,14 @@
     return NULL;
   }
 
-  if (ContextSlotTaken[slot]) {
+  llvm::MutexGuard Locked(mContextSlotOccupiedLock);
+  if (mContextSlotOccupied[slot]) {
     LOGW("Suggested bcc context slot has been occupied.\n");
     return NULL;
   }
 
   // LOGI("addr=%x, imageFd=%d, imageOffset=%x", addr, imageFd, imageOffset);
-  void *result = mmap(addr, BCC_CONTEXT_SIZE,
+  void *result = mmap(addr, ContextSize,
                       PROT_READ | PROT_WRITE | PROT_EXEC,
                       MAP_PRIVATE, imageFd, imageOffset);
 
@@ -138,27 +133,27 @@
 
   if (result != addr) {
     LOGE("Unable to allocate at suggested=%p, result=%p\n", addr, result);
-    munmap(result, BCC_CONTEXT_SIZE);
+    munmap(result, ContextSize);
     return NULL;
   }
 
   LOGI("Allocate bcc context. addr=%p\n", addr);
-  ContextSlotTaken[slot] = true;
+  mContextSlotOccupied[slot] = true;
   return static_cast<char *>(result);
 }
 
 
-void deallocateContext(char *addr) {
+void ContextManager::deallocateContext(char *addr) {
   if (!addr) {
     return;
   }
 
-  android::AutoMutex _l(gContextLock);
+  llvm::MutexGuard Locked(mContextSlotOccupiedLock);
 
   LOGI("Deallocate bcc context. addr=%p\n", addr);
 
   // Unmap
-  if (munmap(addr, BCC_CONTEXT_SIZE) < 0) {
+  if (munmap(addr, ContextSize) < 0) {
     LOGE("Unable to unmap. addr=%p (reason: %s)\n", addr, strerror(errno));
     return;
   }
@@ -168,8 +163,36 @@
   ssize_t slot = getSlotIndexFromAddress(addr);
   if (slot >= 0) {
     // Give the context slot back.
-    ContextSlotTaken[slot] = false;
+    mContextSlotOccupied[slot] = false;
   }
 }
 
+
+bool ContextManager::isManagingContext(char *addr) {
+  ssize_t slot = getSlotIndexFromAddress(addr);
+
+  if (slot < 0) {
+    return false;
+  }
+
+  llvm::MutexGuard Locked(mContextSlotOccupiedLock);
+  return mContextSlotOccupied[slot];
+}
+
+
+ssize_t ContextManager::getSlotIndexFromAddress(char *addr) {
+  if (addr >= ContextFixedAddr) {
+    size_t offset = (size_t)(addr - ContextFixedAddr);
+    if (offset % ContextSize == 0) {
+      size_t slot = offset / ContextSize;
+      if (slot < ContextSlotCount) {
+        return slot;
+      }
+    }
+  }
+  return -1;
+}
+
+
+
 } // namespace bcc
diff --git a/lib/bcc/ContextManager.h b/lib/bcc/ContextManager.h
index 461caff..0060012 100644
--- a/lib/bcc/ContextManager.h
+++ b/lib/bcc/ContextManager.h
@@ -17,30 +17,57 @@
 #ifndef BCC_CONTEXTMANAGER_H
 #define BCC_CONTEXTMANAGER_H
 
+#include <Config.h>
+
+#include <llvm/System/Mutex.h>
+
 #include <stddef.h>
 
-#include <unistd.h>
-
-
-#define BCC_CONTEXT_FIXED_ADDR (reinterpret_cast<char *>(0x7e000000))
-#define BCC_CONTEXT_SLOT_COUNT 8
-
-#define BCC_CONTEXT_CODE_SIZE (128 * 1024)
-#define BCC_CONTEXT_DATA_SIZE (128 * 1024)
-#define BCC_CONTEXT_SIZE (BCC_CONTEXT_CODE_SIZE + BCC_CONTEXT_DATA_SIZE)
-
 
 namespace bcc {
 
-  extern ssize_t getSlotIndexFromAddress(char *addr);
+  class ContextManager {
+  public:
+    // Starting address of context slot address space
+    static char * const ContextFixedAddr;
 
-  extern char *allocateContext();
+    // Number of the context slots
+    static size_t const ContextSlotCount = BCC_CONTEXT_SLOT_COUNT_;
 
-  extern char *allocateContext(char *addr, int imageFd, off_t imageOffset);
+    // Context size
+    static size_t const ContextCodeSize = BCC_CONTEXT_CODE_SIZE_;
+    static size_t const ContextDataSize = BCC_CONTEXT_DATA_SIZE_;
+    static size_t const ContextSize = ContextCodeSize + ContextDataSize;
 
-  extern void deallocateContext(char *addr);
+  private:
+    // Context manager singleton
+    static ContextManager TheContextManager;
+
+  private:
+    // Mutex lock for context slot occupation table
+    llvm::sys::Mutex mContextSlotOccupiedLock;
+
+    // Context slot occupation table
+    bool mContextSlotOccupied[ContextSlotCount];
+
+    ContextManager();
+
+  public:
+    static ContextManager &get() {
+      return TheContextManager;
+    }
+
+    char *allocateContext();
+    char *allocateContext(char *addr, int imageFd, off_t imageOffset);
+    void deallocateContext(char *addr);
+
+    bool isManagingContext(char *addr);
+
+  private:
+    static ssize_t getSlotIndexFromAddress(char *addr);
+
+  };
 
 } // namespace bcc
 
-
 #endif // BCC_CONTEXTMANAGER_H
diff --git a/lib/bcc/Script.cpp b/lib/bcc/Script.cpp
index e8dd4a3..34fe4f5 100644
--- a/lib/bcc/Script.cpp
+++ b/lib/bcc/Script.cpp
@@ -300,10 +300,9 @@
   // Note: If the address of the context is not in the context slot, then
   // we don't have to cache it.
 
-  char *addr = getContext();
-
   if (mCachePath &&
-      !mIsContextSlotNotAvail && getSlotIndexFromAddress(addr) >= 0 &&
+      !mIsContextSlotNotAvail &&
+      ContextManager::get().isManagingContext(getContext()) &&
       !getBooleanProp("debug.bcc.nocache")) {
 
     FileHandle file;
diff --git a/lib/bcc/ScriptCached.cpp b/lib/bcc/ScriptCached.cpp
index 1003163..183e552 100644
--- a/lib/bcc/ScriptCached.cpp
+++ b/lib/bcc/ScriptCached.cpp
@@ -30,7 +30,7 @@
 ScriptCached::~ScriptCached() {
   // Deallocate the bcc script context
   if (mContext) {
-    deallocateContext(mContext);
+    ContextManager::get().deallocateContext(mContext);
   }
 
   // Deallocate string pool, exported var list, exported func list
diff --git a/lib/bcc/ScriptCompiled.cpp b/lib/bcc/ScriptCompiled.cpp
index 5fd45b6..7aa29f1 100644
--- a/lib/bcc/ScriptCompiled.cpp
+++ b/lib/bcc/ScriptCompiled.cpp
@@ -27,7 +27,7 @@
 ScriptCompiled::~ScriptCompiled() {
   // Deallocate the BCC context
   if (mContext) {
-    deallocateContext(mContext);
+    ContextManager::get().deallocateContext(mContext);
   }
 
   // Delete the emitted function information