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