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.
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.
12 #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
13 #include <pthread_np.h> // for pthread_set_name_np
15 #include <sched.h> // for sched_yield
20 #include <sys/resource.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
31 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
33 #include <android/log.h> // NOLINT
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"
45 #ifdef V8_FAST_TLS_SUPPORTED
46 #include "src/base/atomicops.h"
54 #include <sys/prctl.h> // NOLINT, for prctl
58 #include <sys/syscall.h>
66 // 0 is never a valid thread id.
67 const pthread_t kNoThread = (pthread_t) 0;
69 bool g_hard_abort = false;
71 const char* g_gc_fake_mmap = NULL;
76 int OS::ActivationFrameAlignment() {
77 #if V8_TARGET_ARCH_ARM
78 // On EABI ARM targets this is required for fp correctness in the
81 #elif V8_TARGET_ARCH_MIPS
84 // Otherwise we just assume 16 byte alignment, i.e.:
85 // - With gcc 4.4 the tree vectorization optimizer can generate code
86 // that requires 16 byte alignment such as movdqa on x86.
87 // - Mac OS X and Solaris (64-bit) activation frames must be 16 byte-aligned;
88 // see "Mac OS X ABI Function Call Guide"
94 intptr_t OS::CommitPageSize() {
95 static intptr_t page_size = getpagesize();
100 void OS::Free(void* address, const size_t size) {
101 // TODO(1240712): munmap has a return value which is ignored here.
102 int result = munmap(address, size);
108 // Get rid of writable permission on code allocations.
109 void OS::ProtectCode(void* address, const size_t size) {
112 VirtualProtect(address, size, PAGE_EXECUTE_READ, &old_protect);
114 // The Native Client port of V8 uses an interpreter, so
115 // code pages don't need PROT_EXEC.
116 mprotect(address, size, PROT_READ);
118 mprotect(address, size, PROT_READ | PROT_EXEC);
123 // Create guard pages.
124 void OS::Guard(void* address, const size_t size) {
127 VirtualProtect(address, size, PAGE_NOACCESS, &oldprotect);
129 mprotect(address, size, PROT_NONE);
134 static LazyInstance<RandomNumberGenerator>::type
135 platform_random_number_generator = LAZY_INSTANCE_INITIALIZER;
138 void OS::Initialize(int64_t random_seed, bool hard_abort,
139 const char* const gc_fake_mmap) {
141 platform_random_number_generator.Pointer()->SetSeed(random_seed);
143 g_hard_abort = hard_abort;
144 g_gc_fake_mmap = gc_fake_mmap;
148 const char* OS::GetGCFakeMMapFile() {
149 return g_gc_fake_mmap;
153 void* OS::GetRandomMmapAddr() {
155 // TODO(bradchen): restore randomization once Native Client gets
156 // smarter about using mmap address hints.
157 // See http://code.google.com/p/nativeclient/issues/3341
160 #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
161 defined(THREAD_SANITIZER)
162 // Dynamic tools do not support custom mmap addresses.
166 platform_random_number_generator.Pointer()->NextBytes(&raw_addr,
168 #if V8_TARGET_ARCH_X64
169 // Currently available CPUs have 48 bits of virtual addressing. Truncate
170 // the hint address to 46 bits to give the kernel a fighting chance of
171 // fulfilling our placement request.
172 raw_addr &= V8_UINT64_C(0x3ffffffff000);
174 raw_addr &= 0x3ffff000;
177 // For our Solaris/illumos mmap hint, we pick a random address in the bottom
178 // half of the top half of the address space (that is, the third quarter).
179 // Because we do not MAP_FIXED, this will be treated only as a hint -- the
180 // system will not fail to mmap() because something else happens to already
181 // be mapped at our random address. We deliberately set the hint high enough
182 // to get well above the system's break (that is, the heap); Solaris and
183 // illumos will try the hint and if that fails allocate as if there were
184 // no hint at all. The high hint prevents the break from getting hemmed in
185 // at low values, ceding half of the address space to the system heap.
186 raw_addr += 0x80000000;
188 // The range 0x20000000 - 0x60000000 is relatively unpopulated across a
189 // variety of ASLR modes (PAE kernel, NX compat mode, etc) and on macos
191 raw_addr += 0x20000000;
194 return reinterpret_cast<void*>(raw_addr);
198 size_t OS::AllocateAlignment() {
199 return static_cast<size_t>(sysconf(_SC_PAGESIZE));
203 void OS::Sleep(int milliseconds) {
204 useconds_t ms = static_cast<useconds_t>(milliseconds);
211 V8_IMMEDIATE_CRASH();
213 // Redirect to std abort to signal abnormal program termination.
218 void OS::DebugBreak() {
221 #elif V8_HOST_ARCH_ARM64
223 #elif V8_HOST_ARCH_MIPS
225 #elif V8_HOST_ARCH_MIPS64
227 #elif V8_HOST_ARCH_IA32
233 #elif V8_HOST_ARCH_X64
236 #error Unsupported host architecture.
241 // ----------------------------------------------------------------------------
244 double OS::nan_value() {
245 // NAN from math.h is defined in C99 and not in POSIX.
250 int OS::GetCurrentProcessId() {
251 return static_cast<int>(getpid());
255 int OS::GetCurrentThreadId() {
257 return static_cast<int>(pthread_mach_thread_np(pthread_self()));
259 return static_cast<int>(syscall(__NR_gettid));
261 return static_cast<int>(gettid());
263 return static_cast<int>(pthread_self());
268 // ----------------------------------------------------------------------------
269 // POSIX date/time support.
272 int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) {
274 // Optionally used in Logger::ResourceEvent.
279 if (getrusage(RUSAGE_SELF, &usage) < 0) return -1;
280 *secs = usage.ru_utime.tv_sec;
281 *usecs = usage.ru_utime.tv_usec;
287 double OS::TimeCurrentMillis() {
288 return Time::Now().ToJsTime();
292 class TimezoneCache {};
295 TimezoneCache* OS::CreateTimezoneCache() {
300 void OS::DisposeTimezoneCache(TimezoneCache* cache) {
301 DCHECK(cache == NULL);
305 void OS::ClearTimezoneCache(TimezoneCache* cache) {
306 DCHECK(cache == NULL);
310 double OS::DaylightSavingsOffset(double time, TimezoneCache*) {
311 if (std::isnan(time)) return nan_value();
312 time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
313 struct tm* t = localtime(&tv);
314 if (NULL == t) return nan_value();
315 return t->tm_isdst > 0 ? 3600 * msPerSecond : 0;
319 int OS::GetLastError() {
324 // ----------------------------------------------------------------------------
325 // POSIX stdio support.
328 FILE* OS::FOpen(const char* path, const char* mode) {
329 FILE* file = fopen(path, mode);
330 if (file == NULL) return NULL;
331 struct stat file_stat;
332 if (fstat(fileno(file), &file_stat) != 0) return NULL;
333 bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0);
334 if (is_regular_file) return file;
340 bool OS::Remove(const char* path) {
341 return (remove(path) == 0);
345 FILE* OS::OpenTemporaryFile() {
350 const char* const OS::LogFileOpenMode = "w";
353 void OS::Print(const char* format, ...) {
355 va_start(args, format);
356 VPrint(format, args);
361 void OS::VPrint(const char* format, va_list args) {
362 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
363 __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args);
365 vprintf(format, args);
370 void OS::FPrint(FILE* out, const char* format, ...) {
372 va_start(args, format);
373 VFPrint(out, format, args);
378 void OS::VFPrint(FILE* out, const char* format, va_list args) {
379 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
380 __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args);
382 vfprintf(out, format, args);
387 void OS::PrintError(const char* format, ...) {
389 va_start(args, format);
390 VPrintError(format, args);
395 void OS::VPrintError(const char* format, va_list args) {
396 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
397 __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, format, args);
399 vfprintf(stderr, format, args);
404 int OS::SNPrintF(char* str, int length, const char* format, ...) {
406 va_start(args, format);
407 int result = VSNPrintF(str, length, format, args);
413 int OS::VSNPrintF(char* str,
417 int n = vsnprintf(str, length, format, args);
418 if (n < 0 || n >= length) {
419 // If the length is zero, the assignment fails.
421 str[length - 1] = '\0';
429 // ----------------------------------------------------------------------------
430 // POSIX string support.
433 char* OS::StrChr(char* str, int c) {
434 return strchr(str, c);
438 void OS::StrNCpy(char* dest, int length, const char* src, size_t n) {
439 strncpy(dest, src, n);
443 // ----------------------------------------------------------------------------
444 // POSIX thread support.
447 class Thread::PlatformData {
449 PlatformData() : thread_(kNoThread) {}
450 pthread_t thread_; // Thread handle for pthread.
451 // Synchronizes thread creation
452 Mutex thread_creation_mutex_;
455 Thread::Thread(const Options& options)
456 : data_(new PlatformData),
457 stack_size_(options.stack_size()),
458 start_semaphore_(NULL) {
459 if (stack_size_ > 0 && static_cast<size_t>(stack_size_) < PTHREAD_STACK_MIN) {
460 stack_size_ = PTHREAD_STACK_MIN;
462 set_name(options.name());
471 static void SetThreadName(const char* name) {
472 #if V8_OS_DRAGONFLYBSD || V8_OS_FREEBSD || V8_OS_OPENBSD
473 pthread_set_name_np(pthread_self(), name);
475 STATIC_ASSERT(Thread::kMaxThreadNameLength <= PTHREAD_MAX_NAMELEN_NP);
476 pthread_setname_np(pthread_self(), "%s", name);
478 // pthread_setname_np is only available in 10.6 or later, so test
479 // for it at runtime.
480 int (*dynamic_pthread_setname_np)(const char*);
481 *reinterpret_cast<void**>(&dynamic_pthread_setname_np) =
482 dlsym(RTLD_DEFAULT, "pthread_setname_np");
483 if (dynamic_pthread_setname_np == NULL)
486 // Mac OS X does not expose the length limit of the name, so hardcode it.
487 static const int kMaxNameLength = 63;
488 STATIC_ASSERT(Thread::kMaxThreadNameLength <= kMaxNameLength);
489 dynamic_pthread_setname_np(name);
490 #elif defined(PR_SET_NAME)
492 reinterpret_cast<unsigned long>(name), // NOLINT
498 static void* ThreadEntry(void* arg) {
499 Thread* thread = reinterpret_cast<Thread*>(arg);
500 // We take the lock here to make sure that pthread_create finished first since
501 // we don't know which thread will run first (the original thread or the new
503 { LockGuard<Mutex> lock_guard(&thread->data()->thread_creation_mutex_); }
504 SetThreadName(thread->name());
505 DCHECK(thread->data()->thread_ != kNoThread);
506 thread->NotifyStartedAndRun();
511 void Thread::set_name(const char* name) {
512 strncpy(name_, name, sizeof(name_));
513 name_[sizeof(name_) - 1] = '\0';
517 void Thread::Start() {
520 memset(&attr, 0, sizeof(attr));
521 result = pthread_attr_init(&attr);
522 DCHECK_EQ(0, result);
523 // Native client uses default stack size.
525 if (stack_size_ > 0) {
526 result = pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
527 DCHECK_EQ(0, result);
531 LockGuard<Mutex> lock_guard(&data_->thread_creation_mutex_);
532 result = pthread_create(&data_->thread_, &attr, ThreadEntry, this);
534 DCHECK_EQ(0, result);
535 result = pthread_attr_destroy(&attr);
536 DCHECK_EQ(0, result);
537 DCHECK(data_->thread_ != kNoThread);
542 void Thread::Join() {
543 pthread_join(data_->thread_, NULL);
547 void Thread::YieldCPU() {
548 int result = sched_yield();
549 DCHECK_EQ(0, result);
554 static Thread::LocalStorageKey PthreadKeyToLocalKey(pthread_key_t pthread_key) {
556 // We need to cast pthread_key_t to Thread::LocalStorageKey in two steps
557 // because pthread_key_t is a pointer type on Cygwin. This will probably not
558 // work on 64-bit platforms, but Cygwin doesn't support 64-bit anyway.
559 STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t));
560 intptr_t ptr_key = reinterpret_cast<intptr_t>(pthread_key);
561 return static_cast<Thread::LocalStorageKey>(ptr_key);
563 return static_cast<Thread::LocalStorageKey>(pthread_key);
568 static pthread_key_t LocalKeyToPthreadKey(Thread::LocalStorageKey local_key) {
570 STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t));
571 intptr_t ptr_key = static_cast<intptr_t>(local_key);
572 return reinterpret_cast<pthread_key_t>(ptr_key);
574 return static_cast<pthread_key_t>(local_key);
579 #ifdef V8_FAST_TLS_SUPPORTED
581 static Atomic32 tls_base_offset_initialized = 0;
582 intptr_t kMacTlsBaseOffset = 0;
584 // It's safe to do the initialization more that once, but it has to be
585 // done at least once.
586 static void InitializeTlsBaseOffset() {
587 const size_t kBufferSize = 128;
588 char buffer[kBufferSize];
589 size_t buffer_size = kBufferSize;
590 int ctl_name[] = { CTL_KERN , KERN_OSRELEASE };
591 if (sysctl(ctl_name, 2, buffer, &buffer_size, NULL, 0) != 0) {
592 V8_Fatal(__FILE__, __LINE__, "V8 failed to get kernel version");
594 // The buffer now contains a string of the form XX.YY.ZZ, where
595 // XX is the major kernel version component.
596 // Make sure the buffer is 0-terminated.
597 buffer[kBufferSize - 1] = '\0';
598 char* period_pos = strchr(buffer, '.');
600 int kernel_version_major =
601 static_cast<int>(strtol(buffer, NULL, 10)); // NOLINT
602 // The constants below are taken from pthreads.s from the XNU kernel
603 // sources archive at www.opensource.apple.com.
604 if (kernel_version_major < 11) {
605 // 8.x.x (Tiger), 9.x.x (Leopard), 10.x.x (Snow Leopard) have the
607 #if V8_HOST_ARCH_IA32
608 kMacTlsBaseOffset = 0x48;
610 kMacTlsBaseOffset = 0x60;
613 // 11.x.x (Lion) changed the offset.
614 kMacTlsBaseOffset = 0;
617 Release_Store(&tls_base_offset_initialized, 1);
621 static void CheckFastTls(Thread::LocalStorageKey key) {
622 void* expected = reinterpret_cast<void*>(0x1234CAFE);
623 Thread::SetThreadLocal(key, expected);
624 void* actual = Thread::GetExistingThreadLocal(key);
625 if (expected != actual) {
626 V8_Fatal(__FILE__, __LINE__,
627 "V8 failed to initialize fast TLS on current kernel");
629 Thread::SetThreadLocal(key, NULL);
632 #endif // V8_FAST_TLS_SUPPORTED
635 Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
636 #ifdef V8_FAST_TLS_SUPPORTED
637 bool check_fast_tls = false;
638 if (tls_base_offset_initialized == 0) {
639 check_fast_tls = true;
640 InitializeTlsBaseOffset();
644 int result = pthread_key_create(&key, NULL);
645 DCHECK_EQ(0, result);
647 LocalStorageKey local_key = PthreadKeyToLocalKey(key);
648 #ifdef V8_FAST_TLS_SUPPORTED
649 // If we just initialized fast TLS support, make sure it works.
650 if (check_fast_tls) CheckFastTls(local_key);
656 void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
657 pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
658 int result = pthread_key_delete(pthread_key);
659 DCHECK_EQ(0, result);
664 void* Thread::GetThreadLocal(LocalStorageKey key) {
665 pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
666 return pthread_getspecific(pthread_key);
670 void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
671 pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
672 int result = pthread_setspecific(pthread_key, value);
673 DCHECK_EQ(0, result);
678 } } // namespace v8::base