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 "src/base/atomicops.h"
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 2336621 : 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 12541272 : int GetProtectionFromMemoryPermission(OS::MemoryPermission access) {
112 12541272 : switch (access) {
113 : case OS::MemoryPermission::kNoAccess:
114 : return PROT_NONE;
115 : case OS::MemoryPermission::kRead:
116 145235 : return PROT_READ;
117 : case OS::MemoryPermission::kReadWrite:
118 4620191 : return PROT_READ | PROT_WRITE;
119 : case OS::MemoryPermission::kReadWriteExecute:
120 1244467 : return PROT_READ | PROT_WRITE | PROT_EXEC;
121 : case OS::MemoryPermission::kReadExecute:
122 3582178 : 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 2087543 : 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 2087543 : void* Allocate(void* address, size_t size, OS::MemoryPermission access) {
141 2087543 : int prot = GetProtectionFromMemoryPermission(access);
142 : int flags = GetFlagsForMemoryPermission(access);
143 2087543 : void* result = mmap(address, size, prot, flags, kMmapFd, kMmapFdOffset);
144 2087549 : if (result == MAP_FAILED) return nullptr;
145 2087529 : return result;
146 : }
147 :
148 : #endif // !V8_OS_FUCHSIA
149 :
150 : } // namespace
151 :
152 59583 : void OS::Initialize(bool hard_abort, const char* const gc_fake_mmap) {
153 59583 : g_hard_abort = hard_abort;
154 59583 : g_gc_fake_mmap = gc_fake_mmap;
155 59583 : }
156 :
157 762580 : 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 762580 : return 16;
173 : #endif
174 : }
175 :
176 : // static
177 59619 : size_t OS::AllocatePageSize() {
178 4348473 : return static_cast<size_t>(sysconf(_SC_PAGESIZE));
179 : }
180 :
181 : // static
182 59619 : size_t OS::CommitPageSize() {
183 59619 : static size_t page_size = getpagesize();
184 59619 : return page_size;
185 : }
186 :
187 : // static
188 58099 : void OS::SetRandomMmapSeed(int64_t seed) {
189 58099 : if (seed) {
190 : MutexGuard guard(rng_mutex.Pointer());
191 58099 : GetPlatformRandomNumberGenerator()->SetSeed(seed);
192 : }
193 58099 : }
194 :
195 : // static
196 2218934 : void* OS::GetRandomMmapAddr() {
197 : uintptr_t raw_addr;
198 : {
199 : MutexGuard guard(rng_mutex.Pointer());
200 2218943 : 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 2218943 : 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 2218943 : return reinterpret_cast<void*>(raw_addr);
270 : }
271 :
272 : // TODO(bbudge) Move Cygwin and Fuschia stuff into platform-specific files.
273 : #if !V8_OS_CYGWIN && !V8_OS_FUCHSIA
274 : // static
275 2087547 : 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 2087542 : size_t request_size = size + (alignment - page_size);
283 : request_size = RoundUp(request_size, OS::AllocatePageSize());
284 2087544 : void* result = base::Allocate(address, request_size, access);
285 2087549 : 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 4175058 : RoundUp(reinterpret_cast<uintptr_t>(base), alignment));
291 2087529 : if (aligned_base != base) {
292 : DCHECK_LT(base, aligned_base);
293 176893 : size_t prefix_size = static_cast<size_t>(aligned_base - base);
294 176893 : CHECK(Free(base, prefix_size));
295 176893 : request_size -= prefix_size;
296 : }
297 : // Unmap memory allocated after the potentially unaligned end.
298 2087529 : if (size != request_size) {
299 : DCHECK_LT(size, request_size);
300 611538 : size_t suffix_size = request_size - size;
301 1223076 : CHECK(Free(aligned_base + size, suffix_size));
302 : request_size -= suffix_size;
303 : }
304 :
305 : DCHECK_EQ(size, request_size);
306 2087529 : return static_cast<void*>(aligned_base);
307 : }
308 :
309 : // static
310 2087277 : 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 2989473 : return munmap(address, size) == 0;
314 : }
315 :
316 : // static
317 121932 : 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 121932 : return munmap(address, size) == 0;
321 : }
322 :
323 : // static
324 10453733 : 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 10453733 : int prot = GetProtectionFromMemoryPermission(access);
329 10453731 : int ret = mprotect(address, size, prot);
330 10453749 : if (ret == 0 && access == OS::MemoryPermission::kNoAccess) {
331 : // This is advisory; ignore errors and continue execution.
332 863791 : 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 10453749 : return ret == 0;
347 : }
348 :
349 918491 : 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 918491 : int ret = madvise(address, size, MADV_FREE);
361 : #endif
362 918489 : if (ret != 0 && errno == ENOSYS)
363 : return true; // madvise is not available on all systems.
364 918487 : 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 918487 : return ret == 0;
375 : }
376 :
377 : // static
378 13519 : bool OS::HasLazyCommits() {
379 : #if V8_OS_AIX || V8_OS_LINUX || V8_OS_MACOSX
380 13519 : 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 12917 : void OS::Sleep(TimeDelta interval) {
394 12917 : usleep(static_cast<useconds_t>(interval.InMicroseconds()));
395 12917 : }
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 113774 : : file_(file), memory_(memory), size_(size) {}
435 : ~PosixMemoryMappedFile() final;
436 113885 : void* memory() const final { return memory_; }
437 113846 : 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 113868 : OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
448 113868 : if (FILE* file = fopen(name, "r+")) {
449 113774 : if (fseek(file, 0, SEEK_END) == 0) {
450 113774 : long size = ftell(file); // NOLINT(runtime/int)
451 113783 : if (size == 0) return new PosixMemoryMappedFile(file, nullptr, 0);
452 113765 : if (size > 0) {
453 : void* const memory =
454 : mmap(OS::GetRandomMmapAddr(), size, PROT_READ | PROT_WRITE,
455 113765 : MAP_SHARED, fileno(file), 0);
456 113765 : if (memory != MAP_FAILED) {
457 227530 : return new PosixMemoryMappedFile(file, memory, size);
458 : }
459 : }
460 : }
461 0 : fclose(file);
462 : }
463 : return nullptr;
464 : }
465 :
466 :
467 : // static
468 0 : OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name,
469 : size_t size, void* initial) {
470 0 : if (FILE* file = fopen(name, "w+")) {
471 0 : if (size == 0) return new PosixMemoryMappedFile(file, 0, 0);
472 0 : size_t result = fwrite(initial, 1, size, file);
473 0 : if (result == size && !ferror(file)) {
474 : void* memory = mmap(OS::GetRandomMmapAddr(), result,
475 0 : PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
476 0 : if (memory != MAP_FAILED) {
477 0 : return new PosixMemoryMappedFile(file, memory, result);
478 : }
479 : }
480 0 : fclose(file);
481 : }
482 : return nullptr;
483 : }
484 :
485 :
486 227548 : PosixMemoryMappedFile::~PosixMemoryMappedFile() {
487 455069 : if (memory_) CHECK(OS::Free(memory_, RoundUp(size_, OS::AllocatePageSize())));
488 113774 : fclose(file_);
489 227548 : }
490 :
491 :
492 129674 : int OS::GetCurrentProcessId() {
493 129674 : return static_cast<int>(getpid());
494 : }
495 :
496 :
497 790 : int OS::GetCurrentThreadId() {
498 : #if V8_OS_MACOSX || (V8_OS_ANDROID && defined(__APPLE__))
499 : return static_cast<int>(pthread_mach_thread_np(pthread_self()));
500 : #elif V8_OS_LINUX
501 790 : return static_cast<int>(syscall(__NR_gettid));
502 : #elif V8_OS_ANDROID
503 : return static_cast<int>(gettid());
504 : #elif V8_OS_AIX
505 : return static_cast<int>(thread_self());
506 : #elif V8_OS_FUCHSIA
507 : return static_cast<int>(zx_thread_self());
508 : #elif V8_OS_SOLARIS
509 : return static_cast<int>(pthread_self());
510 : #else
511 : return static_cast<int>(reinterpret_cast<intptr_t>(pthread_self()));
512 : #endif
513 : }
514 :
515 0 : void OS::ExitProcess(int exit_code) {
516 : // Use _exit instead of exit to avoid races between isolate
517 : // threads and static destructors.
518 0 : fflush(stdout);
519 0 : fflush(stderr);
520 0 : _exit(exit_code);
521 : }
522 :
523 : // ----------------------------------------------------------------------------
524 : // POSIX date/time support.
525 : //
526 :
527 : #if !defined(V8_OS_FUCHSIA)
528 44 : int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) {
529 : struct rusage usage;
530 :
531 44 : if (getrusage(RUSAGE_SELF, &usage) < 0) return -1;
532 44 : *secs = static_cast<uint32_t>(usage.ru_utime.tv_sec);
533 44 : *usecs = static_cast<uint32_t>(usage.ru_utime.tv_usec);
534 44 : return 0;
535 : }
536 : #endif
537 :
538 165177 : double OS::TimeCurrentMillis() {
539 165177 : return Time::Now().ToJsTime();
540 : }
541 :
542 225 : double PosixTimezoneCache::DaylightSavingsOffset(double time) {
543 225 : if (std::isnan(time)) return std::numeric_limits<double>::quiet_NaN();
544 225 : time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
545 : struct tm tm;
546 225 : struct tm* t = localtime_r(&tv, &tm);
547 225 : if (nullptr == t) return std::numeric_limits<double>::quiet_NaN();
548 225 : return t->tm_isdst > 0 ? 3600 * msPerSecond : 0;
549 : }
550 :
551 :
552 15 : int OS::GetLastError() {
553 15 : return errno;
554 : }
555 :
556 :
557 : // ----------------------------------------------------------------------------
558 : // POSIX stdio support.
559 : //
560 :
561 2245 : FILE* OS::FOpen(const char* path, const char* mode) {
562 2245 : FILE* file = fopen(path, mode);
563 2245 : if (file == nullptr) return nullptr;
564 : struct stat file_stat;
565 4490 : if (fstat(fileno(file), &file_stat) != 0) {
566 0 : fclose(file);
567 0 : return nullptr;
568 : }
569 2245 : bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0);
570 2245 : if (is_regular_file) return file;
571 0 : fclose(file);
572 0 : return nullptr;
573 : }
574 :
575 :
576 0 : bool OS::Remove(const char* path) {
577 0 : return (remove(path) == 0);
578 : }
579 :
580 2 : char OS::DirectorySeparator() { return '/'; }
581 :
582 1654139 : bool OS::isDirectorySeparator(const char ch) {
583 1654139 : return ch == DirectorySeparator();
584 : }
585 :
586 :
587 60 : FILE* OS::OpenTemporaryFile() {
588 60 : return tmpfile();
589 : }
590 :
591 :
592 : const char* const OS::LogFileOpenMode = "w";
593 :
594 :
595 4693 : void OS::Print(const char* format, ...) {
596 : va_list args;
597 4693 : va_start(args, format);
598 : VPrint(format, args);
599 4693 : va_end(args);
600 4693 : }
601 :
602 :
603 141209 : void OS::VPrint(const char* format, va_list args) {
604 : #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
605 : __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args);
606 : #else
607 : vprintf(format, args);
608 : #endif
609 141209 : }
610 :
611 :
612 0 : void OS::FPrint(FILE* out, const char* format, ...) {
613 : va_list args;
614 0 : va_start(args, format);
615 : VFPrint(out, format, args);
616 0 : va_end(args);
617 0 : }
618 :
619 :
620 3490944 : void OS::VFPrint(FILE* out, const char* format, va_list args) {
621 : #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
622 : __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args);
623 : #else
624 : vfprintf(out, format, args);
625 : #endif
626 3490944 : }
627 :
628 :
629 95 : void OS::PrintError(const char* format, ...) {
630 : va_list args;
631 95 : va_start(args, format);
632 : VPrintError(format, args);
633 95 : va_end(args);
634 95 : }
635 :
636 :
637 0 : void OS::VPrintError(const char* format, va_list args) {
638 : #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
639 : __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, format, args);
640 : #else
641 95 : vfprintf(stderr, format, args);
642 : #endif
643 0 : }
644 :
645 :
646 404668 : int OS::SNPrintF(char* str, int length, const char* format, ...) {
647 : va_list args;
648 404668 : va_start(args, format);
649 404668 : int result = VSNPrintF(str, length, format, args);
650 404668 : va_end(args);
651 404668 : return result;
652 : }
653 :
654 :
655 6660593 : int OS::VSNPrintF(char* str,
656 : int length,
657 : const char* format,
658 : va_list args) {
659 6660593 : int n = vsnprintf(str, length, format, args);
660 6660593 : if (n < 0 || n >= length) {
661 : // If the length is zero, the assignment fails.
662 171905 : if (length > 0)
663 171905 : str[length - 1] = '\0';
664 : return -1;
665 : } else {
666 : return n;
667 : }
668 : }
669 :
670 :
671 : // ----------------------------------------------------------------------------
672 : // POSIX string support.
673 : //
674 :
675 0 : char* OS::StrChr(char* str, int c) {
676 0 : return strchr(str, c);
677 : }
678 :
679 :
680 25836 : void OS::StrNCpy(char* dest, int length, const char* src, size_t n) {
681 : strncpy(dest, src, n);
682 25836 : }
683 :
684 :
685 : // ----------------------------------------------------------------------------
686 : // POSIX thread support.
687 : //
688 :
689 483048 : class Thread::PlatformData {
690 : public:
691 504830 : PlatformData() : thread_(kNoThread) {}
692 : pthread_t thread_; // Thread handle for pthread.
693 : // Synchronizes thread creation
694 : Mutex thread_creation_mutex_;
695 : };
696 :
697 1514490 : Thread::Thread(const Options& options)
698 : : data_(new PlatformData),
699 : stack_size_(options.stack_size()),
700 1514490 : start_semaphore_(nullptr) {
701 504830 : if (stack_size_ > 0 && static_cast<size_t>(stack_size_) < PTHREAD_STACK_MIN) {
702 0 : stack_size_ = PTHREAD_STACK_MIN;
703 : }
704 : set_name(options.name());
705 504830 : }
706 :
707 :
708 483048 : Thread::~Thread() {
709 966096 : delete data_;
710 483048 : }
711 :
712 :
713 : static void SetThreadName(const char* name) {
714 : #if V8_OS_DRAGONFLYBSD || V8_OS_FREEBSD || V8_OS_OPENBSD
715 : pthread_set_name_np(pthread_self(), name);
716 : #elif V8_OS_NETBSD
717 : STATIC_ASSERT(Thread::kMaxThreadNameLength <= PTHREAD_MAX_NAMELEN_NP);
718 : pthread_setname_np(pthread_self(), "%s", name);
719 : #elif V8_OS_MACOSX
720 : // pthread_setname_np is only available in 10.6 or later, so test
721 : // for it at runtime.
722 : int (*dynamic_pthread_setname_np)(const char*);
723 : *reinterpret_cast<void**>(&dynamic_pthread_setname_np) =
724 : dlsym(RTLD_DEFAULT, "pthread_setname_np");
725 : if (dynamic_pthread_setname_np == nullptr) return;
726 :
727 : // Mac OS X does not expose the length limit of the name, so hardcode it.
728 : static const int kMaxNameLength = 63;
729 : STATIC_ASSERT(Thread::kMaxThreadNameLength <= kMaxNameLength);
730 : dynamic_pthread_setname_np(name);
731 : #elif defined(PR_SET_NAME)
732 : prctl(PR_SET_NAME,
733 : reinterpret_cast<unsigned long>(name), // NOLINT
734 443715 : 0, 0, 0);
735 : #endif
736 : }
737 :
738 :
739 443449 : static void* ThreadEntry(void* arg) {
740 443449 : Thread* thread = reinterpret_cast<Thread*>(arg);
741 : // We take the lock here to make sure that pthread_create finished first since
742 : // we don't know which thread will run first (the original thread or the new
743 : // one).
744 443449 : { MutexGuard lock_guard(&thread->data()->thread_creation_mutex_); }
745 443715 : SetThreadName(thread->name());
746 : DCHECK_NE(thread->data()->thread_, kNoThread);
747 443355 : thread->NotifyStartedAndRun();
748 422450 : return nullptr;
749 : }
750 :
751 :
752 0 : void Thread::set_name(const char* name) {
753 504830 : strncpy(name_, name, sizeof(name_));
754 504830 : name_[sizeof(name_) - 1] = '\0';
755 0 : }
756 :
757 :
758 443776 : void Thread::Start() {
759 : int result;
760 : pthread_attr_t attr;
761 : memset(&attr, 0, sizeof(attr));
762 443776 : result = pthread_attr_init(&attr);
763 : DCHECK_EQ(0, result);
764 443776 : size_t stack_size = stack_size_;
765 : if (stack_size == 0) {
766 : #if V8_OS_MACOSX
767 : // Default on Mac OS X is 512kB -- bump up to 1MB
768 : stack_size = 1 * 1024 * 1024;
769 : #elif V8_OS_AIX
770 : // Default on AIX is 96kB -- bump up to 2MB
771 : stack_size = 2 * 1024 * 1024;
772 : #endif
773 : }
774 443776 : if (stack_size > 0) {
775 13756 : result = pthread_attr_setstacksize(&attr, stack_size);
776 : DCHECK_EQ(0, result);
777 : }
778 : {
779 443776 : MutexGuard lock_guard(&data_->thread_creation_mutex_);
780 443776 : result = pthread_create(&data_->thread_, &attr, ThreadEntry, this);
781 : }
782 : DCHECK_EQ(0, result);
783 443776 : result = pthread_attr_destroy(&attr);
784 : DCHECK_EQ(0, result);
785 : DCHECK_NE(data_->thread_, kNoThread);
786 : USE(result);
787 443776 : }
788 :
789 426297 : void Thread::Join() { pthread_join(data_->thread_, nullptr); }
790 :
791 : static Thread::LocalStorageKey PthreadKeyToLocalKey(pthread_key_t pthread_key) {
792 : #if V8_OS_CYGWIN
793 : // We need to cast pthread_key_t to Thread::LocalStorageKey in two steps
794 : // because pthread_key_t is a pointer type on Cygwin. This will probably not
795 : // work on 64-bit platforms, but Cygwin doesn't support 64-bit anyway.
796 : STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t));
797 : intptr_t ptr_key = reinterpret_cast<intptr_t>(pthread_key);
798 : return static_cast<Thread::LocalStorageKey>(ptr_key);
799 : #else
800 176978 : return static_cast<Thread::LocalStorageKey>(pthread_key);
801 : #endif
802 : }
803 :
804 :
805 : static pthread_key_t LocalKeyToPthreadKey(Thread::LocalStorageKey local_key) {
806 : #if V8_OS_CYGWIN
807 : STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t));
808 : intptr_t ptr_key = static_cast<intptr_t>(local_key);
809 : return reinterpret_cast<pthread_key_t>(ptr_key);
810 : #else
811 3209779 : return static_cast<pthread_key_t>(local_key);
812 : #endif
813 : }
814 :
815 :
816 : #ifdef V8_FAST_TLS_SUPPORTED
817 :
818 : static Atomic32 tls_base_offset_initialized = 0;
819 : intptr_t kMacTlsBaseOffset = 0;
820 :
821 : // It's safe to do the initialization more that once, but it has to be
822 : // done at least once.
823 : static void InitializeTlsBaseOffset() {
824 : const size_t kBufferSize = 128;
825 : char buffer[kBufferSize];
826 : size_t buffer_size = kBufferSize;
827 : int ctl_name[] = { CTL_KERN , KERN_OSRELEASE };
828 : if (sysctl(ctl_name, 2, buffer, &buffer_size, nullptr, 0) != 0) {
829 : FATAL("V8 failed to get kernel version");
830 : }
831 : // The buffer now contains a string of the form XX.YY.ZZ, where
832 : // XX is the major kernel version component.
833 : // Make sure the buffer is 0-terminated.
834 : buffer[kBufferSize - 1] = '\0';
835 : char* period_pos = strchr(buffer, '.');
836 : *period_pos = '\0';
837 : int kernel_version_major =
838 : static_cast<int>(strtol(buffer, nullptr, 10)); // NOLINT
839 : // The constants below are taken from pthreads.s from the XNU kernel
840 : // sources archive at www.opensource.apple.com.
841 : if (kernel_version_major < 11) {
842 : // 8.x.x (Tiger), 9.x.x (Leopard), 10.x.x (Snow Leopard) have the
843 : // same offsets.
844 : #if V8_HOST_ARCH_IA32
845 : kMacTlsBaseOffset = 0x48;
846 : #else
847 : kMacTlsBaseOffset = 0x60;
848 : #endif
849 : } else {
850 : // 11.x.x (Lion) changed the offset.
851 : kMacTlsBaseOffset = 0;
852 : }
853 :
854 : Release_Store(&tls_base_offset_initialized, 1);
855 : }
856 :
857 :
858 : static void CheckFastTls(Thread::LocalStorageKey key) {
859 : void* expected = reinterpret_cast<void*>(0x1234CAFE);
860 : Thread::SetThreadLocal(key, expected);
861 : void* actual = Thread::GetExistingThreadLocal(key);
862 : if (expected != actual) {
863 : FATAL("V8 failed to initialize fast TLS on current kernel");
864 : }
865 : Thread::SetThreadLocal(key, nullptr);
866 : }
867 :
868 : #endif // V8_FAST_TLS_SUPPORTED
869 :
870 :
871 176978 : Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
872 : #ifdef V8_FAST_TLS_SUPPORTED
873 : bool check_fast_tls = false;
874 : if (tls_base_offset_initialized == 0) {
875 : check_fast_tls = true;
876 : InitializeTlsBaseOffset();
877 : }
878 : #endif
879 : pthread_key_t key;
880 176978 : int result = pthread_key_create(&key, nullptr);
881 : DCHECK_EQ(0, result);
882 : USE(result);
883 176978 : LocalStorageKey local_key = PthreadKeyToLocalKey(key);
884 : #ifdef V8_FAST_TLS_SUPPORTED
885 : // If we just initialized fast TLS support, make sure it works.
886 : if (check_fast_tls) CheckFastTls(local_key);
887 : #endif
888 176978 : return local_key;
889 : }
890 :
891 :
892 32 : void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
893 : pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
894 32 : int result = pthread_key_delete(pthread_key);
895 : DCHECK_EQ(0, result);
896 : USE(result);
897 32 : }
898 :
899 :
900 1928297 : void* Thread::GetThreadLocal(LocalStorageKey key) {
901 : pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
902 1928297 : return pthread_getspecific(pthread_key);
903 : }
904 :
905 :
906 1281450 : void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
907 : pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
908 1281450 : int result = pthread_setspecific(pthread_key, value);
909 : DCHECK_EQ(0, result);
910 : USE(result);
911 1281462 : }
912 :
913 : #undef LOG_TAG
914 : #undef MAP_ANONYMOUS
915 : #undef MADV_FREE
916 :
917 : } // namespace base
918 : } // namespace v8
|