Home | History | Annotate | Download | only in src
      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 <sys/time.h>
     12 #include <sys/resource.h>
     13 #include <sys/types.h>
     14 #include <sys/ucontext.h>
     15 #include <stdlib.h>
     16 
     17 #include <sys/types.h>  // mmap & munmap
     18 #include <sys/mman.h>   // mmap & munmap
     19 #include <sys/stat.h>   // open
     20 #include <sys/fcntl.h>  // open
     21 #include <unistd.h>     // getpagesize
     22 // If you don't have execinfo.h then you need devel/libexecinfo from ports.
     23 #include <strings.h>    // index
     24 #include <errno.h>
     25 #include <stdarg.h>
     26 #include <limits.h>
     27 
     28 #undef MAP_TYPE
     29 
     30 #include "src/v8.h"
     31 
     32 #include "src/platform.h"
     33 
     34 
     35 namespace v8 {
     36 namespace internal {
     37 
     38 
     39 const 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* t = localtime(&tv);
     43   if (NULL == t) return "";
     44   return t->tm_zone;
     45 }
     46 
     47 
     48 double OS::LocalTimeOffset(TimezoneCache* cache) {
     49   time_t tv = time(NULL);
     50   struct tm* t = localtime(&tv);
     51   // tm_gmtoff includes any daylight savings offset, so subtract it.
     52   return static_cast<double>(t->tm_gmtoff * msPerSecond -
     53                              (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
     54 }
     55 
     56 
     57 void* OS::Allocate(const size_t requested,
     58                    size_t* allocated,
     59                    bool executable) {
     60   const size_t msize = RoundUp(requested, getpagesize());
     61   int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
     62   void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
     63 
     64   if (mbase == MAP_FAILED) return NULL;
     65   *allocated = msize;
     66   return mbase;
     67 }
     68 
     69 
     70 class PosixMemoryMappedFile : public OS::MemoryMappedFile {
     71  public:
     72   PosixMemoryMappedFile(FILE* file, void* memory, int size)
     73     : file_(file), memory_(memory), size_(size) { }
     74   virtual ~PosixMemoryMappedFile();
     75   virtual void* memory() { return memory_; }
     76   virtual int size() { return size_; }
     77  private:
     78   FILE* file_;
     79   void* memory_;
     80   int size_;
     81 };
     82 
     83 
     84 OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
     85   FILE* file = fopen(name, "r+");
     86   if (file == NULL) return NULL;
     87 
     88   fseek(file, 0, SEEK_END);
     89   int size = ftell(file);
     90 
     91   void* memory =
     92       mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
     93   return new PosixMemoryMappedFile(file, memory, size);
     94 }
     95 
     96 
     97 OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
     98     void* initial) {
     99   FILE* file = fopen(name, "w+");
    100   if (file == NULL) return NULL;
    101   int result = fwrite(initial, size, 1, file);
    102   if (result < 1) {
    103     fclose(file);
    104     return NULL;
    105   }
    106   void* memory =
    107       mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
    108   return new PosixMemoryMappedFile(file, memory, size);
    109 }
    110 
    111 
    112 PosixMemoryMappedFile::~PosixMemoryMappedFile() {
    113   if (memory_) munmap(memory_, size_);
    114   fclose(file_);
    115 }
    116 
    117 
    118 static unsigned StringToLong(char* buffer) {
    119   return static_cast<unsigned>(strtol(buffer, NULL, 16));  // NOLINT
    120 }
    121 
    122 
    123 std::vector<OS::SharedLibraryAddress> OS::GetSharedLibraryAddresses() {
    124   std::vector<SharedLibraryAddress> result;
    125   static const int MAP_LENGTH = 1024;
    126   int fd = open("/proc/self/maps", O_RDONLY);
    127   if (fd < 0) return result;
    128   while (true) {
    129     char addr_buffer[11];
    130     addr_buffer[0] = '0';
    131     addr_buffer[1] = 'x';
    132     addr_buffer[10] = 0;
    133     int result = read(fd, addr_buffer + 2, 8);
    134     if (result < 8) break;
    135     unsigned start = StringToLong(addr_buffer);
    136     result = read(fd, addr_buffer + 2, 1);
    137     if (result < 1) break;
    138     if (addr_buffer[2] != '-') break;
    139     result = read(fd, addr_buffer + 2, 8);
    140     if (result < 8) break;
    141     unsigned end = StringToLong(addr_buffer);
    142     char buffer[MAP_LENGTH];
    143     int bytes_read = -1;
    144     do {
    145       bytes_read++;
    146       if (bytes_read >= MAP_LENGTH - 1)
    147         break;
    148       result = read(fd, buffer + bytes_read, 1);
    149       if (result < 1) break;
    150     } while (buffer[bytes_read] != '\n');
    151     buffer[bytes_read] = 0;
    152     // Ignore mappings that are not executable.
    153     if (buffer[3] != 'x') continue;
    154     char* start_of_path = index(buffer, '/');
    155     // There may be no filename in this line.  Skip to next.
    156     if (start_of_path == NULL) continue;
    157     buffer[bytes_read] = 0;
    158     result.push_back(SharedLibraryAddress(start_of_path, start, end));
    159   }
    160   close(fd);
    161   return result;
    162 }
    163 
    164 
    165 void OS::SignalCodeMovingGC() {
    166 }
    167 
    168 
    169 
    170 // Constants used for mmap.
    171 static const int kMmapFd = -1;
    172 static const int kMmapFdOffset = 0;
    173 
    174 
    175 VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
    176 
    177 
    178 VirtualMemory::VirtualMemory(size_t size)
    179     : address_(ReserveRegion(size)), size_(size) { }
    180 
    181 
    182 VirtualMemory::VirtualMemory(size_t size, size_t alignment)
    183     : address_(NULL), size_(0) {
    184   ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
    185   size_t request_size = RoundUp(size + alignment,
    186                                 static_cast<intptr_t>(OS::AllocateAlignment()));
    187   void* reservation = mmap(OS::GetRandomMmapAddr(),
    188                            request_size,
    189                            PROT_NONE,
    190                            MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
    191                            kMmapFd,
    192                            kMmapFdOffset);
    193   if (reservation == MAP_FAILED) return;
    194 
    195   Address base = static_cast<Address>(reservation);
    196   Address aligned_base = RoundUp(base, alignment);
    197   ASSERT_LE(base, aligned_base);
    198 
    199   // Unmap extra memory reserved before and after the desired block.
    200   if (aligned_base != base) {
    201     size_t prefix_size = static_cast<size_t>(aligned_base - base);
    202     OS::Free(base, prefix_size);
    203     request_size -= prefix_size;
    204   }
    205 
    206   size_t aligned_size = RoundUp(size, OS::AllocateAlignment());
    207   ASSERT_LE(aligned_size, request_size);
    208 
    209   if (aligned_size != request_size) {
    210     size_t suffix_size = request_size - aligned_size;
    211     OS::Free(aligned_base + aligned_size, suffix_size);
    212     request_size -= suffix_size;
    213   }
    214 
    215   ASSERT(aligned_size == request_size);
    216 
    217   address_ = static_cast<void*>(aligned_base);
    218   size_ = aligned_size;
    219 }
    220 
    221 
    222 VirtualMemory::~VirtualMemory() {
    223   if (IsReserved()) {
    224     bool result = ReleaseRegion(address(), size());
    225     ASSERT(result);
    226     USE(result);
    227   }
    228 }
    229 
    230 
    231 bool VirtualMemory::IsReserved() {
    232   return address_ != NULL;
    233 }
    234 
    235 
    236 void VirtualMemory::Reset() {
    237   address_ = NULL;
    238   size_ = 0;
    239 }
    240 
    241 
    242 bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
    243   return CommitRegion(address, size, is_executable);
    244 }
    245 
    246 
    247 bool VirtualMemory::Uncommit(void* address, size_t size) {
    248   return UncommitRegion(address, size);
    249 }
    250 
    251 
    252 bool VirtualMemory::Guard(void* address) {
    253   OS::Guard(address, OS::CommitPageSize());
    254   return true;
    255 }
    256 
    257 
    258 void* VirtualMemory::ReserveRegion(size_t size) {
    259   void* result = mmap(OS::GetRandomMmapAddr(),
    260                       size,
    261                       PROT_NONE,
    262                       MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
    263                       kMmapFd,
    264                       kMmapFdOffset);
    265 
    266   if (result == MAP_FAILED) return NULL;
    267 
    268   return result;
    269 }
    270 
    271 
    272 bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
    273   int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
    274   if (MAP_FAILED == mmap(base,
    275                          size,
    276                          prot,
    277                          MAP_PRIVATE | MAP_ANON | MAP_FIXED,
    278                          kMmapFd,
    279                          kMmapFdOffset)) {
    280     return false;
    281   }
    282   return true;
    283 }
    284 
    285 
    286 bool VirtualMemory::UncommitRegion(void* base, size_t size) {
    287   return mmap(base,
    288               size,
    289               PROT_NONE,
    290               MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | MAP_FIXED,
    291               kMmapFd,
    292               kMmapFdOffset) != MAP_FAILED;
    293 }
    294 
    295 
    296 bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
    297   return munmap(base, size) == 0;
    298 }
    299 
    300 
    301 bool VirtualMemory::HasLazyCommits() {
    302   // TODO(alph): implement for the platform.
    303   return false;
    304 }
    305 
    306 } }  // namespace v8::internal
    307