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
ContextManager()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
allocateContext()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
allocateContext(char * addr,int imageFd,off_t imageOffset)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
deallocateContext(char * addr)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
isManagingContext(char * addr) const170 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
getSlotIndexFromAddress(char * addr)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