• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 Cygwin goes here. For the POSIX-compatible
6 // parts, the implementation is in platform-posix.cc.
7 
8 #include <errno.h>
9 #include <pthread.h>
10 #include <semaphore.h>
11 #include <stdarg.h>
12 #include <strings.h>    // index
13 #include <sys/mman.h>   // mmap & munmap
14 #include <sys/time.h>
15 #include <unistd.h>     // sysconf
16 
17 #include <cmath>
18 
19 #undef MAP_TYPE
20 
21 #include "src/base/macros.h"
22 #include "src/base/platform/platform.h"
23 #include "src/base/win32-headers.h"
24 
25 namespace v8 {
26 namespace base {
27 
28 
LocalTimezone(double time,TimezoneCache * cache)29 const char* OS::LocalTimezone(double time, TimezoneCache* cache) {
30   if (std::isnan(time)) return "";
31   time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
32   struct tm tm;
33   struct tm* t = localtime_r(&tv, &tm);
34   if (NULL == t) return "";
35   return tzname[0];  // The location of the timezone string on Cygwin.
36 }
37 
38 
LocalTimeOffset(TimezoneCache * cache)39 double OS::LocalTimeOffset(TimezoneCache* cache) {
40   // On Cygwin, struct tm does not contain a tm_gmtoff field.
41   time_t utc = time(NULL);
42   DCHECK(utc != -1);
43   struct tm tm;
44   struct tm* loc = localtime_r(&utc, &tm);
45   DCHECK(loc != NULL);
46   // time - localtime includes any daylight savings offset, so subtract it.
47   return static_cast<double>((mktime(loc) - utc) * msPerSecond -
48                              (loc->tm_isdst > 0 ? 3600 * msPerSecond : 0));
49 }
50 
51 
Allocate(const size_t requested,size_t * allocated,bool is_executable)52 void* OS::Allocate(const size_t requested,
53                    size_t* allocated,
54                    bool is_executable) {
55   const size_t msize = RoundUp(requested, sysconf(_SC_PAGESIZE));
56   int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
57   void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
58   if (mbase == MAP_FAILED) return NULL;
59   *allocated = msize;
60   return mbase;
61 }
62 
63 
GetSharedLibraryAddresses()64 std::vector<OS::SharedLibraryAddress> OS::GetSharedLibraryAddresses() {
65   std::vector<SharedLibraryAddresses> result;
66   // This function assumes that the layout of the file is as follows:
67   // hex_start_addr-hex_end_addr rwxp <unused data> [binary_file_name]
68   // If we encounter an unexpected situation we abort scanning further entries.
69   FILE* fp = fopen("/proc/self/maps", "r");
70   if (fp == NULL) return result;
71 
72   // Allocate enough room to be able to store a full file name.
73   const int kLibNameLen = FILENAME_MAX + 1;
74   char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen));
75 
76   // This loop will terminate once the scanning hits an EOF.
77   while (true) {
78     uintptr_t start, end;
79     char attr_r, attr_w, attr_x, attr_p;
80     // Parse the addresses and permission bits at the beginning of the line.
81     if (fscanf(fp, "%" V8PRIxPTR "-%" V8PRIxPTR, &start, &end) != 2) break;
82     if (fscanf(fp, " %c%c%c%c", &attr_r, &attr_w, &attr_x, &attr_p) != 4) break;
83 
84     int c;
85     if (attr_r == 'r' && attr_w != 'w' && attr_x == 'x') {
86       // Found a read-only executable entry. Skip characters until we reach
87       // the beginning of the filename or the end of the line.
88       do {
89         c = getc(fp);
90       } while ((c != EOF) && (c != '\n') && (c != '/'));
91       if (c == EOF) break;  // EOF: Was unexpected, just exit.
92 
93       // Process the filename if found.
94       if (c == '/') {
95         ungetc(c, fp);  // Push the '/' back into the stream to be read below.
96 
97         // Read to the end of the line. Exit if the read fails.
98         if (fgets(lib_name, kLibNameLen, fp) == NULL) break;
99 
100         // Drop the newline character read by fgets. We do not need to check
101         // for a zero-length string because we know that we at least read the
102         // '/' character.
103         lib_name[strlen(lib_name) - 1] = '\0';
104       } else {
105         // No library name found, just record the raw address range.
106         snprintf(lib_name, kLibNameLen,
107                  "%08" V8PRIxPTR "-%08" V8PRIxPTR, start, end);
108       }
109       result.push_back(SharedLibraryAddress(lib_name, start, end));
110     } else {
111       // Entry not describing executable data. Skip to end of line to set up
112       // reading the next entry.
113       do {
114         c = getc(fp);
115       } while ((c != EOF) && (c != '\n'));
116       if (c == EOF) break;
117     }
118   }
119   free(lib_name);
120   fclose(fp);
121   return result;
122 }
123 
124 
SignalCodeMovingGC()125 void OS::SignalCodeMovingGC() {
126   // Nothing to do on Cygwin.
127 }
128 
129 
130 // The VirtualMemory implementation is taken from platform-win32.cc.
131 // The mmap-based virtual memory implementation as it is used on most posix
132 // platforms does not work well because Cygwin does not support MAP_FIXED.
133 // This causes VirtualMemory::Commit to not always commit the memory region
134 // specified.
135 
RandomizedVirtualAlloc(size_t size,int action,int protection)136 static void* RandomizedVirtualAlloc(size_t size, int action, int protection) {
137   LPVOID base = NULL;
138 
139   if (protection == PAGE_EXECUTE_READWRITE || protection == PAGE_NOACCESS) {
140     // For exectutable pages try and randomize the allocation address
141     for (size_t attempts = 0; base == NULL && attempts < 3; ++attempts) {
142       base = VirtualAlloc(OS::GetRandomMmapAddr(), size, action, protection);
143     }
144   }
145 
146   // After three attempts give up and let the OS find an address to use.
147   if (base == NULL) base = VirtualAlloc(NULL, size, action, protection);
148 
149   return base;
150 }
151 
152 
VirtualMemory()153 VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
154 
155 
VirtualMemory(size_t size)156 VirtualMemory::VirtualMemory(size_t size)
157     : address_(ReserveRegion(size)), size_(size) { }
158 
159 
VirtualMemory(size_t size,size_t alignment)160 VirtualMemory::VirtualMemory(size_t size, size_t alignment)
161     : address_(NULL), size_(0) {
162   DCHECK((alignment % OS::AllocateAlignment()) == 0);
163   size_t request_size = RoundUp(size + alignment,
164                                 static_cast<intptr_t>(OS::AllocateAlignment()));
165   void* address = ReserveRegion(request_size);
166   if (address == NULL) return;
167   uint8_t* base = RoundUp(static_cast<uint8_t*>(address), alignment);
168   // Try reducing the size by freeing and then reallocating a specific area.
169   bool result = ReleaseRegion(address, request_size);
170   USE(result);
171   DCHECK(result);
172   address = VirtualAlloc(base, size, MEM_RESERVE, PAGE_NOACCESS);
173   if (address != NULL) {
174     request_size = size;
175     DCHECK(base == static_cast<uint8_t*>(address));
176   } else {
177     // Resizing failed, just go with a bigger area.
178     address = ReserveRegion(request_size);
179     if (address == NULL) return;
180   }
181   address_ = address;
182   size_ = request_size;
183 }
184 
185 
~VirtualMemory()186 VirtualMemory::~VirtualMemory() {
187   if (IsReserved()) {
188     bool result = ReleaseRegion(address_, size_);
189     DCHECK(result);
190     USE(result);
191   }
192 }
193 
194 
IsReserved()195 bool VirtualMemory::IsReserved() {
196   return address_ != NULL;
197 }
198 
199 
Reset()200 void VirtualMemory::Reset() {
201   address_ = NULL;
202   size_ = 0;
203 }
204 
205 
Commit(void * address,size_t size,bool is_executable)206 bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
207   return CommitRegion(address, size, is_executable);
208 }
209 
210 
Uncommit(void * address,size_t size)211 bool VirtualMemory::Uncommit(void* address, size_t size) {
212   DCHECK(IsReserved());
213   return UncommitRegion(address, size);
214 }
215 
216 
ReserveRegion(size_t size)217 void* VirtualMemory::ReserveRegion(size_t size) {
218   return RandomizedVirtualAlloc(size, MEM_RESERVE, PAGE_NOACCESS);
219 }
220 
221 
CommitRegion(void * base,size_t size,bool is_executable)222 bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
223   int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
224   if (NULL == VirtualAlloc(base, size, MEM_COMMIT, prot)) {
225     return false;
226   }
227   return true;
228 }
229 
230 
Guard(void * address)231 bool VirtualMemory::Guard(void* address) {
232   if (NULL == VirtualAlloc(address,
233                            OS::CommitPageSize(),
234                            MEM_COMMIT,
235                            PAGE_NOACCESS)) {
236     return false;
237   }
238   return true;
239 }
240 
241 
UncommitRegion(void * base,size_t size)242 bool VirtualMemory::UncommitRegion(void* base, size_t size) {
243   return VirtualFree(base, size, MEM_DECOMMIT) != 0;
244 }
245 
246 
ReleaseRegion(void * base,size_t size)247 bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
248   return VirtualFree(base, 0, MEM_RELEASE) != 0;
249 }
250 
251 
HasLazyCommits()252 bool VirtualMemory::HasLazyCommits() {
253   // TODO(alph): implement for the platform.
254   return false;
255 }
256 
257 }  // namespace base
258 }  // namespace v8
259