1 // Copyright 2014 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 AIX goes here. For the POSIX comaptible parts 6 // the implementation is in platform-posix.cc. 7 8 #include <pthread.h> 9 #include <semaphore.h> 10 #include <signal.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <sys/resource.h> 14 #include <sys/time.h> 15 #include <sys/ucontext.h> 16 17 #include <errno.h> 18 #include <fcntl.h> // open 19 #include <limits.h> 20 #include <stdarg.h> 21 #include <strings.h> // index 22 #include <sys/mman.h> // mmap & munmap 23 #include <sys/stat.h> // open 24 #include <sys/types.h> // mmap & munmap 25 #include <unistd.h> // getpagesize 26 27 #include <cmath> 28 29 #undef MAP_TYPE 30 31 #include "src/base/macros.h" 32 #include "src/base/platform/platform.h" 33 34 35 namespace v8 { 36 namespace base { 37 38 39 static inline void* mmapHelper(size_t len, int prot, int flags, int fildes, 40 off_t off) { 41 void* addr = OS::GetRandomMmapAddr(); 42 return mmap(addr, len, prot, flags, fildes, off); 43 } 44 45 46 const char* OS::LocalTimezone(double time, TimezoneCache* cache) { 47 if (std::isnan(time)) return ""; 48 time_t tv = static_cast<time_t>(floor(time / msPerSecond)); 49 struct tm* t = localtime(&tv); // NOLINT(runtime/threadsafe_fn) 50 if (NULL == t) return ""; 51 return tzname[0]; // The location of the timezone string on AIX. 52 } 53 54 55 double OS::LocalTimeOffset(TimezoneCache* cache) { 56 // On AIX, struct tm does not contain a tm_gmtoff field. 57 time_t utc = time(NULL); 58 DCHECK(utc != -1); 59 struct tm* loc = localtime(&utc); // NOLINT(runtime/threadsafe_fn) 60 DCHECK(loc != NULL); 61 return static_cast<double>((mktime(loc) - utc) * msPerSecond); 62 } 63 64 65 void* OS::Allocate(const size_t requested, size_t* allocated, bool executable) { 66 const size_t msize = RoundUp(requested, getpagesize()); 67 int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0); 68 void* mbase = mmapHelper(msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 69 70 if (mbase == MAP_FAILED) return NULL; 71 *allocated = msize; 72 return mbase; 73 } 74 75 76 static unsigned StringToLong(char* buffer) { 77 return static_cast<unsigned>(strtol(buffer, NULL, 16)); // NOLINT 78 } 79 80 81 std::vector<OS::SharedLibraryAddress> OS::GetSharedLibraryAddresses() { 82 std::vector<SharedLibraryAddress> result; 83 static const int MAP_LENGTH = 1024; 84 int fd = open("/proc/self/maps", O_RDONLY); 85 if (fd < 0) return result; 86 while (true) { 87 char addr_buffer[11]; 88 addr_buffer[0] = '0'; 89 addr_buffer[1] = 'x'; 90 addr_buffer[10] = 0; 91 ssize_t rc = read(fd, addr_buffer + 2, 8); 92 if (rc < 8) break; 93 unsigned start = StringToLong(addr_buffer); 94 rc = read(fd, addr_buffer + 2, 1); 95 if (rc < 1) break; 96 if (addr_buffer[2] != '-') break; 97 rc = read(fd, addr_buffer + 2, 8); 98 if (rc < 8) break; 99 unsigned end = StringToLong(addr_buffer); 100 char buffer[MAP_LENGTH]; 101 int bytes_read = -1; 102 do { 103 bytes_read++; 104 if (bytes_read >= MAP_LENGTH - 1) break; 105 rc = read(fd, buffer + bytes_read, 1); 106 if (rc < 1) break; 107 } while (buffer[bytes_read] != '\n'); 108 buffer[bytes_read] = 0; 109 // Ignore mappings that are not executable. 110 if (buffer[3] != 'x') continue; 111 char* start_of_path = index(buffer, '/'); 112 // There may be no filename in this line. Skip to next. 113 if (start_of_path == NULL) continue; 114 buffer[bytes_read] = 0; 115 result.push_back(SharedLibraryAddress(start_of_path, start, end)); 116 } 117 close(fd); 118 return result; 119 } 120 121 122 void OS::SignalCodeMovingGC() {} 123 124 125 // Constants used for mmap. 126 static const int kMmapFd = -1; 127 static const int kMmapFdOffset = 0; 128 129 VirtualMemory::VirtualMemory() : address_(NULL), size_(0) {} 130 131 132 VirtualMemory::VirtualMemory(size_t size) 133 : address_(ReserveRegion(size)), size_(size) {} 134 135 136 VirtualMemory::VirtualMemory(size_t size, size_t alignment) 137 : address_(NULL), size_(0) { 138 DCHECK((alignment % OS::AllocateAlignment()) == 0); 139 size_t request_size = 140 RoundUp(size + alignment, static_cast<intptr_t>(OS::AllocateAlignment())); 141 void* reservation = 142 mmapHelper(request_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, kMmapFd, 143 kMmapFdOffset); 144 if (reservation == MAP_FAILED) return; 145 146 uint8_t* base = static_cast<uint8_t*>(reservation); 147 uint8_t* aligned_base = RoundUp(base, alignment); 148 DCHECK_LE(base, aligned_base); 149 150 // Unmap extra memory reserved before and after the desired block. 151 if (aligned_base != base) { 152 size_t prefix_size = static_cast<size_t>(aligned_base - base); 153 OS::Free(base, prefix_size); 154 request_size -= prefix_size; 155 } 156 157 size_t aligned_size = RoundUp(size, OS::AllocateAlignment()); 158 DCHECK_LE(aligned_size, request_size); 159 160 if (aligned_size != request_size) { 161 size_t suffix_size = request_size - aligned_size; 162 OS::Free(aligned_base + aligned_size, suffix_size); 163 request_size -= suffix_size; 164 } 165 166 DCHECK(aligned_size == request_size); 167 168 address_ = static_cast<void*>(aligned_base); 169 size_ = aligned_size; 170 } 171 172 173 VirtualMemory::~VirtualMemory() { 174 if (IsReserved()) { 175 bool result = ReleaseRegion(address(), size()); 176 DCHECK(result); 177 USE(result); 178 } 179 } 180 181 182 bool VirtualMemory::IsReserved() { return address_ != NULL; } 183 184 185 void VirtualMemory::Reset() { 186 address_ = NULL; 187 size_ = 0; 188 } 189 190 191 bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) { 192 return CommitRegion(address, size, is_executable); 193 } 194 195 196 bool VirtualMemory::Uncommit(void* address, size_t size) { 197 return UncommitRegion(address, size); 198 } 199 200 201 bool VirtualMemory::Guard(void* address) { 202 OS::Guard(address, OS::CommitPageSize()); 203 return true; 204 } 205 206 207 void* VirtualMemory::ReserveRegion(size_t size) { 208 void* result = mmapHelper(size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 209 kMmapFd, kMmapFdOffset); 210 211 if (result == MAP_FAILED) return NULL; 212 213 return result; 214 } 215 216 217 bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) { 218 #if defined(__native_client__) 219 // The Native Client port of V8 uses an interpreter, 220 // so code pages don't need PROT_EXEC. 221 int prot = PROT_READ | PROT_WRITE; 222 #else 223 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0); 224 #endif 225 if (mprotect(base, size, prot) == -1) return false; 226 227 return true; 228 } 229 230 231 bool VirtualMemory::UncommitRegion(void* base, size_t size) { 232 return mprotect(base, size, PROT_NONE) != -1; 233 } 234 235 236 bool VirtualMemory::ReleaseRegion(void* base, size_t size) { 237 return munmap(base, size) == 0; 238 } 239 240 241 bool VirtualMemory::HasLazyCommits() { return true; } 242 } // namespace base 243 } // namespace v8 244