blob: 64aed2b8d1f2d0c3d3c86ef86cfd6d8fccd573e9 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016#include <stdio.h>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017#include <time.h>
18#include <unistd.h>
19
20#include <sys/mman.h>
21#include <sys/resource.h>
22#include <sys/stat.h>
23#include <sys/time.h>
24#include <sys/types.h>
25#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || \
26 defined(__NetBSD__) || defined(__OpenBSD__)
27#include <sys/sysctl.h> // NOLINT, for sysctl
28#endif
29
30#undef MAP_TYPE
31
32#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
33#define LOG_TAG "v8"
34#include <android/log.h> // NOLINT
35#endif
36
37#include <cmath>
38#include <cstdlib>
39
40#include "src/base/lazy-instance.h"
41#include "src/base/macros.h"
42#include "src/base/platform/platform.h"
43#include "src/base/platform/time.h"
44#include "src/base/utils/random-number-generator.h"
45
46#ifdef V8_FAST_TLS_SUPPORTED
47#include "src/base/atomicops.h"
48#endif
49
50#if V8_OS_MACOSX
51#include <dlfcn.h>
52#endif
53
54#if V8_OS_LINUX
55#include <sys/prctl.h> // NOLINT, for prctl
56#endif
57
58#if !V8_OS_NACL
59#include <sys/syscall.h>
60#endif
61
62namespace v8 {
63namespace base {
64
65namespace {
66
67// 0 is never a valid thread id.
68const pthread_t kNoThread = (pthread_t) 0;
69
70bool g_hard_abort = false;
71
72const char* g_gc_fake_mmap = NULL;
73
74} // namespace
75
76
77int OS::ActivationFrameAlignment() {
78#if V8_TARGET_ARCH_ARM
79 // On EABI ARM targets this is required for fp correctness in the
80 // runtime system.
81 return 8;
82#elif V8_TARGET_ARCH_MIPS
83 return 8;
84#else
85 // Otherwise we just assume 16 byte alignment, i.e.:
86 // - With gcc 4.4 the tree vectorization optimizer can generate code
87 // that requires 16 byte alignment such as movdqa on x86.
88 // - Mac OS X and Solaris (64-bit) activation frames must be 16 byte-aligned;
89 // see "Mac OS X ABI Function Call Guide"
90 return 16;
91#endif
92}
93
94
95intptr_t OS::CommitPageSize() {
96 static intptr_t page_size = getpagesize();
97 return page_size;
98}
99
100
101void OS::Free(void* address, const size_t size) {
102 // TODO(1240712): munmap has a return value which is ignored here.
103 int result = munmap(address, size);
104 USE(result);
105 DCHECK(result == 0);
106}
107
108
109// Get rid of writable permission on code allocations.
110void OS::ProtectCode(void* address, const size_t size) {
111#if V8_OS_CYGWIN
112 DWORD old_protect;
113 VirtualProtect(address, size, PAGE_EXECUTE_READ, &old_protect);
114#elif V8_OS_NACL
115 // The Native Client port of V8 uses an interpreter, so
116 // code pages don't need PROT_EXEC.
117 mprotect(address, size, PROT_READ);
118#else
119 mprotect(address, size, PROT_READ | PROT_EXEC);
120#endif
121}
122
123
124// Create guard pages.
125void OS::Guard(void* address, const size_t size) {
126#if V8_OS_CYGWIN
127 DWORD oldprotect;
128 VirtualProtect(address, size, PAGE_NOACCESS, &oldprotect);
129#else
130 mprotect(address, size, PROT_NONE);
131#endif
132}
133
134
135static LazyInstance<RandomNumberGenerator>::type
136 platform_random_number_generator = LAZY_INSTANCE_INITIALIZER;
137
138
139void OS::Initialize(int64_t random_seed, bool hard_abort,
140 const char* const gc_fake_mmap) {
141 if (random_seed) {
142 platform_random_number_generator.Pointer()->SetSeed(random_seed);
143 }
144 g_hard_abort = hard_abort;
145 g_gc_fake_mmap = gc_fake_mmap;
146}
147
148
149const char* OS::GetGCFakeMMapFile() {
150 return g_gc_fake_mmap;
151}
152
153
154void* OS::GetRandomMmapAddr() {
155#if V8_OS_NACL
156 // TODO(bradchen): restore randomization once Native Client gets
157 // smarter about using mmap address hints.
158 // See http://code.google.com/p/nativeclient/issues/3341
159 return NULL;
160#endif
161#if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
162 defined(THREAD_SANITIZER)
163 // Dynamic tools do not support custom mmap addresses.
164 return NULL;
165#endif
166 uintptr_t raw_addr;
167 platform_random_number_generator.Pointer()->NextBytes(&raw_addr,
168 sizeof(raw_addr));
169#if V8_TARGET_ARCH_X64
170 // Currently available CPUs have 48 bits of virtual addressing. Truncate
171 // the hint address to 46 bits to give the kernel a fighting chance of
172 // fulfilling our placement request.
173 raw_addr &= V8_UINT64_C(0x3ffffffff000);
174#else
175 raw_addr &= 0x3ffff000;
176
177# ifdef __sun
178 // For our Solaris/illumos mmap hint, we pick a random address in the bottom
179 // half of the top half of the address space (that is, the third quarter).
180 // Because we do not MAP_FIXED, this will be treated only as a hint -- the
181 // system will not fail to mmap() because something else happens to already
182 // be mapped at our random address. We deliberately set the hint high enough
183 // to get well above the system's break (that is, the heap); Solaris and
184 // illumos will try the hint and if that fails allocate as if there were
185 // no hint at all. The high hint prevents the break from getting hemmed in
186 // at low values, ceding half of the address space to the system heap.
187 raw_addr += 0x80000000;
188# else
189 // The range 0x20000000 - 0x60000000 is relatively unpopulated across a
190 // variety of ASLR modes (PAE kernel, NX compat mode, etc) and on macos
191 // 10.6 and 10.7.
192 raw_addr += 0x20000000;
193# endif
194#endif
195 return reinterpret_cast<void*>(raw_addr);
196}
197
198
199size_t OS::AllocateAlignment() {
200 return static_cast<size_t>(sysconf(_SC_PAGESIZE));
201}
202
203
204void OS::Sleep(int milliseconds) {
205 useconds_t ms = static_cast<useconds_t>(milliseconds);
206 usleep(1000 * ms);
207}
208
209
210void OS::Abort() {
211 if (g_hard_abort) {
212 V8_IMMEDIATE_CRASH();
213 }
214 // Redirect to std abort to signal abnormal program termination.
215 abort();
216}
217
218
219void OS::DebugBreak() {
220#if V8_HOST_ARCH_ARM
221 asm("bkpt 0");
222#elif V8_HOST_ARCH_ARM64
223 asm("brk 0");
224#elif V8_HOST_ARCH_MIPS
225 asm("break");
226#elif V8_HOST_ARCH_MIPS64
227 asm("break");
228#elif V8_HOST_ARCH_IA32
229#if V8_OS_NACL
230 asm("hlt");
231#else
232 asm("int $3");
233#endif // V8_OS_NACL
234#elif V8_HOST_ARCH_X64
235 asm("int $3");
236#else
237#error Unsupported host architecture.
238#endif
239}
240
241
242// ----------------------------------------------------------------------------
243// Math functions
244
245double OS::nan_value() {
246 // NAN from math.h is defined in C99 and not in POSIX.
247 return NAN;
248}
249
250
251int OS::GetCurrentProcessId() {
252 return static_cast<int>(getpid());
253}
254
255
256int OS::GetCurrentThreadId() {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400257#if V8_OS_MACOSX || (V8_OS_ANDROID && defined(__APPLE__))
258 return static_cast<int>(pthread_mach_thread_np(pthread_self()));
259#elif V8_OS_LINUX
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000260 return static_cast<int>(syscall(__NR_gettid));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400261#elif V8_OS_ANDROID
262 return static_cast<int>(gettid());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000263#else
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400264 return static_cast<int>(reinterpret_cast<intptr_t>(pthread_self()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000265#endif
266}
267
268
269// ----------------------------------------------------------------------------
270// POSIX date/time support.
271//
272
273int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) {
274#if V8_OS_NACL
275 // Optionally used in Logger::ResourceEvent.
276 return -1;
277#else
278 struct rusage usage;
279
280 if (getrusage(RUSAGE_SELF, &usage) < 0) return -1;
281 *secs = usage.ru_utime.tv_sec;
282 *usecs = usage.ru_utime.tv_usec;
283 return 0;
284#endif
285}
286
287
288double OS::TimeCurrentMillis() {
289 return Time::Now().ToJsTime();
290}
291
292
293class TimezoneCache {};
294
295
296TimezoneCache* OS::CreateTimezoneCache() {
297 return NULL;
298}
299
300
301void OS::DisposeTimezoneCache(TimezoneCache* cache) {
302 DCHECK(cache == NULL);
303}
304
305
306void OS::ClearTimezoneCache(TimezoneCache* cache) {
307 DCHECK(cache == NULL);
308}
309
310
311double OS::DaylightSavingsOffset(double time, TimezoneCache*) {
312 if (std::isnan(time)) return nan_value();
313 time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
314 struct tm* t = localtime(&tv);
315 if (NULL == t) return nan_value();
316 return t->tm_isdst > 0 ? 3600 * msPerSecond : 0;
317}
318
319
320int OS::GetLastError() {
321 return errno;
322}
323
324
325// ----------------------------------------------------------------------------
326// POSIX stdio support.
327//
328
329FILE* OS::FOpen(const char* path, const char* mode) {
330 FILE* file = fopen(path, mode);
331 if (file == NULL) return NULL;
332 struct stat file_stat;
333 if (fstat(fileno(file), &file_stat) != 0) return NULL;
334 bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0);
335 if (is_regular_file) return file;
336 fclose(file);
337 return NULL;
338}
339
340
341bool OS::Remove(const char* path) {
342 return (remove(path) == 0);
343}
344
345
346FILE* OS::OpenTemporaryFile() {
347 return tmpfile();
348}
349
350
351const char* const OS::LogFileOpenMode = "w";
352
353
354void OS::Print(const char* format, ...) {
355 va_list args;
356 va_start(args, format);
357 VPrint(format, args);
358 va_end(args);
359}
360
361
362void OS::VPrint(const char* format, va_list args) {
363#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
364 __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args);
365#else
366 vprintf(format, args);
367#endif
368}
369
370
371void OS::FPrint(FILE* out, const char* format, ...) {
372 va_list args;
373 va_start(args, format);
374 VFPrint(out, format, args);
375 va_end(args);
376}
377
378
379void OS::VFPrint(FILE* out, const char* format, va_list args) {
380#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
381 __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args);
382#else
383 vfprintf(out, format, args);
384#endif
385}
386
387
388void OS::PrintError(const char* format, ...) {
389 va_list args;
390 va_start(args, format);
391 VPrintError(format, args);
392 va_end(args);
393}
394
395
396void OS::VPrintError(const char* format, va_list args) {
397#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
398 __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, format, args);
399#else
400 vfprintf(stderr, format, args);
401#endif
402}
403
404
405int OS::SNPrintF(char* str, int length, const char* format, ...) {
406 va_list args;
407 va_start(args, format);
408 int result = VSNPrintF(str, length, format, args);
409 va_end(args);
410 return result;
411}
412
413
414int OS::VSNPrintF(char* str,
415 int length,
416 const char* format,
417 va_list args) {
418 int n = vsnprintf(str, length, format, args);
419 if (n < 0 || n >= length) {
420 // If the length is zero, the assignment fails.
421 if (length > 0)
422 str[length - 1] = '\0';
423 return -1;
424 } else {
425 return n;
426 }
427}
428
429
430// ----------------------------------------------------------------------------
431// POSIX string support.
432//
433
434char* OS::StrChr(char* str, int c) {
435 return strchr(str, c);
436}
437
438
439void OS::StrNCpy(char* dest, int length, const char* src, size_t n) {
440 strncpy(dest, src, n);
441}
442
443
444// ----------------------------------------------------------------------------
445// POSIX thread support.
446//
447
448class Thread::PlatformData {
449 public:
450 PlatformData() : thread_(kNoThread) {}
451 pthread_t thread_; // Thread handle for pthread.
452 // Synchronizes thread creation
453 Mutex thread_creation_mutex_;
454};
455
456Thread::Thread(const Options& options)
457 : data_(new PlatformData),
458 stack_size_(options.stack_size()),
459 start_semaphore_(NULL) {
460 if (stack_size_ > 0 && static_cast<size_t>(stack_size_) < PTHREAD_STACK_MIN) {
461 stack_size_ = PTHREAD_STACK_MIN;
462 }
463 set_name(options.name());
464}
465
466
467Thread::~Thread() {
468 delete data_;
469}
470
471
472static void SetThreadName(const char* name) {
473#if V8_OS_DRAGONFLYBSD || V8_OS_FREEBSD || V8_OS_OPENBSD
474 pthread_set_name_np(pthread_self(), name);
475#elif V8_OS_NETBSD
476 STATIC_ASSERT(Thread::kMaxThreadNameLength <= PTHREAD_MAX_NAMELEN_NP);
477 pthread_setname_np(pthread_self(), "%s", name);
478#elif V8_OS_MACOSX
479 // pthread_setname_np is only available in 10.6 or later, so test
480 // for it at runtime.
481 int (*dynamic_pthread_setname_np)(const char*);
482 *reinterpret_cast<void**>(&dynamic_pthread_setname_np) =
483 dlsym(RTLD_DEFAULT, "pthread_setname_np");
484 if (dynamic_pthread_setname_np == NULL)
485 return;
486
487 // Mac OS X does not expose the length limit of the name, so hardcode it.
488 static const int kMaxNameLength = 63;
489 STATIC_ASSERT(Thread::kMaxThreadNameLength <= kMaxNameLength);
490 dynamic_pthread_setname_np(name);
491#elif defined(PR_SET_NAME)
492 prctl(PR_SET_NAME,
493 reinterpret_cast<unsigned long>(name), // NOLINT
494 0, 0, 0);
495#endif
496}
497
498
499static void* ThreadEntry(void* arg) {
500 Thread* thread = reinterpret_cast<Thread*>(arg);
501 // We take the lock here to make sure that pthread_create finished first since
502 // we don't know which thread will run first (the original thread or the new
503 // one).
504 { LockGuard<Mutex> lock_guard(&thread->data()->thread_creation_mutex_); }
505 SetThreadName(thread->name());
506 DCHECK(thread->data()->thread_ != kNoThread);
507 thread->NotifyStartedAndRun();
508 return NULL;
509}
510
511
512void Thread::set_name(const char* name) {
513 strncpy(name_, name, sizeof(name_));
514 name_[sizeof(name_) - 1] = '\0';
515}
516
517
518void Thread::Start() {
519 int result;
520 pthread_attr_t attr;
521 memset(&attr, 0, sizeof(attr));
522 result = pthread_attr_init(&attr);
523 DCHECK_EQ(0, result);
524 // Native client uses default stack size.
525#if !V8_OS_NACL
526 if (stack_size_ > 0) {
527 result = pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
528 DCHECK_EQ(0, result);
529 }
530#endif
531 {
532 LockGuard<Mutex> lock_guard(&data_->thread_creation_mutex_);
533 result = pthread_create(&data_->thread_, &attr, ThreadEntry, this);
534 }
535 DCHECK_EQ(0, result);
536 result = pthread_attr_destroy(&attr);
537 DCHECK_EQ(0, result);
538 DCHECK(data_->thread_ != kNoThread);
539 USE(result);
540}
541
542
543void Thread::Join() {
544 pthread_join(data_->thread_, NULL);
545}
546
547
548void Thread::YieldCPU() {
549 int result = sched_yield();
550 DCHECK_EQ(0, result);
551 USE(result);
552}
553
554
555static Thread::LocalStorageKey PthreadKeyToLocalKey(pthread_key_t pthread_key) {
556#if V8_OS_CYGWIN
557 // We need to cast pthread_key_t to Thread::LocalStorageKey in two steps
558 // because pthread_key_t is a pointer type on Cygwin. This will probably not
559 // work on 64-bit platforms, but Cygwin doesn't support 64-bit anyway.
560 STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t));
561 intptr_t ptr_key = reinterpret_cast<intptr_t>(pthread_key);
562 return static_cast<Thread::LocalStorageKey>(ptr_key);
563#else
564 return static_cast<Thread::LocalStorageKey>(pthread_key);
565#endif
566}
567
568
569static pthread_key_t LocalKeyToPthreadKey(Thread::LocalStorageKey local_key) {
570#if V8_OS_CYGWIN
571 STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t));
572 intptr_t ptr_key = static_cast<intptr_t>(local_key);
573 return reinterpret_cast<pthread_key_t>(ptr_key);
574#else
575 return static_cast<pthread_key_t>(local_key);
576#endif
577}
578
579
580#ifdef V8_FAST_TLS_SUPPORTED
581
582static Atomic32 tls_base_offset_initialized = 0;
583intptr_t kMacTlsBaseOffset = 0;
584
585// It's safe to do the initialization more that once, but it has to be
586// done at least once.
587static void InitializeTlsBaseOffset() {
588 const size_t kBufferSize = 128;
589 char buffer[kBufferSize];
590 size_t buffer_size = kBufferSize;
591 int ctl_name[] = { CTL_KERN , KERN_OSRELEASE };
592 if (sysctl(ctl_name, 2, buffer, &buffer_size, NULL, 0) != 0) {
593 V8_Fatal(__FILE__, __LINE__, "V8 failed to get kernel version");
594 }
595 // The buffer now contains a string of the form XX.YY.ZZ, where
596 // XX is the major kernel version component.
597 // Make sure the buffer is 0-terminated.
598 buffer[kBufferSize - 1] = '\0';
599 char* period_pos = strchr(buffer, '.');
600 *period_pos = '\0';
601 int kernel_version_major =
602 static_cast<int>(strtol(buffer, NULL, 10)); // NOLINT
603 // The constants below are taken from pthreads.s from the XNU kernel
604 // sources archive at www.opensource.apple.com.
605 if (kernel_version_major < 11) {
606 // 8.x.x (Tiger), 9.x.x (Leopard), 10.x.x (Snow Leopard) have the
607 // same offsets.
608#if V8_HOST_ARCH_IA32
609 kMacTlsBaseOffset = 0x48;
610#else
611 kMacTlsBaseOffset = 0x60;
612#endif
613 } else {
614 // 11.x.x (Lion) changed the offset.
615 kMacTlsBaseOffset = 0;
616 }
617
618 Release_Store(&tls_base_offset_initialized, 1);
619}
620
621
622static void CheckFastTls(Thread::LocalStorageKey key) {
623 void* expected = reinterpret_cast<void*>(0x1234CAFE);
624 Thread::SetThreadLocal(key, expected);
625 void* actual = Thread::GetExistingThreadLocal(key);
626 if (expected != actual) {
627 V8_Fatal(__FILE__, __LINE__,
628 "V8 failed to initialize fast TLS on current kernel");
629 }
630 Thread::SetThreadLocal(key, NULL);
631}
632
633#endif // V8_FAST_TLS_SUPPORTED
634
635
636Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
637#ifdef V8_FAST_TLS_SUPPORTED
638 bool check_fast_tls = false;
639 if (tls_base_offset_initialized == 0) {
640 check_fast_tls = true;
641 InitializeTlsBaseOffset();
642 }
643#endif
644 pthread_key_t key;
645 int result = pthread_key_create(&key, NULL);
646 DCHECK_EQ(0, result);
647 USE(result);
648 LocalStorageKey local_key = PthreadKeyToLocalKey(key);
649#ifdef V8_FAST_TLS_SUPPORTED
650 // If we just initialized fast TLS support, make sure it works.
651 if (check_fast_tls) CheckFastTls(local_key);
652#endif
653 return local_key;
654}
655
656
657void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
658 pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
659 int result = pthread_key_delete(pthread_key);
660 DCHECK_EQ(0, result);
661 USE(result);
662}
663
664
665void* Thread::GetThreadLocal(LocalStorageKey key) {
666 pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
667 return pthread_getspecific(pthread_key);
668}
669
670
671void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
672 pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
673 int result = pthread_setspecific(pthread_key, value);
674 DCHECK_EQ(0, result);
675 USE(result);
676}
677
678
679} } // namespace v8::base