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 FreeBSD goes here. For the POSIX-compatible 6// 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/time.h> 14#include <sys/types.h> 15#include <sys/ucontext.h> 16 17#include <sys/fcntl.h> // open 18#include <sys/mman.h> // mmap & munmap 19#include <sys/stat.h> // open 20#include <sys/types.h> // mmap & munmap 21#include <unistd.h> // getpagesize 22// If you don't have execinfo.h then you need devel/libexecinfo from ports. 23#include <errno.h> 24#include <limits.h> 25#include <stdarg.h> 26#include <strings.h> // index 27 28#include <cmath> 29 30#undef MAP_TYPE 31 32#include "src/base/macros.h" 33#include "src/base/platform/platform.h" 34 35 36namespace v8 { 37namespace base { 38 39 40const char* OS::LocalTimezone(double time, TimezoneCache* cache) { 41 if (std::isnan(time)) return ""; 42 time_t tv = static_cast<time_t>(std::floor(time/msPerSecond)); 43 struct tm* t = localtime(&tv); 44 if (NULL == t) return ""; 45 return t->tm_zone; 46} 47 48 49double OS::LocalTimeOffset(TimezoneCache* cache) { 50 time_t tv = time(NULL); 51 struct tm* t = localtime(&tv); 52 // tm_gmtoff includes any daylight savings offset, so subtract it. 53 return static_cast<double>(t->tm_gmtoff * msPerSecond - 54 (t->tm_isdst > 0 ? 3600 * msPerSecond : 0)); 55} 56 57 58void* OS::Allocate(const size_t requested, 59 size_t* allocated, 60 bool executable) { 61 const size_t msize = RoundUp(requested, getpagesize()); 62 int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0); 63 void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0); 64 65 if (mbase == MAP_FAILED) return NULL; 66 *allocated = msize; 67 return mbase; 68} 69 70 71class PosixMemoryMappedFile : public OS::MemoryMappedFile { 72 public: 73 PosixMemoryMappedFile(FILE* file, void* memory, int size) 74 : file_(file), memory_(memory), size_(size) { } 75 virtual ~PosixMemoryMappedFile(); 76 virtual void* memory() { return memory_; } 77 virtual int size() { return size_; } 78 private: 79 FILE* file_; 80 void* memory_; 81 int size_; 82}; 83 84 85OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) { 86 FILE* file = fopen(name, "r+"); 87 if (file == NULL) return NULL; 88 89 fseek(file, 0, SEEK_END); 90 int size = ftell(file); 91 92 void* memory = 93 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0); 94 return new PosixMemoryMappedFile(file, memory, size); 95} 96 97 98OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size, 99 void* initial) { 100 FILE* file = fopen(name, "w+"); 101 if (file == NULL) return NULL; 102 int result = fwrite(initial, size, 1, file); 103 if (result < 1) { 104 fclose(file); 105 return NULL; 106 } 107 void* memory = 108 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0); 109 return new PosixMemoryMappedFile(file, memory, size); 110} 111 112 113PosixMemoryMappedFile::~PosixMemoryMappedFile() { 114 if (memory_) munmap(memory_, size_); 115 fclose(file_); 116} 117 118 119static unsigned StringToLong(char* buffer) { 120 return static_cast<unsigned>(strtol(buffer, NULL, 16)); // NOLINT 121} 122 123 124std::vector<OS::SharedLibraryAddress> OS::GetSharedLibraryAddresses() { 125 std::vector<SharedLibraryAddress> result; 126 static const int MAP_LENGTH = 1024; 127 int fd = open("/proc/self/maps", O_RDONLY); 128 if (fd < 0) return result; 129 while (true) { 130 char addr_buffer[11]; 131 addr_buffer[0] = '0'; 132 addr_buffer[1] = 'x'; 133 addr_buffer[10] = 0; 134 ssize_t bytes_read = read(fd, addr_buffer + 2, 8); 135 if (bytes_read < 8) break; 136 unsigned start = StringToLong(addr_buffer); 137 bytes_read = read(fd, addr_buffer + 2, 1); 138 if (bytes_read < 1) break; 139 if (addr_buffer[2] != '-') break; 140 bytes_read = read(fd, addr_buffer + 2, 8); 141 if (bytes_read < 8) break; 142 unsigned end = StringToLong(addr_buffer); 143 char buffer[MAP_LENGTH]; 144 int bytes_read = -1; 145 do { 146 bytes_read++; 147 if (bytes_read >= MAP_LENGTH - 1) 148 break; 149 bytes_read = read(fd, buffer + bytes_read, 1); 150 if (bytes_read < 1) break; 151 } while (buffer[bytes_read] != '\n'); 152 buffer[bytes_read] = 0; 153 // Ignore mappings that are not executable. 154 if (buffer[3] != 'x') continue; 155 char* start_of_path = index(buffer, '/'); 156 // There may be no filename in this line. Skip to next. 157 if (start_of_path == NULL) continue; 158 buffer[bytes_read] = 0; 159 result.push_back(SharedLibraryAddress(start_of_path, start, end)); 160 } 161 close(fd); 162 return result; 163} 164 165 166void OS::SignalCodeMovingGC() { 167} 168 169 170 171// Constants used for mmap. 172static const int kMmapFd = -1; 173static const int kMmapFdOffset = 0; 174 175 176VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { } 177 178 179VirtualMemory::VirtualMemory(size_t size) 180 : address_(ReserveRegion(size)), size_(size) { } 181 182 183VirtualMemory::VirtualMemory(size_t size, size_t alignment) 184 : address_(NULL), size_(0) { 185 DCHECK((alignment % OS::AllocateAlignment()) == 0); 186 size_t request_size = RoundUp(size + alignment, 187 static_cast<intptr_t>(OS::AllocateAlignment())); 188 void* reservation = mmap(OS::GetRandomMmapAddr(), 189 request_size, 190 PROT_NONE, 191 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, 192 kMmapFd, 193 kMmapFdOffset); 194 if (reservation == MAP_FAILED) return; 195 196 uint8_t* base = static_cast<uint8_t*>(reservation); 197 uint8_t* aligned_base = RoundUp(base, alignment); 198 DCHECK_LE(base, aligned_base); 199 200 // Unmap extra memory reserved before and after the desired block. 201 if (aligned_base != base) { 202 size_t prefix_size = static_cast<size_t>(aligned_base - base); 203 OS::Free(base, prefix_size); 204 request_size -= prefix_size; 205 } 206 207 size_t aligned_size = RoundUp(size, OS::AllocateAlignment()); 208 DCHECK_LE(aligned_size, request_size); 209 210 if (aligned_size != request_size) { 211 size_t suffix_size = request_size - aligned_size; 212 OS::Free(aligned_base + aligned_size, suffix_size); 213 request_size -= suffix_size; 214 } 215 216 DCHECK(aligned_size == request_size); 217 218 address_ = static_cast<void*>(aligned_base); 219 size_ = aligned_size; 220} 221 222 223VirtualMemory::~VirtualMemory() { 224 if (IsReserved()) { 225 bool result = ReleaseRegion(address(), size()); 226 DCHECK(result); 227 USE(result); 228 } 229} 230 231 232bool VirtualMemory::IsReserved() { 233 return address_ != NULL; 234} 235 236 237void VirtualMemory::Reset() { 238 address_ = NULL; 239 size_ = 0; 240} 241 242 243bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) { 244 return CommitRegion(address, size, is_executable); 245} 246 247 248bool VirtualMemory::Uncommit(void* address, size_t size) { 249 return UncommitRegion(address, size); 250} 251 252 253bool VirtualMemory::Guard(void* address) { 254 OS::Guard(address, OS::CommitPageSize()); 255 return true; 256} 257 258 259void* VirtualMemory::ReserveRegion(size_t size) { 260 void* result = mmap(OS::GetRandomMmapAddr(), 261 size, 262 PROT_NONE, 263 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, 264 kMmapFd, 265 kMmapFdOffset); 266 267 if (result == MAP_FAILED) return NULL; 268 269 return result; 270} 271 272 273bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) { 274 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0); 275 if (MAP_FAILED == mmap(base, 276 size, 277 prot, 278 MAP_PRIVATE | MAP_ANON | MAP_FIXED, 279 kMmapFd, 280 kMmapFdOffset)) { 281 return false; 282 } 283 return true; 284} 285 286 287bool VirtualMemory::UncommitRegion(void* base, size_t size) { 288 return mmap(base, 289 size, 290 PROT_NONE, 291 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | MAP_FIXED, 292 kMmapFd, 293 kMmapFdOffset) != MAP_FAILED; 294} 295 296 297bool VirtualMemory::ReleaseRegion(void* base, size_t size) { 298 return munmap(base, size) == 0; 299} 300 301 302bool VirtualMemory::HasLazyCommits() { 303 // TODO(alph): implement for the platform. 304 return false; 305} 306 307} } // namespace v8::base 308