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