OLD | NEW |
| (Empty) |
1 // Copyright 2012 the V8 project authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 // Platform-specific code for OpenBSD and NetBSD goes here. For the | |
6 // POSIX-compatible parts, the implementation is in platform-posix.cc. | |
7 | |
8 #include <pthread.h> | |
9 #include <semaphore.h> | |
10 #include <signal.h> | |
11 #include <stdlib.h> | |
12 #include <sys/resource.h> | |
13 #include <sys/syscall.h> | |
14 #include <sys/time.h> | |
15 #include <sys/types.h> | |
16 | |
17 #include <errno.h> | |
18 #include <fcntl.h> // open | |
19 #include <stdarg.h> | |
20 #include <strings.h> // index | |
21 #include <sys/mman.h> // mmap & munmap | |
22 #include <sys/stat.h> // open | |
23 #include <sys/types.h> // mmap & munmap | |
24 #include <unistd.h> // sysconf | |
25 | |
26 #include <cmath> | |
27 | |
28 #undef MAP_TYPE | |
29 | |
30 #include "src/platform.h" | |
31 #include "src/utils.h" | |
32 | |
33 | |
34 namespace v8 { | |
35 namespace internal { | |
36 | |
37 | |
38 const char* OS::LocalTimezone(double time, TimezoneCache* cache) { | |
39 if (std::isnan(time)) return ""; | |
40 time_t tv = static_cast<time_t>(std::floor(time/msPerSecond)); | |
41 struct tm* t = localtime(&tv); | |
42 if (NULL == t) return ""; | |
43 return t->tm_zone; | |
44 } | |
45 | |
46 | |
47 double OS::LocalTimeOffset(TimezoneCache* cache) { | |
48 time_t tv = time(NULL); | |
49 struct tm* t = localtime(&tv); | |
50 // tm_gmtoff includes any daylight savings offset, so subtract it. | |
51 return static_cast<double>(t->tm_gmtoff * msPerSecond - | |
52 (t->tm_isdst > 0 ? 3600 * msPerSecond : 0)); | |
53 } | |
54 | |
55 | |
56 void* OS::Allocate(const size_t requested, | |
57 size_t* allocated, | |
58 bool is_executable) { | |
59 const size_t msize = RoundUp(requested, AllocateAlignment()); | |
60 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0); | |
61 void* addr = OS::GetRandomMmapAddr(); | |
62 void* mbase = mmap(addr, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0); | |
63 if (mbase == MAP_FAILED) return NULL; | |
64 *allocated = msize; | |
65 return mbase; | |
66 } | |
67 | |
68 | |
69 class PosixMemoryMappedFile : public OS::MemoryMappedFile { | |
70 public: | |
71 PosixMemoryMappedFile(FILE* file, void* memory, int size) | |
72 : file_(file), memory_(memory), size_(size) { } | |
73 virtual ~PosixMemoryMappedFile(); | |
74 virtual void* memory() { return memory_; } | |
75 virtual int size() { return size_; } | |
76 private: | |
77 FILE* file_; | |
78 void* memory_; | |
79 int size_; | |
80 }; | |
81 | |
82 | |
83 OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) { | |
84 FILE* file = fopen(name, "r+"); | |
85 if (file == NULL) return NULL; | |
86 | |
87 fseek(file, 0, SEEK_END); | |
88 int size = ftell(file); | |
89 | |
90 void* memory = | |
91 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0); | |
92 return new PosixMemoryMappedFile(file, memory, size); | |
93 } | |
94 | |
95 | |
96 OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size, | |
97 void* initial) { | |
98 FILE* file = fopen(name, "w+"); | |
99 if (file == NULL) return NULL; | |
100 int result = fwrite(initial, size, 1, file); | |
101 if (result < 1) { | |
102 fclose(file); | |
103 return NULL; | |
104 } | |
105 void* memory = | |
106 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0); | |
107 return new PosixMemoryMappedFile(file, memory, size); | |
108 } | |
109 | |
110 | |
111 PosixMemoryMappedFile::~PosixMemoryMappedFile() { | |
112 if (memory_) OS::Free(memory_, size_); | |
113 fclose(file_); | |
114 } | |
115 | |
116 | |
117 std::vector<OS::SharedLibraryAddress> OS::GetSharedLibraryAddresses() { | |
118 std::vector<SharedLibraryAddress> result; | |
119 // This function assumes that the layout of the file is as follows: | |
120 // hex_start_addr-hex_end_addr rwxp <unused data> [binary_file_name] | |
121 // If we encounter an unexpected situation we abort scanning further entries. | |
122 FILE* fp = fopen("/proc/self/maps", "r"); | |
123 if (fp == NULL) return result; | |
124 | |
125 // Allocate enough room to be able to store a full file name. | |
126 const int kLibNameLen = FILENAME_MAX + 1; | |
127 char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen)); | |
128 | |
129 // This loop will terminate once the scanning hits an EOF. | |
130 while (true) { | |
131 uintptr_t start, end; | |
132 char attr_r, attr_w, attr_x, attr_p; | |
133 // Parse the addresses and permission bits at the beginning of the line. | |
134 if (fscanf(fp, "%" V8PRIxPTR "-%" V8PRIxPTR, &start, &end) != 2) break; | |
135 if (fscanf(fp, " %c%c%c%c", &attr_r, &attr_w, &attr_x, &attr_p) != 4) break; | |
136 | |
137 int c; | |
138 if (attr_r == 'r' && attr_w != 'w' && attr_x == 'x') { | |
139 // Found a read-only executable entry. Skip characters until we reach | |
140 // the beginning of the filename or the end of the line. | |
141 do { | |
142 c = getc(fp); | |
143 } while ((c != EOF) && (c != '\n') && (c != '/')); | |
144 if (c == EOF) break; // EOF: Was unexpected, just exit. | |
145 | |
146 // Process the filename if found. | |
147 if (c == '/') { | |
148 ungetc(c, fp); // Push the '/' back into the stream to be read below. | |
149 | |
150 // Read to the end of the line. Exit if the read fails. | |
151 if (fgets(lib_name, kLibNameLen, fp) == NULL) break; | |
152 | |
153 // Drop the newline character read by fgets. We do not need to check | |
154 // for a zero-length string because we know that we at least read the | |
155 // '/' character. | |
156 lib_name[strlen(lib_name) - 1] = '\0'; | |
157 } else { | |
158 // No library name found, just record the raw address range. | |
159 snprintf(lib_name, kLibNameLen, | |
160 "%08" V8PRIxPTR "-%08" V8PRIxPTR, start, end); | |
161 } | |
162 result.push_back(SharedLibraryAddress(lib_name, start, end)); | |
163 } else { | |
164 // Entry not describing executable data. Skip to end of line to set up | |
165 // reading the next entry. | |
166 do { | |
167 c = getc(fp); | |
168 } while ((c != EOF) && (c != '\n')); | |
169 if (c == EOF) break; | |
170 } | |
171 } | |
172 free(lib_name); | |
173 fclose(fp); | |
174 return result; | |
175 } | |
176 | |
177 | |
178 void OS::SignalCodeMovingGC() { | |
179 // Support for ll_prof.py. | |
180 // | |
181 // The Linux profiler built into the kernel logs all mmap's with | |
182 // PROT_EXEC so that analysis tools can properly attribute ticks. We | |
183 // do a mmap with a name known by ll_prof.py and immediately munmap | |
184 // it. This injects a GC marker into the stream of events generated | |
185 // by the kernel and allows us to synchronize V8 code log and the | |
186 // kernel log. | |
187 int size = sysconf(_SC_PAGESIZE); | |
188 FILE* f = fopen(OS::GetGCFakeMMapFile(), "w+"); | |
189 if (f == NULL) { | |
190 OS::PrintError("Failed to open %s\n", OS::GetGCFakeMMapFile()); | |
191 OS::Abort(); | |
192 } | |
193 void* addr = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_PRIVATE, | |
194 fileno(f), 0); | |
195 ASSERT(addr != MAP_FAILED); | |
196 OS::Free(addr, size); | |
197 fclose(f); | |
198 } | |
199 | |
200 | |
201 | |
202 // Constants used for mmap. | |
203 static const int kMmapFd = -1; | |
204 static const int kMmapFdOffset = 0; | |
205 | |
206 | |
207 VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { } | |
208 | |
209 | |
210 VirtualMemory::VirtualMemory(size_t size) | |
211 : address_(ReserveRegion(size)), size_(size) { } | |
212 | |
213 | |
214 VirtualMemory::VirtualMemory(size_t size, size_t alignment) | |
215 : address_(NULL), size_(0) { | |
216 ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment()))); | |
217 size_t request_size = RoundUp(size + alignment, | |
218 static_cast<intptr_t>(OS::AllocateAlignment())); | |
219 void* reservation = mmap(OS::GetRandomMmapAddr(), | |
220 request_size, | |
221 PROT_NONE, | |
222 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, | |
223 kMmapFd, | |
224 kMmapFdOffset); | |
225 if (reservation == MAP_FAILED) return; | |
226 | |
227 uint8_t* base = static_cast<uint8_t*>(reservation); | |
228 uint8_t* aligned_base = RoundUp(base, alignment); | |
229 ASSERT_LE(base, aligned_base); | |
230 | |
231 // Unmap extra memory reserved before and after the desired block. | |
232 if (aligned_base != base) { | |
233 size_t prefix_size = static_cast<size_t>(aligned_base - base); | |
234 OS::Free(base, prefix_size); | |
235 request_size -= prefix_size; | |
236 } | |
237 | |
238 size_t aligned_size = RoundUp(size, OS::AllocateAlignment()); | |
239 ASSERT_LE(aligned_size, request_size); | |
240 | |
241 if (aligned_size != request_size) { | |
242 size_t suffix_size = request_size - aligned_size; | |
243 OS::Free(aligned_base + aligned_size, suffix_size); | |
244 request_size -= suffix_size; | |
245 } | |
246 | |
247 ASSERT(aligned_size == request_size); | |
248 | |
249 address_ = static_cast<void*>(aligned_base); | |
250 size_ = aligned_size; | |
251 } | |
252 | |
253 | |
254 VirtualMemory::~VirtualMemory() { | |
255 if (IsReserved()) { | |
256 bool result = ReleaseRegion(address(), size()); | |
257 ASSERT(result); | |
258 USE(result); | |
259 } | |
260 } | |
261 | |
262 | |
263 bool VirtualMemory::IsReserved() { | |
264 return address_ != NULL; | |
265 } | |
266 | |
267 | |
268 void VirtualMemory::Reset() { | |
269 address_ = NULL; | |
270 size_ = 0; | |
271 } | |
272 | |
273 | |
274 bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) { | |
275 return CommitRegion(address, size, is_executable); | |
276 } | |
277 | |
278 | |
279 bool VirtualMemory::Uncommit(void* address, size_t size) { | |
280 return UncommitRegion(address, size); | |
281 } | |
282 | |
283 | |
284 bool VirtualMemory::Guard(void* address) { | |
285 OS::Guard(address, OS::CommitPageSize()); | |
286 return true; | |
287 } | |
288 | |
289 | |
290 void* VirtualMemory::ReserveRegion(size_t size) { | |
291 void* result = mmap(OS::GetRandomMmapAddr(), | |
292 size, | |
293 PROT_NONE, | |
294 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, | |
295 kMmapFd, | |
296 kMmapFdOffset); | |
297 | |
298 if (result == MAP_FAILED) return NULL; | |
299 | |
300 return result; | |
301 } | |
302 | |
303 | |
304 bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) { | |
305 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0); | |
306 if (MAP_FAILED == mmap(base, | |
307 size, | |
308 prot, | |
309 MAP_PRIVATE | MAP_ANON | MAP_FIXED, | |
310 kMmapFd, | |
311 kMmapFdOffset)) { | |
312 return false; | |
313 } | |
314 return true; | |
315 } | |
316 | |
317 | |
318 bool VirtualMemory::UncommitRegion(void* base, size_t size) { | |
319 return mmap(base, | |
320 size, | |
321 PROT_NONE, | |
322 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | MAP_FIXED, | |
323 kMmapFd, | |
324 kMmapFdOffset) != MAP_FAILED; | |
325 } | |
326 | |
327 | |
328 bool VirtualMemory::ReleaseRegion(void* base, size_t size) { | |
329 return munmap(base, size) == 0; | |
330 } | |
331 | |
332 | |
333 bool VirtualMemory::HasLazyCommits() { | |
334 // TODO(alph): implement for the platform. | |
335 return false; | |
336 } | |
337 | |
338 } } // namespace v8::internal | |
OLD | NEW |