• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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 AIX goes here. For the POSIX comaptible parts
6 // the implementation is in platform-posix.cc.
7 
8 #include <pthread.h>
9 #include <semaphore.h>
10 #include <signal.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <sys/resource.h>
14 #include <sys/time.h>
15 #include <sys/ucontext.h>
16 
17 #include <errno.h>
18 #include <fcntl.h>  // open
19 #include <limits.h>
20 #include <stdarg.h>
21 #include <strings.h>    // index
22 #include <sys/mman.h>   // mmap & munmap
23 #include <sys/stat.h>   // open
24 #include <sys/types.h>  // mmap & munmap
25 #include <unistd.h>     // getpagesize
26 
27 #include <cmath>
28 
29 #undef MAP_TYPE
30 
31 #include "src/base/macros.h"
32 #include "src/base/platform/platform-posix.h"
33 #include "src/base/platform/platform.h"
34 
35 namespace v8 {
36 namespace base {
37 
38 
get_gmt_offset(const tm & localtm)39 int64_t get_gmt_offset(const tm& localtm) {
40   // replacement for tm->tm_gmtoff field in glibc
41   // returns seconds east of UTC, taking DST into account
42   struct timeval tv;
43   struct timezone tz;
44   int ret_code = gettimeofday(&tv, &tz);
45   // 0 = success, -1 = failure
46   DCHECK_NE(ret_code, -1);
47   if (ret_code == -1) {
48     return 0;
49   }
50   return (-tz.tz_minuteswest * 60) + (localtm.tm_isdst > 0 ? 3600 : 0);
51 }
52 
53 class AIXTimezoneCache : public PosixTimezoneCache {
54   const char* LocalTimezone(double time) override;
55 
56   double LocalTimeOffset(double time_ms, bool is_utc) override;
57 
~AIXTimezoneCache()58   ~AIXTimezoneCache() override {}
59 };
60 
LocalTimezone(double time_ms)61 const char* AIXTimezoneCache::LocalTimezone(double time_ms) {
62   if (std::isnan(time_ms)) return "";
63   time_t tv = static_cast<time_t>(floor(time_ms / msPerSecond));
64   struct tm tm;
65   struct tm* t = localtime_r(&tv, &tm);
66   if (nullptr == t) return "";
67   return tzname[0];  // The location of the timezone string on AIX.
68 }
69 
LocalTimeOffset(double time_ms,bool is_utc)70 double AIXTimezoneCache::LocalTimeOffset(double time_ms, bool is_utc) {
71   // On AIX, struct tm does not contain a tm_gmtoff field, use get_gmt_offset
72   // helper function
73   time_t utc = time(nullptr);
74   DCHECK_NE(utc, -1);
75   struct tm tm;
76   struct tm* loc = localtime_r(&utc, &tm);
77   DCHECK_NOT_NULL(loc);
78   return static_cast<double>(get_gmt_offset(*loc) * msPerSecond -
79                              (loc->tm_isdst > 0 ? 3600 * msPerSecond : 0));
80 }
81 
CreateTimezoneCache()82 TimezoneCache* OS::CreateTimezoneCache() { return new AIXTimezoneCache(); }
83 
StringToLong(char * buffer)84 static unsigned StringToLong(char* buffer) {
85   return static_cast<unsigned>(strtol(buffer, nullptr, 16));
86 }
87 
GetSharedLibraryAddresses()88 std::vector<OS::SharedLibraryAddress> OS::GetSharedLibraryAddresses() {
89   std::vector<SharedLibraryAddress> result;
90   static const int MAP_LENGTH = 1024;
91   int fd = open("/proc/self/maps", O_RDONLY);
92   if (fd < 0) return result;
93   while (true) {
94     char addr_buffer[11];
95     addr_buffer[0] = '0';
96     addr_buffer[1] = 'x';
97     addr_buffer[10] = 0;
98     ssize_t rc = read(fd, addr_buffer + 2, 8);
99     if (rc < 8) break;
100     unsigned start = StringToLong(addr_buffer);
101     rc = read(fd, addr_buffer + 2, 1);
102     if (rc < 1) break;
103     if (addr_buffer[2] != '-') break;
104     rc = read(fd, addr_buffer + 2, 8);
105     if (rc < 8) break;
106     unsigned end = StringToLong(addr_buffer);
107     char buffer[MAP_LENGTH];
108     int bytes_read = -1;
109     do {
110       bytes_read++;
111       if (bytes_read >= MAP_LENGTH - 1) break;
112       rc = read(fd, buffer + bytes_read, 1);
113       if (rc < 1) break;
114     } while (buffer[bytes_read] != '\n');
115     buffer[bytes_read] = 0;
116     // Ignore mappings that are not executable.
117     if (buffer[3] != 'x') continue;
118     char* start_of_path = index(buffer, '/');
119     // There may be no filename in this line.  Skip to next.
120     if (start_of_path == nullptr) continue;
121     buffer[bytes_read] = 0;
122     result.push_back(SharedLibraryAddress(start_of_path, start, end));
123   }
124   close(fd);
125   return result;
126 }
127 
SignalCodeMovingGC()128 void OS::SignalCodeMovingGC() {}
129 
AdjustSchedulingParams()130 void OS::AdjustSchedulingParams() {}
131 
GetFreeMemoryRangesWithin(OS::Address boundary_start,OS::Address boundary_end,size_t minimum_size,size_t alignment)132 std::vector<OS::MemoryRange> OS::GetFreeMemoryRangesWithin(
133     OS::Address boundary_start, OS::Address boundary_end, size_t minimum_size,
134     size_t alignment) {
135   return {};
136 }
137 
138 // static
GetStackStart()139 Stack::StackSlot Stack::GetStackStart() {
140   // pthread_getthrds_np creates 3 values:
141   // __pi_stackaddr, __pi_stacksize, __pi_stackend
142 
143   // higher address ----- __pi_stackend, stack base
144   //
145   //   |
146   //   |  __pi_stacksize, stack grows downwards
147   //   |
148   //   V
149   //
150   // lower address -----  __pi_stackaddr, current sp
151 
152   pthread_t tid = pthread_self();
153   struct __pthrdsinfo buf;
154   // clear buf
155   memset(&buf, 0, sizeof(buf));
156   char regbuf[1];
157   int regbufsize = sizeof(regbuf);
158   const int rc = pthread_getthrds_np(&tid, PTHRDSINFO_QUERY_ALL, &buf,
159                                      sizeof(buf), regbuf, &regbufsize);
160   CHECK(!rc);
161   if (buf.__pi_stackend == NULL || buf.__pi_stackaddr == NULL) {
162     return nullptr;
163   }
164   return reinterpret_cast<void*>(buf.__pi_stackend);
165 }
166 
167 // static
DecommitPages(void * address,size_t size)168 bool OS::DecommitPages(void* address, size_t size) {
169   // The difference between this implementation and the alternative under
170   // platform-posix.cc is that on AIX, calling mmap on a pre-designated address
171   // with MAP_FIXED will fail and return -1 unless the application has requested
172   // SPEC1170 compliant behaviour:
173   // https://www.ibm.com/docs/en/aix/7.3?topic=m-mmap-mmap64-subroutine
174   // Therefore in case if failure we need to unmap the address before trying to
175   // map it again. The downside is another thread could place another mapping at
176   // the same address after the munmap but before the mmap, therefore a CHECK is
177   // also added to assure the address is mapped successfully. Refer to the
178   // comments under https://crrev.com/c/3010195 for more details.
179 #define MMAP() \
180   mmap(address, size, PROT_NONE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)
181   DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % CommitPageSize());
182   DCHECK_EQ(0, size % CommitPageSize());
183   void* ptr;
184   // Try without mapping first.
185   ptr = MMAP();
186   if (ptr != address) {
187     DCHECK_EQ(ptr, MAP_FAILED);
188     // Returns 0 when successful.
189     if (munmap(address, size)) {
190       return false;
191     }
192     // Try again after unmap.
193     ptr = MMAP();
194     // If this check fails it's most likely due to a racing condition where
195     // another thread has mapped the same address right before we do.
196     // Since this could cause hard-to-debug issues, potentially with security
197     // impact, and we can't recover from this, the best we can do is abort the
198     // process.
199     CHECK_EQ(ptr, address);
200   }
201 #undef MMAP
202   return true;
203 }
204 
205 }  // namespace base
206 }  // namespace v8
207