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