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 <unistd.h>     // getpagesize
21// If you don't have execinfo.h then you need devel/libexecinfo from ports.
22#include <errno.h>
23#include <limits.h>
24#include <stdarg.h>
25#include <strings.h>    // index
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
35namespace v8 {
36namespace base {
37
38
39const char* OS::LocalTimezone(double time, TimezoneCache* cache) {
40  if (std::isnan(time)) return "";
41  time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
42  struct tm tm;
43  struct tm* t = localtime_r(&tv, &tm);
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 tm;
52  struct tm* t = localtime_r(&tv, &tm);
53  // tm_gmtoff includes any daylight savings offset, so subtract it.
54  return static_cast<double>(t->tm_gmtoff * msPerSecond -
55                             (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
56}
57
58
59void* OS::Allocate(const size_t requested,
60                   size_t* allocated,
61                   bool executable) {
62  const size_t msize = RoundUp(requested, getpagesize());
63  int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
64  void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
65
66  if (mbase == MAP_FAILED) return NULL;
67  *allocated = msize;
68  return mbase;
69}
70
71
72static unsigned StringToLong(char* buffer) {
73  return static_cast<unsigned>(strtol(buffer, NULL, 16));  // NOLINT
74}
75
76
77std::vector<OS::SharedLibraryAddress> OS::GetSharedLibraryAddresses() {
78  std::vector<SharedLibraryAddress> result;
79  static const int MAP_LENGTH = 1024;
80  int fd = open("/proc/self/maps", O_RDONLY);
81  if (fd < 0) return result;
82  while (true) {
83    char addr_buffer[11];
84    addr_buffer[0] = '0';
85    addr_buffer[1] = 'x';
86    addr_buffer[10] = 0;
87    ssize_t bytes_read = read(fd, addr_buffer + 2, 8);
88    if (bytes_read < 8) break;
89    unsigned start = StringToLong(addr_buffer);
90    bytes_read = read(fd, addr_buffer + 2, 1);
91    if (bytes_read < 1) break;
92    if (addr_buffer[2] != '-') break;
93    bytes_read = read(fd, addr_buffer + 2, 8);
94    if (bytes_read < 8) break;
95    unsigned end = StringToLong(addr_buffer);
96    char buffer[MAP_LENGTH];
97    bytes_read = -1;
98    do {
99      bytes_read++;
100      if (bytes_read >= MAP_LENGTH - 1)
101        break;
102      bytes_read = read(fd, buffer + bytes_read, 1);
103      if (bytes_read < 1) break;
104    } while (buffer[bytes_read] != '\n');
105    buffer[bytes_read] = 0;
106    // Ignore mappings that are not executable.
107    if (buffer[3] != 'x') continue;
108    char* start_of_path = index(buffer, '/');
109    // There may be no filename in this line.  Skip to next.
110    if (start_of_path == NULL) continue;
111    buffer[bytes_read] = 0;
112    result.push_back(SharedLibraryAddress(start_of_path, start, end));
113  }
114  close(fd);
115  return result;
116}
117
118
119void OS::SignalCodeMovingGC() {
120}
121
122
123
124// Constants used for mmap.
125static const int kMmapFd = -1;
126static const int kMmapFdOffset = 0;
127
128
129VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
130
131
132VirtualMemory::VirtualMemory(size_t size)
133    : address_(ReserveRegion(size)), size_(size) { }
134
135
136VirtualMemory::VirtualMemory(size_t size, size_t alignment)
137    : address_(NULL), size_(0) {
138  DCHECK((alignment % OS::AllocateAlignment()) == 0);
139  size_t request_size = RoundUp(size + alignment,
140                                static_cast<intptr_t>(OS::AllocateAlignment()));
141  void* reservation = mmap(OS::GetRandomMmapAddr(),
142                           request_size,
143                           PROT_NONE,
144                           MAP_PRIVATE | MAP_ANON,
145                           kMmapFd,
146                           kMmapFdOffset);
147  if (reservation == MAP_FAILED) return;
148
149  uint8_t* base = static_cast<uint8_t*>(reservation);
150  uint8_t* aligned_base = RoundUp(base, alignment);
151  DCHECK_LE(base, aligned_base);
152
153  // Unmap extra memory reserved before and after the desired block.
154  if (aligned_base != base) {
155    size_t prefix_size = static_cast<size_t>(aligned_base - base);
156    OS::Free(base, prefix_size);
157    request_size -= prefix_size;
158  }
159
160  size_t aligned_size = RoundUp(size, OS::AllocateAlignment());
161  DCHECK_LE(aligned_size, request_size);
162
163  if (aligned_size != request_size) {
164    size_t suffix_size = request_size - aligned_size;
165    OS::Free(aligned_base + aligned_size, suffix_size);
166    request_size -= suffix_size;
167  }
168
169  DCHECK(aligned_size == request_size);
170
171  address_ = static_cast<void*>(aligned_base);
172  size_ = aligned_size;
173}
174
175
176VirtualMemory::~VirtualMemory() {
177  if (IsReserved()) {
178    bool result = ReleaseRegion(address(), size());
179    DCHECK(result);
180    USE(result);
181  }
182}
183
184
185bool VirtualMemory::IsReserved() {
186  return address_ != NULL;
187}
188
189
190void VirtualMemory::Reset() {
191  address_ = NULL;
192  size_ = 0;
193}
194
195
196bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
197  return CommitRegion(address, size, is_executable);
198}
199
200
201bool VirtualMemory::Uncommit(void* address, size_t size) {
202  return UncommitRegion(address, size);
203}
204
205
206bool VirtualMemory::Guard(void* address) {
207  OS::Guard(address, OS::CommitPageSize());
208  return true;
209}
210
211
212void* VirtualMemory::ReserveRegion(size_t size) {
213  void* result = mmap(OS::GetRandomMmapAddr(),
214                      size,
215                      PROT_NONE,
216                      MAP_PRIVATE | MAP_ANON,
217                      kMmapFd,
218                      kMmapFdOffset);
219
220  if (result == MAP_FAILED) return NULL;
221
222  return result;
223}
224
225
226bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
227  int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
228  if (MAP_FAILED == mmap(base,
229                         size,
230                         prot,
231                         MAP_PRIVATE | MAP_ANON | MAP_FIXED,
232                         kMmapFd,
233                         kMmapFdOffset)) {
234    return false;
235  }
236  return true;
237}
238
239
240bool VirtualMemory::UncommitRegion(void* base, size_t size) {
241  return mmap(base,
242              size,
243              PROT_NONE,
244              MAP_PRIVATE | MAP_ANON | MAP_FIXED,
245              kMmapFd,
246              kMmapFdOffset) != MAP_FAILED;
247}
248
249bool VirtualMemory::ReleasePartialRegion(void* base, size_t size,
250                                         void* free_start, size_t free_size) {
251  return munmap(free_start, free_size) == 0;
252}
253
254bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
255  return munmap(base, size) == 0;
256}
257
258
259bool VirtualMemory::HasLazyCommits() {
260  // TODO(alph): implement for the platform.
261  return false;
262}
263
264}  // namespace base
265}  // namespace v8
266