Line data Source code
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 POSIX goes here. This is not a platform on its
6 : // own, but contains the parts which are the same across the POSIX platforms
7 : // Linux, MacOS, FreeBSD, OpenBSD, NetBSD and QNX.
8 :
9 : #include <errno.h>
10 : #include <limits.h>
11 : #include <pthread.h>
12 : #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
13 : #include <pthread_np.h> // for pthread_set_name_np
14 : #endif
15 : #include <sched.h> // for sched_yield
16 : #include <stdio.h>
17 : #include <time.h>
18 : #include <unistd.h>
19 :
20 : #include <sys/mman.h>
21 : #include <sys/stat.h>
22 : #include <sys/time.h>
23 : #include <sys/types.h>
24 : #if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || \
25 : defined(__NetBSD__) || defined(__OpenBSD__)
26 : #include <sys/sysctl.h> // NOLINT, for sysctl
27 : #endif
28 :
29 : #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
30 : #define LOG_TAG "v8"
31 : #include <android/log.h> // NOLINT
32 : #endif
33 :
34 : #include <cmath>
35 : #include <cstdlib>
36 :
37 : #include "src/base/platform/platform-posix.h"
38 :
39 : #include "src/base/lazy-instance.h"
40 : #include "src/base/macros.h"
41 : #include "src/base/platform/platform.h"
42 : #include "src/base/platform/time.h"
43 : #include "src/base/utils/random-number-generator.h"
44 :
45 : #ifdef V8_FAST_TLS_SUPPORTED
46 : #include <atomic>
47 : #endif
48 :
49 : #if V8_OS_MACOSX
50 : #include <dlfcn.h>
51 : #endif
52 :
53 : #if V8_OS_LINUX
54 : #include <sys/prctl.h> // NOLINT, for prctl
55 : #endif
56 :
57 : #if defined(V8_OS_FUCHSIA)
58 : #include <zircon/process.h>
59 : #else
60 : #include <sys/resource.h>
61 : #endif
62 :
63 : #if !defined(_AIX) && !defined(V8_OS_FUCHSIA)
64 : #include <sys/syscall.h>
65 : #endif
66 :
67 : #if V8_OS_FREEBSD || V8_OS_MACOSX || V8_OS_OPENBSD || V8_OS_SOLARIS
68 : #define MAP_ANONYMOUS MAP_ANON
69 : #endif
70 :
71 : #if defined(V8_OS_SOLARIS)
72 : #if (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE > 2) || defined(__EXTENSIONS__)
73 : extern "C" int madvise(caddr_t, size_t, int);
74 : #else
75 : extern int madvise(caddr_t, size_t, int);
76 : #endif
77 : #endif
78 :
79 : #ifndef MADV_FREE
80 : #define MADV_FREE MADV_DONTNEED
81 : #endif
82 :
83 : namespace v8 {
84 : namespace base {
85 :
86 : namespace {
87 :
88 : // 0 is never a valid thread id.
89 : const pthread_t kNoThread = static_cast<pthread_t>(0);
90 :
91 : bool g_hard_abort = false;
92 :
93 : const char* g_gc_fake_mmap = nullptr;
94 :
95 2586624 : DEFINE_LAZY_LEAKY_OBJECT_GETTER(RandomNumberGenerator,
96 : GetPlatformRandomNumberGenerator)
97 : static LazyMutex rng_mutex = LAZY_MUTEX_INITIALIZER;
98 :
99 : #if !V8_OS_FUCHSIA
100 : #if V8_OS_MACOSX
101 : // kMmapFd is used to pass vm_alloc flags to tag the region with the user
102 : // defined tag 255 This helps identify V8-allocated regions in memory analysis
103 : // tools like vmmap(1).
104 : const int kMmapFd = VM_MAKE_TAG(255);
105 : #else // !V8_OS_MACOSX
106 : const int kMmapFd = -1;
107 : #endif // !V8_OS_MACOSX
108 :
109 : const int kMmapFdOffset = 0;
110 :
111 12030910 : int GetProtectionFromMemoryPermission(OS::MemoryPermission access) {
112 12030910 : switch (access) {
113 : case OS::MemoryPermission::kNoAccess:
114 : return PROT_NONE;
115 : case OS::MemoryPermission::kRead:
116 147516 : return PROT_READ;
117 : case OS::MemoryPermission::kReadWrite:
118 4272708 : return PROT_READ | PROT_WRITE;
119 : case OS::MemoryPermission::kReadWriteExecute:
120 1245408 : return PROT_READ | PROT_WRITE | PROT_EXEC;
121 : case OS::MemoryPermission::kReadExecute:
122 2976915 : return PROT_READ | PROT_EXEC;
123 : }
124 0 : UNREACHABLE();
125 : }
126 :
127 : int GetFlagsForMemoryPermission(OS::MemoryPermission access) {
128 : int flags = MAP_PRIVATE | MAP_ANONYMOUS;
129 2332921 : if (access == OS::MemoryPermission::kNoAccess) {
130 : #if !V8_OS_AIX && !V8_OS_FREEBSD && !V8_OS_QNX
131 : flags |= MAP_NORESERVE;
132 : #endif // !V8_OS_AIX && !V8_OS_FREEBSD && !V8_OS_QNX
133 : #if V8_OS_QNX
134 : flags |= MAP_LAZY;
135 : #endif // V8_OS_QNX
136 : }
137 : return flags;
138 : }
139 :
140 2332923 : void* Allocate(void* address, size_t size, OS::MemoryPermission access) {
141 2332923 : int prot = GetProtectionFromMemoryPermission(access);
142 : int flags = GetFlagsForMemoryPermission(access);
143 2332921 : void* result = mmap(address, size, prot, flags, kMmapFd, kMmapFdOffset);
144 2332926 : if (result == MAP_FAILED) return nullptr;
145 2332906 : return result;
146 : }
147 :
148 : #endif // !V8_OS_FUCHSIA
149 :
150 : } // namespace
151 :
152 60988 : void OS::Initialize(bool hard_abort, const char* const gc_fake_mmap) {
153 60988 : g_hard_abort = hard_abort;
154 60988 : g_gc_fake_mmap = gc_fake_mmap;
155 60988 : }
156 :
157 764980 : int OS::ActivationFrameAlignment() {
158 : #if V8_TARGET_ARCH_ARM
159 : // On EABI ARM targets this is required for fp correctness in the
160 : // runtime system.
161 : return 8;
162 : #elif V8_TARGET_ARCH_MIPS
163 : return 8;
164 : #elif V8_TARGET_ARCH_S390
165 : return 8;
166 : #else
167 : // Otherwise we just assume 16 byte alignment, i.e.:
168 : // - With gcc 4.4 the tree vectorization optimizer can generate code
169 : // that requires 16 byte alignment such as movdqa on x86.
170 : // - Mac OS X, PPC and Solaris (64-bit) activation frames must
171 : // be 16 byte-aligned; see "Mac OS X ABI Function Call Guide"
172 764980 : return 16;
173 : #endif
174 : }
175 :
176 : // static
177 61029 : size_t OS::AllocatePageSize() {
178 4843040 : return static_cast<size_t>(sysconf(_SC_PAGESIZE));
179 : }
180 :
181 : // static
182 61029 : size_t OS::CommitPageSize() {
183 61029 : static size_t page_size = getpagesize();
184 61029 : return page_size;
185 : }
186 :
187 : // static
188 59504 : void OS::SetRandomMmapSeed(int64_t seed) {
189 59504 : if (seed) {
190 : MutexGuard guard(rng_mutex.Pointer());
191 59504 : GetPlatformRandomNumberGenerator()->SetSeed(seed);
192 : }
193 59504 : }
194 :
195 : // static
196 2466121 : void* OS::GetRandomMmapAddr() {
197 : uintptr_t raw_addr;
198 : {
199 : MutexGuard guard(rng_mutex.Pointer());
200 2466136 : GetPlatformRandomNumberGenerator()->NextBytes(&raw_addr, sizeof(raw_addr));
201 : }
202 : #if defined(V8_USE_ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
203 : defined(THREAD_SANITIZER) || defined(LEAK_SANITIZER)
204 : // If random hint addresses interfere with address ranges hard coded in
205 : // sanitizers, bad things happen. This address range is copied from TSAN
206 : // source but works with all tools.
207 : // See crbug.com/539863.
208 : raw_addr &= 0x007fffff0000ULL;
209 : raw_addr += 0x7e8000000000ULL;
210 : #else
211 : #if V8_TARGET_ARCH_X64
212 : // Currently available CPUs have 48 bits of virtual addressing. Truncate
213 : // the hint address to 46 bits to give the kernel a fighting chance of
214 : // fulfilling our placement request.
215 2466136 : raw_addr &= uint64_t{0x3FFFFFFFF000};
216 : #elif V8_TARGET_ARCH_PPC64
217 : #if V8_OS_AIX
218 : // AIX: 64 bits of virtual addressing, but we limit address range to:
219 : // a) minimize Segment Lookaside Buffer (SLB) misses and
220 : raw_addr &= uint64_t{0x3FFFF000};
221 : // Use extra address space to isolate the mmap regions.
222 : raw_addr += uint64_t{0x400000000000};
223 : #elif V8_TARGET_BIG_ENDIAN
224 : // Big-endian Linux: 42 bits of virtual addressing.
225 : raw_addr &= uint64_t{0x03FFFFFFF000};
226 : #else
227 : // Little-endian Linux: 46 bits of virtual addressing.
228 : raw_addr &= uint64_t{0x3FFFFFFF0000};
229 : #endif
230 : #elif V8_TARGET_ARCH_S390X
231 : // Linux on Z uses bits 22-32 for Region Indexing, which translates to 42 bits
232 : // of virtual addressing. Truncate to 40 bits to allow kernel chance to
233 : // fulfill request.
234 : raw_addr &= uint64_t{0xFFFFFFF000};
235 : #elif V8_TARGET_ARCH_S390
236 : // 31 bits of virtual addressing. Truncate to 29 bits to allow kernel chance
237 : // to fulfill request.
238 : raw_addr &= 0x1FFFF000;
239 : #elif V8_TARGET_ARCH_MIPS64
240 : // 42 bits of virtual addressing. Truncate to 40 bits to allow kernel chance
241 : // to fulfill request.
242 : raw_addr &= uint64_t{0xFFFFFF0000};
243 : #else
244 : raw_addr &= 0x3FFFF000;
245 :
246 : #ifdef __sun
247 : // For our Solaris/illumos mmap hint, we pick a random address in the bottom
248 : // half of the top half of the address space (that is, the third quarter).
249 : // Because we do not MAP_FIXED, this will be treated only as a hint -- the
250 : // system will not fail to mmap() because something else happens to already
251 : // be mapped at our random address. We deliberately set the hint high enough
252 : // to get well above the system's break (that is, the heap); Solaris and
253 : // illumos will try the hint and if that fails allocate as if there were
254 : // no hint at all. The high hint prevents the break from getting hemmed in
255 : // at low values, ceding half of the address space to the system heap.
256 : raw_addr += 0x80000000;
257 : #elif V8_OS_AIX
258 : // The range 0x30000000 - 0xD0000000 is available on AIX;
259 : // choose the upper range.
260 : raw_addr += 0x90000000;
261 : #else
262 : // The range 0x20000000 - 0x60000000 is relatively unpopulated across a
263 : // variety of ASLR modes (PAE kernel, NX compat mode, etc) and on macos
264 : // 10.6 and 10.7.
265 : raw_addr += 0x20000000;
266 : #endif
267 : #endif
268 : #endif
269 2466136 : return reinterpret_cast<void*>(raw_addr);
270 : }
271 :
272 : // TODO(bbudge) Move Cygwin and Fuchsia stuff into platform-specific files.
273 : #if !V8_OS_CYGWIN && !V8_OS_FUCHSIA
274 : // static
275 2332926 : void* OS::Allocate(void* address, size_t size, size_t alignment,
276 : MemoryPermission access) {
277 : size_t page_size = AllocatePageSize();
278 : DCHECK_EQ(0, size % page_size);
279 : DCHECK_EQ(0, alignment % page_size);
280 : address = AlignedAddress(address, alignment);
281 : // Add the maximum misalignment so we are guaranteed an aligned base address.
282 2332923 : size_t request_size = size + (alignment - page_size);
283 : request_size = RoundUp(request_size, OS::AllocatePageSize());
284 2332924 : void* result = base::Allocate(address, request_size, access);
285 2332926 : if (result == nullptr) return nullptr;
286 :
287 : // Unmap memory allocated before the aligned base address.
288 : uint8_t* base = static_cast<uint8_t*>(result);
289 : uint8_t* aligned_base = reinterpret_cast<uint8_t*>(
290 4665812 : RoundUp(reinterpret_cast<uintptr_t>(base), alignment));
291 2332906 : if (aligned_base != base) {
292 : DCHECK_LT(base, aligned_base);
293 176606 : size_t prefix_size = static_cast<size_t>(aligned_base - base);
294 176606 : CHECK(Free(base, prefix_size));
295 176606 : request_size -= prefix_size;
296 : }
297 : // Unmap memory allocated after the potentially unaligned end.
298 2332906 : if (size != request_size) {
299 : DCHECK_LT(size, request_size);
300 853089 : size_t suffix_size = request_size - size;
301 1706178 : CHECK(Free(aligned_base + size, suffix_size));
302 : request_size -= suffix_size;
303 : }
304 :
305 : DCHECK_EQ(size, request_size);
306 : return static_cast<void*>(aligned_base);
307 : }
308 :
309 : // static
310 2332581 : bool OS::Free(void* address, const size_t size) {
311 : DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % AllocatePageSize());
312 : DCHECK_EQ(0, size % AllocatePageSize());
313 3478438 : return munmap(address, size) == 0;
314 : }
315 :
316 : // static
317 124710 : bool OS::Release(void* address, size_t size) {
318 : DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % CommitPageSize());
319 : DCHECK_EQ(0, size % CommitPageSize());
320 124710 : return munmap(address, size) == 0;
321 : }
322 :
323 : // static
324 9697992 : bool OS::SetPermissions(void* address, size_t size, MemoryPermission access) {
325 : DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % CommitPageSize());
326 : DCHECK_EQ(0, size % CommitPageSize());
327 :
328 9697992 : int prot = GetProtectionFromMemoryPermission(access);
329 9697985 : int ret = mprotect(address, size, prot);
330 9698045 : if (ret == 0 && access == OS::MemoryPermission::kNoAccess) {
331 : // This is advisory; ignore errors and continue execution.
332 1056592 : USE(DiscardSystemPages(address, size));
333 : }
334 :
335 : // For accounting purposes, we want to call MADV_FREE_REUSE on macOS after
336 : // changing permissions away from OS::MemoryPermission::kNoAccess. Since this
337 : // state is not kept at this layer, we always call this if access != kNoAccess.
338 : // The cost is a syscall that effectively no-ops.
339 : // TODO(erikchen): Fix this to only call MADV_FREE_REUSE when necessary.
340 : // https://crbug.com/823915
341 : #if defined(OS_MACOSX)
342 : if (access != OS::MemoryPermission::kNoAccess)
343 : madvise(address, size, MADV_FREE_REUSE);
344 : #endif
345 :
346 9698039 : return ret == 0;
347 : }
348 :
349 1084266 : bool OS::DiscardSystemPages(void* address, size_t size) {
350 : DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % CommitPageSize());
351 : DCHECK_EQ(0, size % CommitPageSize());
352 : #if defined(OS_MACOSX)
353 : // On OSX, MADV_FREE_REUSABLE has comparable behavior to MADV_FREE, but also
354 : // marks the pages with the reusable bit, which allows both Activity Monitor
355 : // and memory-infra to correctly track the pages.
356 : int ret = madvise(address, size, MADV_FREE_REUSABLE);
357 : #elif defined(_AIX) || defined(V8_OS_SOLARIS)
358 : int ret = madvise(reinterpret_cast<caddr_t>(address), size, MADV_FREE);
359 : #else
360 1084266 : int ret = madvise(address, size, MADV_FREE);
361 : #endif
362 1084267 : if (ret != 0 && errno == ENOSYS)
363 : return true; // madvise is not available on all systems.
364 1084254 : if (ret != 0 && errno == EINVAL) {
365 : // MADV_FREE only works on Linux 4.5+ . If request failed, retry with older
366 : // MADV_DONTNEED . Note that MADV_FREE being defined at compile time doesn't
367 : // imply runtime support.
368 : #if defined(_AIX) || defined(V8_OS_SOLARIS)
369 : ret = madvise(reinterpret_cast<caddr_t>(address), size, MADV_DONTNEED);
370 : #else
371 0 : ret = madvise(address, size, MADV_DONTNEED);
372 : #endif
373 : }
374 1084254 : return ret == 0;
375 : }
376 :
377 : // static
378 19553 : bool OS::HasLazyCommits() {
379 : #if V8_OS_AIX || V8_OS_LINUX || V8_OS_MACOSX
380 19553 : return true;
381 : #else
382 : // TODO(bbudge) Return true for all POSIX platforms.
383 : return false;
384 : #endif
385 : }
386 : #endif // !V8_OS_CYGWIN && !V8_OS_FUCHSIA
387 :
388 0 : const char* OS::GetGCFakeMMapFile() {
389 0 : return g_gc_fake_mmap;
390 : }
391 :
392 :
393 21800 : void OS::Sleep(TimeDelta interval) {
394 21800 : usleep(static_cast<useconds_t>(interval.InMicroseconds()));
395 21800 : }
396 :
397 :
398 0 : void OS::Abort() {
399 0 : if (g_hard_abort) {
400 0 : V8_IMMEDIATE_CRASH();
401 : }
402 : // Redirect to std abort to signal abnormal program termination.
403 0 : abort();
404 : }
405 :
406 :
407 0 : void OS::DebugBreak() {
408 : #if V8_HOST_ARCH_ARM
409 : asm("bkpt 0");
410 : #elif V8_HOST_ARCH_ARM64
411 : asm("brk 0");
412 : #elif V8_HOST_ARCH_MIPS
413 : asm("break");
414 : #elif V8_HOST_ARCH_MIPS64
415 : asm("break");
416 : #elif V8_HOST_ARCH_PPC
417 : asm("twge 2,2");
418 : #elif V8_HOST_ARCH_IA32
419 : asm("int $3");
420 : #elif V8_HOST_ARCH_X64
421 0 : asm("int $3");
422 : #elif V8_HOST_ARCH_S390
423 : // Software breakpoint instruction is 0x0001
424 : asm volatile(".word 0x0001");
425 : #else
426 : #error Unsupported host architecture.
427 : #endif
428 0 : }
429 :
430 :
431 : class PosixMemoryMappedFile final : public OS::MemoryMappedFile {
432 : public:
433 : PosixMemoryMappedFile(FILE* file, void* memory, size_t size)
434 116171 : : file_(file), memory_(memory), size_(size) {}
435 : ~PosixMemoryMappedFile() final;
436 116282 : void* memory() const final { return memory_; }
437 116243 : size_t size() const final { return size_; }
438 :
439 : private:
440 : FILE* const file_;
441 : void* const memory_;
442 : size_t const size_;
443 : };
444 :
445 :
446 : // static
447 116265 : OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name,
448 : FileMode mode) {
449 116265 : const char* fopen_mode = (mode == FileMode::kReadOnly) ? "r" : "r+";
450 116265 : if (FILE* file = fopen(name, fopen_mode)) {
451 116171 : if (fseek(file, 0, SEEK_END) == 0) {
452 116171 : long size = ftell(file); // NOLINT(runtime/int)
453 116180 : if (size == 0) return new PosixMemoryMappedFile(file, nullptr, 0);
454 116162 : if (size > 0) {
455 : int prot = PROT_READ;
456 : int flags = MAP_PRIVATE;
457 116162 : if (mode == FileMode::kReadWrite) {
458 : prot |= PROT_WRITE;
459 : flags = MAP_SHARED;
460 : }
461 : void* const memory =
462 116162 : mmap(OS::GetRandomMmapAddr(), size, prot, flags, fileno(file), 0);
463 116162 : if (memory != MAP_FAILED) {
464 232324 : return new PosixMemoryMappedFile(file, memory, size);
465 : }
466 : }
467 : }
468 0 : fclose(file);
469 : }
470 : return nullptr;
471 : }
472 :
473 : // static
474 0 : OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name,
475 : size_t size, void* initial) {
476 0 : if (FILE* file = fopen(name, "w+")) {
477 0 : if (size == 0) return new PosixMemoryMappedFile(file, 0, 0);
478 0 : size_t result = fwrite(initial, 1, size, file);
479 0 : if (result == size && !ferror(file)) {
480 0 : void* memory = mmap(OS::GetRandomMmapAddr(), result,
481 0 : PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
482 0 : if (memory != MAP_FAILED) {
483 0 : return new PosixMemoryMappedFile(file, memory, result);
484 : }
485 : }
486 0 : fclose(file);
487 : }
488 : return nullptr;
489 : }
490 :
491 :
492 348513 : PosixMemoryMappedFile::~PosixMemoryMappedFile() {
493 464657 : if (memory_) CHECK(OS::Free(memory_, RoundUp(size_, OS::AllocatePageSize())));
494 116171 : fclose(file_);
495 232342 : }
496 :
497 :
498 130428 : int OS::GetCurrentProcessId() {
499 130428 : return static_cast<int>(getpid());
500 : }
501 :
502 :
503 2076 : int OS::GetCurrentThreadId() {
504 : #if V8_OS_MACOSX || (V8_OS_ANDROID && defined(__APPLE__))
505 : return static_cast<int>(pthread_mach_thread_np(pthread_self()));
506 : #elif V8_OS_LINUX
507 2076 : return static_cast<int>(syscall(__NR_gettid));
508 : #elif V8_OS_ANDROID
509 : return static_cast<int>(gettid());
510 : #elif V8_OS_AIX
511 : return static_cast<int>(thread_self());
512 : #elif V8_OS_FUCHSIA
513 : return static_cast<int>(zx_thread_self());
514 : #elif V8_OS_SOLARIS
515 : return static_cast<int>(pthread_self());
516 : #else
517 : return static_cast<int>(reinterpret_cast<intptr_t>(pthread_self()));
518 : #endif
519 : }
520 :
521 0 : void OS::ExitProcess(int exit_code) {
522 : // Use _exit instead of exit to avoid races between isolate
523 : // threads and static destructors.
524 0 : fflush(stdout);
525 0 : fflush(stderr);
526 0 : _exit(exit_code);
527 : }
528 :
529 : // ----------------------------------------------------------------------------
530 : // POSIX date/time support.
531 : //
532 :
533 : #if !defined(V8_OS_FUCHSIA)
534 50 : int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) {
535 : struct rusage usage;
536 :
537 50 : if (getrusage(RUSAGE_SELF, &usage) < 0) return -1;
538 50 : *secs = static_cast<uint32_t>(usage.ru_utime.tv_sec);
539 50 : *usecs = static_cast<uint32_t>(usage.ru_utime.tv_usec);
540 50 : return 0;
541 : }
542 : #endif
543 :
544 1204179 : double OS::TimeCurrentMillis() {
545 1204179 : return Time::Now().ToJsTime();
546 : }
547 :
548 225 : double PosixTimezoneCache::DaylightSavingsOffset(double time) {
549 225 : if (std::isnan(time)) return std::numeric_limits<double>::quiet_NaN();
550 225 : time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
551 : struct tm tm;
552 225 : struct tm* t = localtime_r(&tv, &tm);
553 225 : if (nullptr == t) return std::numeric_limits<double>::quiet_NaN();
554 225 : return t->tm_isdst > 0 ? 3600 * msPerSecond : 0;
555 : }
556 :
557 :
558 15 : int OS::GetLastError() {
559 15 : return errno;
560 : }
561 :
562 :
563 : // ----------------------------------------------------------------------------
564 : // POSIX stdio support.
565 : //
566 :
567 2329 : FILE* OS::FOpen(const char* path, const char* mode) {
568 2329 : FILE* file = fopen(path, mode);
569 2329 : if (file == nullptr) return nullptr;
570 : struct stat file_stat;
571 4658 : if (fstat(fileno(file), &file_stat) != 0) {
572 0 : fclose(file);
573 0 : return nullptr;
574 : }
575 2329 : bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0);
576 2329 : if (is_regular_file) return file;
577 0 : fclose(file);
578 0 : return nullptr;
579 : }
580 :
581 :
582 0 : bool OS::Remove(const char* path) {
583 0 : return (remove(path) == 0);
584 : }
585 :
586 9 : char OS::DirectorySeparator() { return '/'; }
587 :
588 1694374 : bool OS::isDirectorySeparator(const char ch) {
589 1694374 : return ch == DirectorySeparator();
590 : }
591 :
592 :
593 59 : FILE* OS::OpenTemporaryFile() {
594 59 : return tmpfile();
595 : }
596 :
597 :
598 : const char* const OS::LogFileOpenMode = "w";
599 :
600 :
601 8047 : void OS::Print(const char* format, ...) {
602 : va_list args;
603 8047 : va_start(args, format);
604 : VPrint(format, args);
605 8047 : va_end(args);
606 8047 : }
607 :
608 :
609 142238 : void OS::VPrint(const char* format, va_list args) {
610 : #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
611 : __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args);
612 : #else
613 : vprintf(format, args);
614 : #endif
615 142238 : }
616 :
617 :
618 0 : void OS::FPrint(FILE* out, const char* format, ...) {
619 : va_list args;
620 0 : va_start(args, format);
621 : VFPrint(out, format, args);
622 0 : va_end(args);
623 0 : }
624 :
625 :
626 3490957 : void OS::VFPrint(FILE* out, const char* format, va_list args) {
627 : #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
628 : __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args);
629 : #else
630 : vfprintf(out, format, args);
631 : #endif
632 3490957 : }
633 :
634 :
635 95 : void OS::PrintError(const char* format, ...) {
636 : va_list args;
637 95 : va_start(args, format);
638 : VPrintError(format, args);
639 95 : va_end(args);
640 95 : }
641 :
642 :
643 0 : void OS::VPrintError(const char* format, va_list args) {
644 : #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
645 : __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, format, args);
646 : #else
647 95 : vfprintf(stderr, format, args);
648 : #endif
649 0 : }
650 :
651 :
652 383372 : int OS::SNPrintF(char* str, int length, const char* format, ...) {
653 : va_list args;
654 383372 : va_start(args, format);
655 383372 : int result = VSNPrintF(str, length, format, args);
656 383372 : va_end(args);
657 383372 : return result;
658 : }
659 :
660 :
661 7202229 : int OS::VSNPrintF(char* str,
662 : int length,
663 : const char* format,
664 : va_list args) {
665 7202229 : int n = vsnprintf(str, length, format, args);
666 7202229 : if (n < 0 || n >= length) {
667 : // If the length is zero, the assignment fails.
668 170835 : if (length > 0)
669 170835 : str[length - 1] = '\0';
670 : return -1;
671 : } else {
672 : return n;
673 : }
674 : }
675 :
676 :
677 : // ----------------------------------------------------------------------------
678 : // POSIX string support.
679 : //
680 :
681 0 : char* OS::StrChr(char* str, int c) {
682 0 : return strchr(str, c);
683 : }
684 :
685 :
686 26250 : void OS::StrNCpy(char* dest, int length, const char* src, size_t n) {
687 : strncpy(dest, src, n);
688 26250 : }
689 :
690 :
691 : // ----------------------------------------------------------------------------
692 : // POSIX thread support.
693 : //
694 :
695 494426 : class Thread::PlatformData {
696 : public:
697 516577 : PlatformData() : thread_(kNoThread) {}
698 : pthread_t thread_; // Thread handle for pthread.
699 : // Synchronizes thread creation
700 : Mutex thread_creation_mutex_;
701 : };
702 :
703 516577 : Thread::Thread(const Options& options)
704 : : data_(new PlatformData),
705 : stack_size_(options.stack_size()),
706 1033154 : start_semaphore_(nullptr) {
707 516577 : if (stack_size_ > 0 && static_cast<size_t>(stack_size_) < PTHREAD_STACK_MIN) {
708 0 : stack_size_ = PTHREAD_STACK_MIN;
709 : }
710 : set_name(options.name());
711 516577 : }
712 :
713 :
714 988852 : Thread::~Thread() {
715 988852 : delete data_;
716 494426 : }
717 :
718 :
719 : static void SetThreadName(const char* name) {
720 : #if V8_OS_DRAGONFLYBSD || V8_OS_FREEBSD || V8_OS_OPENBSD
721 : pthread_set_name_np(pthread_self(), name);
722 : #elif V8_OS_NETBSD
723 : STATIC_ASSERT(Thread::kMaxThreadNameLength <= PTHREAD_MAX_NAMELEN_NP);
724 : pthread_setname_np(pthread_self(), "%s", name);
725 : #elif V8_OS_MACOSX
726 : // pthread_setname_np is only available in 10.6 or later, so test
727 : // for it at runtime.
728 : int (*dynamic_pthread_setname_np)(const char*);
729 : *reinterpret_cast<void**>(&dynamic_pthread_setname_np) =
730 : dlsym(RTLD_DEFAULT, "pthread_setname_np");
731 : if (dynamic_pthread_setname_np == nullptr) return;
732 :
733 : // Mac OS X does not expose the length limit of the name, so hardcode it.
734 : static const int kMaxNameLength = 63;
735 : STATIC_ASSERT(Thread::kMaxThreadNameLength <= kMaxNameLength);
736 : dynamic_pthread_setname_np(name);
737 : #elif defined(PR_SET_NAME)
738 453546 : prctl(PR_SET_NAME,
739 : reinterpret_cast<unsigned long>(name), // NOLINT
740 453546 : 0, 0, 0);
741 : #endif
742 : }
743 :
744 :
745 452936 : static void* ThreadEntry(void* arg) {
746 : Thread* thread = reinterpret_cast<Thread*>(arg);
747 : // We take the lock here to make sure that pthread_create finished first since
748 : // we don't know which thread will run first (the original thread or the new
749 : // one).
750 452936 : { MutexGuard lock_guard(&thread->data()->thread_creation_mutex_); }
751 : SetThreadName(thread->name());
752 : DCHECK_NE(thread->data()->thread_, kNoThread);
753 453005 : thread->NotifyStartedAndRun();
754 432322 : return nullptr;
755 : }
756 :
757 :
758 0 : void Thread::set_name(const char* name) {
759 516577 : strncpy(name_, name, sizeof(name_));
760 516577 : name_[sizeof(name_) - 1] = '\0';
761 0 : }
762 :
763 :
764 454150 : void Thread::Start() {
765 : int result;
766 : pthread_attr_t attr;
767 : memset(&attr, 0, sizeof(attr));
768 454150 : result = pthread_attr_init(&attr);
769 : DCHECK_EQ(0, result);
770 454150 : size_t stack_size = stack_size_;
771 : if (stack_size == 0) {
772 : #if V8_OS_MACOSX
773 : // Default on Mac OS X is 512kB -- bump up to 1MB
774 : stack_size = 1 * 1024 * 1024;
775 : #elif V8_OS_AIX
776 : // Default on AIX is 96kB -- bump up to 2MB
777 : stack_size = 2 * 1024 * 1024;
778 : #endif
779 : }
780 454150 : if (stack_size > 0) {
781 14102 : result = pthread_attr_setstacksize(&attr, stack_size);
782 : DCHECK_EQ(0, result);
783 : }
784 : {
785 454150 : MutexGuard lock_guard(&data_->thread_creation_mutex_);
786 454150 : result = pthread_create(&data_->thread_, &attr, ThreadEntry, this);
787 : }
788 : DCHECK_EQ(0, result);
789 454150 : result = pthread_attr_destroy(&attr);
790 : DCHECK_EQ(0, result);
791 : DCHECK_NE(data_->thread_, kNoThread);
792 : USE(result);
793 454150 : }
794 :
795 436465 : void Thread::Join() { pthread_join(data_->thread_, nullptr); }
796 :
797 : static Thread::LocalStorageKey PthreadKeyToLocalKey(pthread_key_t pthread_key) {
798 : #if V8_OS_CYGWIN
799 : // We need to cast pthread_key_t to Thread::LocalStorageKey in two steps
800 : // because pthread_key_t is a pointer type on Cygwin. This will probably not
801 : // work on 64-bit platforms, but Cygwin doesn't support 64-bit anyway.
802 : STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t));
803 : intptr_t ptr_key = reinterpret_cast<intptr_t>(pthread_key);
804 : return static_cast<Thread::LocalStorageKey>(ptr_key);
805 : #else
806 181157 : return static_cast<Thread::LocalStorageKey>(pthread_key);
807 : #endif
808 : }
809 :
810 :
811 : static pthread_key_t LocalKeyToPthreadKey(Thread::LocalStorageKey local_key) {
812 : #if V8_OS_CYGWIN
813 : STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t));
814 : intptr_t ptr_key = static_cast<intptr_t>(local_key);
815 : return reinterpret_cast<pthread_key_t>(ptr_key);
816 : #else
817 3127895 : return static_cast<pthread_key_t>(local_key);
818 : #endif
819 : }
820 :
821 :
822 : #ifdef V8_FAST_TLS_SUPPORTED
823 :
824 : static std::atomic<bool> tls_base_offset_initialized{false};
825 : intptr_t kMacTlsBaseOffset = 0;
826 :
827 : // It's safe to do the initialization more that once, but it has to be
828 : // done at least once.
829 : static void InitializeTlsBaseOffset() {
830 : const size_t kBufferSize = 128;
831 : char buffer[kBufferSize];
832 : size_t buffer_size = kBufferSize;
833 : int ctl_name[] = { CTL_KERN , KERN_OSRELEASE };
834 : if (sysctl(ctl_name, 2, buffer, &buffer_size, nullptr, 0) != 0) {
835 : FATAL("V8 failed to get kernel version");
836 : }
837 : // The buffer now contains a string of the form XX.YY.ZZ, where
838 : // XX is the major kernel version component.
839 : // Make sure the buffer is 0-terminated.
840 : buffer[kBufferSize - 1] = '\0';
841 : char* period_pos = strchr(buffer, '.');
842 : *period_pos = '\0';
843 : int kernel_version_major =
844 : static_cast<int>(strtol(buffer, nullptr, 10)); // NOLINT
845 : // The constants below are taken from pthreads.s from the XNU kernel
846 : // sources archive at www.opensource.apple.com.
847 : if (kernel_version_major < 11) {
848 : // 8.x.x (Tiger), 9.x.x (Leopard), 10.x.x (Snow Leopard) have the
849 : // same offsets.
850 : #if V8_HOST_ARCH_IA32
851 : kMacTlsBaseOffset = 0x48;
852 : #else
853 : kMacTlsBaseOffset = 0x60;
854 : #endif
855 : } else {
856 : // 11.x.x (Lion) changed the offset.
857 : kMacTlsBaseOffset = 0;
858 : }
859 :
860 : tls_base_offset_initialized.store(true, std::memory_order_release);
861 : }
862 :
863 :
864 : static void CheckFastTls(Thread::LocalStorageKey key) {
865 : void* expected = reinterpret_cast<void*>(0x1234CAFE);
866 : Thread::SetThreadLocal(key, expected);
867 : void* actual = Thread::GetExistingThreadLocal(key);
868 : if (expected != actual) {
869 : FATAL("V8 failed to initialize fast TLS on current kernel");
870 : }
871 : Thread::SetThreadLocal(key, nullptr);
872 : }
873 :
874 : #endif // V8_FAST_TLS_SUPPORTED
875 :
876 :
877 181157 : Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
878 : #ifdef V8_FAST_TLS_SUPPORTED
879 : bool check_fast_tls = false;
880 : if (!tls_base_offset_initialized.load(std::memory_order_acquire)) {
881 : check_fast_tls = true;
882 : InitializeTlsBaseOffset();
883 : }
884 : #endif
885 : pthread_key_t key;
886 181157 : int result = pthread_key_create(&key, nullptr);
887 : DCHECK_EQ(0, result);
888 : USE(result);
889 181157 : LocalStorageKey local_key = PthreadKeyToLocalKey(key);
890 : #ifdef V8_FAST_TLS_SUPPORTED
891 : // If we just initialized fast TLS support, make sure it works.
892 : if (check_fast_tls) CheckFastTls(local_key);
893 : #endif
894 181157 : return local_key;
895 : }
896 :
897 :
898 32 : void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
899 : pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
900 32 : int result = pthread_key_delete(pthread_key);
901 : DCHECK_EQ(0, result);
902 : USE(result);
903 32 : }
904 :
905 :
906 1955928 : void* Thread::GetThreadLocal(LocalStorageKey key) {
907 : pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
908 1955928 : return pthread_getspecific(pthread_key);
909 : }
910 :
911 :
912 1171935 : void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
913 : pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
914 1171935 : int result = pthread_setspecific(pthread_key, value);
915 : DCHECK_EQ(0, result);
916 : USE(result);
917 1171923 : }
918 :
919 : #undef LOG_TAG
920 : #undef MAP_ANONYMOUS
921 : #undef MADV_FREE
922 :
923 : } // namespace base
924 : } // namespace v8
|