platform-aix.cc 6.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Platform specific code for AIX goes here. For the POSIX comaptible parts
// the implementation is in platform-posix.cc.

#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/ucontext.h>

#include <errno.h>
#include <fcntl.h>  // open
#include <limits.h>
#include <stdarg.h>
#include <strings.h>    // index
#include <sys/mman.h>   // mmap & munmap
#include <sys/stat.h>   // open
#include <sys/types.h>  // mmap & munmap
#include <unistd.h>     // getpagesize

#include <cmath>

#undef MAP_TYPE

#include "src/base/macros.h"
32
#include "src/base/platform/platform-posix.h"
33 34 35 36 37 38
#include "src/base/platform/platform.h"

namespace v8 {
namespace base {


39 40 41 42 43 44 45 46 47 48 49 50 51 52
int64_t get_gmt_offset(const tm& localtm) {
  // replacement for tm->tm_gmtoff field in glibc
  // returns seconds east of UTC, taking DST into account
  struct timeval tv;
  struct timezone tz;
  int ret_code = gettimeofday(&tv, &tz);
  // 0 = success, -1 = failure
  DCHECK_NE(ret_code, -1);
  if (ret_code == -1) {
    return 0;
  }
  return (-tz.tz_minuteswest * 60) + (localtm.tm_isdst > 0 ? 3600 : 0);
}

53 54 55
class AIXTimezoneCache : public PosixTimezoneCache {
  const char* LocalTimezone(double time) override;

56
  double LocalTimeOffset(double time_ms, bool is_utc) override;
57

58 59 60
  ~AIXTimezoneCache() override {}
};

61 62 63
const char* AIXTimezoneCache::LocalTimezone(double time_ms) {
  if (std::isnan(time_ms)) return "";
  time_t tv = static_cast<time_t>(floor(time_ms / msPerSecond));
64 65
  struct tm tm;
  struct tm* t = localtime_r(&tv, &tm);
66
  if (nullptr == t) return "";
67 68 69
  return tzname[0];  // The location of the timezone string on AIX.
}

70
double AIXTimezoneCache::LocalTimeOffset(double time_ms, bool is_utc) {
71 72
  // On AIX, struct tm does not contain a tm_gmtoff field, use get_gmt_offset
  // helper function
73
  time_t utc = time(nullptr);
74
  DCHECK_NE(utc, -1);
75 76
  struct tm tm;
  struct tm* loc = localtime_r(&utc, &tm);
77
  DCHECK_NOT_NULL(loc);
78 79
  return static_cast<double>(get_gmt_offset(*loc) * msPerSecond -
                             (loc->tm_isdst > 0 ? 3600 * msPerSecond : 0));
80 81
}

82
TimezoneCache* OS::CreateTimezoneCache() { return new AIXTimezoneCache(); }
83

84
static unsigned StringToLong(char* buffer) {
85
  return static_cast<unsigned>(strtol(buffer, nullptr, 16));
86
}
87

88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
std::vector<OS::SharedLibraryAddress> OS::GetSharedLibraryAddresses() {
  std::vector<SharedLibraryAddress> result;
  static const int MAP_LENGTH = 1024;
  int fd = open("/proc/self/maps", O_RDONLY);
  if (fd < 0) return result;
  while (true) {
    char addr_buffer[11];
    addr_buffer[0] = '0';
    addr_buffer[1] = 'x';
    addr_buffer[10] = 0;
    ssize_t rc = read(fd, addr_buffer + 2, 8);
    if (rc < 8) break;
    unsigned start = StringToLong(addr_buffer);
    rc = read(fd, addr_buffer + 2, 1);
    if (rc < 1) break;
    if (addr_buffer[2] != '-') break;
    rc = read(fd, addr_buffer + 2, 8);
    if (rc < 8) break;
    unsigned end = StringToLong(addr_buffer);
    char buffer[MAP_LENGTH];
    int bytes_read = -1;
    do {
      bytes_read++;
      if (bytes_read >= MAP_LENGTH - 1) break;
      rc = read(fd, buffer + bytes_read, 1);
      if (rc < 1) break;
    } while (buffer[bytes_read] != '\n');
    buffer[bytes_read] = 0;
    // Ignore mappings that are not executable.
    if (buffer[3] != 'x') continue;
    char* start_of_path = index(buffer, '/');
    // There may be no filename in this line.  Skip to next.
120
    if (start_of_path == nullptr) continue;
121 122 123 124 125
    buffer[bytes_read] = 0;
    result.push_back(SharedLibraryAddress(start_of_path, start, end));
  }
  close(fd);
  return result;
126 127
}

128
void OS::SignalCodeMovingGC() {}
129

130 131
void OS::AdjustSchedulingParams() {}

132 133 134 135 136 137
std::vector<OS::MemoryRange> OS::GetFreeMemoryRangesWithin(
    OS::Address boundary_start, OS::Address boundary_end, size_t minimum_size,
    size_t alignment) {
  return {};
}

138
// static
139
Stack::StackSlot Stack::GetStackStart() {
140 141 142
  // pthread_getthrds_np creates 3 values:
  // __pi_stackaddr, __pi_stacksize, __pi_stackend

143
  // higher address ----- __pi_stackend, stack base
144 145 146 147 148 149
  //
  //   |
  //   |  __pi_stacksize, stack grows downwards
  //   |
  //   V
  //
150
  // lower address -----  __pi_stackaddr, current sp
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166

  pthread_t tid = pthread_self();
  struct __pthrdsinfo buf;
  // clear buf
  memset(&buf, 0, sizeof(buf));
  char regbuf[1];
  int regbufsize = sizeof(regbuf);
  const int rc = pthread_getthrds_np(&tid, PTHRDSINFO_QUERY_ALL, &buf,
                                     sizeof(buf), regbuf, &regbufsize);
  CHECK(!rc);
  if (buf.__pi_stackend == NULL || buf.__pi_stackaddr == NULL) {
    return nullptr;
  }
  return reinterpret_cast<void*>(buf.__pi_stackend);
}

167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
// static
bool OS::DecommitPages(void* address, size_t size) {
  // The difference between this implementation and the alternative under
  // platform-posix.cc is that on AIX, calling mmap on a pre-designated address
  // with MAP_FIXED will fail and return -1 unless the application has requested
  // SPEC1170 compliant behaviour:
  // https://www.ibm.com/docs/en/aix/7.3?topic=m-mmap-mmap64-subroutine
  // Therefore in case if failure we need to unmap the address before trying to
  // map it again. The downside is another thread could place another mapping at
  // the same address after the munmap but before the mmap, therefore a CHECK is
  // also added to assure the address is mapped successfully. Refer to the
  // comments under https://crrev.com/c/3010195 for more details.
#define MMAP() \
  mmap(address, size, PROT_NONE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)
  DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % CommitPageSize());
  DCHECK_EQ(0, size % CommitPageSize());
  void* ptr;
  // Try without mapping first.
  ptr = MMAP();
  if (ptr != address) {
    DCHECK_EQ(ptr, MAP_FAILED);
    // Returns 0 when successful.
    if (munmap(address, size)) {
      return false;
    }
    // Try again after unmap.
    ptr = MMAP();
    // If this check fails it's most likely due to a racing condition where
    // another thread has mapped the same address right before we do.
    // Since this could cause hard-to-debug issues, potentially with security
    // impact, and we can't recover from this, the best we can do is abort the
    // process.
    CHECK_EQ(ptr, address);
  }
#undef MMAP
  return true;
}

205 206
}  // namespace base
}  // namespace v8