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.
11 #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
12 #include <pthread_np.h> // for pthread_set_name_np
14 #include <sched.h> // for sched_yield
20 #include <sys/resource.h>
22 #include <sys/types.h>
24 #if defined(__linux__)
25 #include <sys/prctl.h> // for prctl
27 #if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || \
28 defined(__NetBSD__) || defined(__OpenBSD__)
29 #include <sys/sysctl.h> // for sysctl
32 #include <arpa/inet.h>
33 #include <netinet/in.h>
38 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
40 #include <android/log.h>
45 #include "src/isolate-inl.h"
46 #include "src/platform.h"
48 #ifdef V8_FAST_TLS_SUPPORTED
49 #include "src/base/atomicops.h"
55 // 0 is never a valid thread id.
56 static const pthread_t kNoThread = (pthread_t) 0;
59 int OS::NumberOfProcessorsOnline() {
60 return static_cast<int>(sysconf(_SC_NPROCESSORS_ONLN));
64 // Maximum size of the virtual memory. 0 means there is no artificial
67 intptr_t OS::MaxVirtualMemory() {
69 int result = getrlimit(RLIMIT_DATA, &limit);
70 if (result != 0) return 0;
72 // The NaCl compiler doesn't like resource.h constants.
73 if (static_cast<int>(limit.rlim_cur) == -1) return 0;
75 if (limit.rlim_cur == RLIM_INFINITY) return 0;
77 return limit.rlim_cur;
81 uint64_t OS::TotalPhysicalMemory() {
87 size_t len = sizeof(size);
88 if (sysctl(mib, 2, &size, &len, NULL, 0) != 0) {
92 return static_cast<uint64_t>(size);
95 size_t size = sizeof(pages);
96 sysctlbyname("vm.stats.vm.v_page_count", &pages, &size, NULL, 0);
97 sysctlbyname("vm.stats.vm.v_page_size", &page_size, &size, NULL, 0);
98 if (pages == -1 || page_size == -1) {
102 return static_cast<uint64_t>(pages) * page_size;
104 MEMORYSTATUS memory_info;
105 memory_info.dwLength = sizeof(memory_info);
106 if (!GlobalMemoryStatus(&memory_info)) {
110 return static_cast<uint64_t>(memory_info.dwTotalPhys);
112 struct stat stat_buf;
113 if (stat("/proc", &stat_buf) != 0) {
117 return static_cast<uint64_t>(stat_buf.st_size);
119 intptr_t pages = sysconf(_SC_PHYS_PAGES);
120 intptr_t page_size = sysconf(_SC_PAGESIZE);
121 if (pages == -1 || page_size == -1) {
125 return static_cast<uint64_t>(pages) * page_size;
130 int OS::ActivationFrameAlignment() {
131 #if V8_TARGET_ARCH_ARM
132 // On EABI ARM targets this is required for fp correctness in the
135 #elif V8_TARGET_ARCH_MIPS
138 // Otherwise we just assume 16 byte alignment, i.e.:
139 // - With gcc 4.4 the tree vectorization optimizer can generate code
140 // that requires 16 byte alignment such as movdqa on x86.
141 // - Mac OS X and Solaris (64-bit) activation frames must be 16 byte-aligned;
142 // see "Mac OS X ABI Function Call Guide"
148 intptr_t OS::CommitPageSize() {
149 static intptr_t page_size = getpagesize();
154 void OS::Free(void* address, const size_t size) {
155 // TODO(1240712): munmap has a return value which is ignored here.
156 int result = munmap(address, size);
162 // Get rid of writable permission on code allocations.
163 void OS::ProtectCode(void* address, const size_t size) {
166 VirtualProtect(address, size, PAGE_EXECUTE_READ, &old_protect);
168 // The Native Client port of V8 uses an interpreter, so
169 // code pages don't need PROT_EXEC.
170 mprotect(address, size, PROT_READ);
172 mprotect(address, size, PROT_READ | PROT_EXEC);
177 // Create guard pages.
178 void OS::Guard(void* address, const size_t size) {
181 VirtualProtect(address, size, PAGE_NOACCESS, &oldprotect);
183 mprotect(address, size, PROT_NONE);
188 void* OS::GetRandomMmapAddr() {
190 // TODO(bradchen): restore randomization once Native Client gets
191 // smarter about using mmap address hints.
192 // See http://code.google.com/p/nativeclient/issues/3341
195 #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
196 defined(THREAD_SANITIZER)
197 // Dynamic tools do not support custom mmap addresses.
200 Isolate* isolate = Isolate::UncheckedCurrent();
201 // Note that the current isolate isn't set up in a call path via
202 // CpuFeatures::Probe. We don't care about randomization in this case because
203 // the code page is immediately freed.
204 if (isolate != NULL) {
206 isolate->random_number_generator()->NextBytes(&raw_addr, sizeof(raw_addr));
207 #if V8_TARGET_ARCH_X64
208 // Currently available CPUs have 48 bits of virtual addressing. Truncate
209 // the hint address to 46 bits to give the kernel a fighting chance of
210 // fulfilling our placement request.
211 raw_addr &= V8_UINT64_C(0x3ffffffff000);
213 raw_addr &= 0x3ffff000;
216 // For our Solaris/illumos mmap hint, we pick a random address in the bottom
217 // half of the top half of the address space (that is, the third quarter).
218 // Because we do not MAP_FIXED, this will be treated only as a hint -- the
219 // system will not fail to mmap() because something else happens to already
220 // be mapped at our random address. We deliberately set the hint high enough
221 // to get well above the system's break (that is, the heap); Solaris and
222 // illumos will try the hint and if that fails allocate as if there were
223 // no hint at all. The high hint prevents the break from getting hemmed in
224 // at low values, ceding half of the address space to the system heap.
225 raw_addr += 0x80000000;
227 // The range 0x20000000 - 0x60000000 is relatively unpopulated across a
228 // variety of ASLR modes (PAE kernel, NX compat mode, etc) and on macos
230 raw_addr += 0x20000000;
233 return reinterpret_cast<void*>(raw_addr);
239 size_t OS::AllocateAlignment() {
240 return static_cast<size_t>(sysconf(_SC_PAGESIZE));
244 void OS::Sleep(int milliseconds) {
245 useconds_t ms = static_cast<useconds_t>(milliseconds);
251 if (FLAG_hard_abort) {
252 V8_IMMEDIATE_CRASH();
254 // Redirect to std abort to signal abnormal program termination.
259 void OS::DebugBreak() {
262 #elif V8_HOST_ARCH_ARM64
264 #elif V8_HOST_ARCH_MIPS
266 #elif V8_HOST_ARCH_IA32
267 #if defined(__native_client__)
271 #endif // __native_client__
272 #elif V8_HOST_ARCH_X64
275 #error Unsupported host architecture.
280 // ----------------------------------------------------------------------------
283 double OS::nan_value() {
284 // NAN from math.h is defined in C99 and not in POSIX.
289 int OS::GetCurrentProcessId() {
290 return static_cast<int>(getpid());
294 // ----------------------------------------------------------------------------
295 // POSIX date/time support.
298 int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) {
301 if (getrusage(RUSAGE_SELF, &usage) < 0) return -1;
302 *secs = usage.ru_utime.tv_sec;
303 *usecs = usage.ru_utime.tv_usec;
308 double OS::TimeCurrentMillis() {
309 return Time::Now().ToJsTime();
313 class TimezoneCache {};
316 TimezoneCache* OS::CreateTimezoneCache() {
321 void OS::DisposeTimezoneCache(TimezoneCache* cache) {
322 ASSERT(cache == NULL);
326 void OS::ClearTimezoneCache(TimezoneCache* cache) {
327 ASSERT(cache == NULL);
331 double OS::DaylightSavingsOffset(double time, TimezoneCache*) {
332 if (std::isnan(time)) return nan_value();
333 time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
334 struct tm* t = localtime(&tv);
335 if (NULL == t) return nan_value();
336 return t->tm_isdst > 0 ? 3600 * msPerSecond : 0;
340 int OS::GetLastError() {
345 // ----------------------------------------------------------------------------
346 // POSIX stdio support.
349 FILE* OS::FOpen(const char* path, const char* mode) {
350 FILE* file = fopen(path, mode);
351 if (file == NULL) return NULL;
352 struct stat file_stat;
353 if (fstat(fileno(file), &file_stat) != 0) return NULL;
354 bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0);
355 if (is_regular_file) return file;
361 bool OS::Remove(const char* path) {
362 return (remove(path) == 0);
366 FILE* OS::OpenTemporaryFile() {
371 const char* const OS::LogFileOpenMode = "w";
374 void OS::Print(const char* format, ...) {
376 va_start(args, format);
377 VPrint(format, args);
382 void OS::VPrint(const char* format, va_list args) {
383 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
384 __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args);
386 vprintf(format, args);
391 void OS::FPrint(FILE* out, const char* format, ...) {
393 va_start(args, format);
394 VFPrint(out, format, args);
399 void OS::VFPrint(FILE* out, const char* format, va_list args) {
400 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
401 __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args);
403 vfprintf(out, format, args);
408 void OS::PrintError(const char* format, ...) {
410 va_start(args, format);
411 VPrintError(format, args);
416 void OS::VPrintError(const char* format, va_list args) {
417 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
418 __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, format, args);
420 vfprintf(stderr, format, args);
425 int OS::SNPrintF(char* str, int length, const char* format, ...) {
427 va_start(args, format);
428 int result = VSNPrintF(str, length, format, args);
434 int OS::VSNPrintF(char* str,
438 int n = vsnprintf(str, length, format, args);
439 if (n < 0 || n >= length) {
440 // If the length is zero, the assignment fails.
442 str[length - 1] = '\0';
450 // ----------------------------------------------------------------------------
451 // POSIX string support.
454 char* OS::StrChr(char* str, int c) {
455 return strchr(str, c);
459 void OS::StrNCpy(char* dest, int length, const char* src, size_t n) {
460 strncpy(dest, src, n);
464 // ----------------------------------------------------------------------------
465 // POSIX thread support.
468 class Thread::PlatformData : public Malloced {
470 PlatformData() : thread_(kNoThread) {}
471 pthread_t thread_; // Thread handle for pthread.
472 // Synchronizes thread creation
473 Mutex thread_creation_mutex_;
476 Thread::Thread(const Options& options)
477 : data_(new PlatformData),
478 stack_size_(options.stack_size()),
479 start_semaphore_(NULL) {
480 if (stack_size_ > 0 && stack_size_ < PTHREAD_STACK_MIN) {
481 stack_size_ = PTHREAD_STACK_MIN;
483 set_name(options.name());
492 static void SetThreadName(const char* name) {
493 #if V8_OS_DRAGONFLYBSD || V8_OS_FREEBSD || V8_OS_OPENBSD
494 pthread_set_name_np(pthread_self(), name);
496 STATIC_ASSERT(Thread::kMaxThreadNameLength <= PTHREAD_MAX_NAMELEN_NP);
497 pthread_setname_np(pthread_self(), "%s", name);
499 // pthread_setname_np is only available in 10.6 or later, so test
500 // for it at runtime.
501 int (*dynamic_pthread_setname_np)(const char*);
502 *reinterpret_cast<void**>(&dynamic_pthread_setname_np) =
503 dlsym(RTLD_DEFAULT, "pthread_setname_np");
504 if (dynamic_pthread_setname_np == NULL)
507 // Mac OS X does not expose the length limit of the name, so hardcode it.
508 static const int kMaxNameLength = 63;
509 STATIC_ASSERT(Thread::kMaxThreadNameLength <= kMaxNameLength);
510 dynamic_pthread_setname_np(name);
511 #elif defined(PR_SET_NAME)
513 reinterpret_cast<unsigned long>(name), // NOLINT
519 static void* ThreadEntry(void* arg) {
520 Thread* thread = reinterpret_cast<Thread*>(arg);
521 // We take the lock here to make sure that pthread_create finished first since
522 // we don't know which thread will run first (the original thread or the new
524 { LockGuard<Mutex> lock_guard(&thread->data()->thread_creation_mutex_); }
525 SetThreadName(thread->name());
526 ASSERT(thread->data()->thread_ != kNoThread);
527 thread->NotifyStartedAndRun();
532 void Thread::set_name(const char* name) {
533 strncpy(name_, name, sizeof(name_));
534 name_[sizeof(name_) - 1] = '\0';
538 void Thread::Start() {
541 memset(&attr, 0, sizeof(attr));
542 result = pthread_attr_init(&attr);
543 ASSERT_EQ(0, result);
544 // Native client uses default stack size.
546 if (stack_size_ > 0) {
547 result = pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
548 ASSERT_EQ(0, result);
552 LockGuard<Mutex> lock_guard(&data_->thread_creation_mutex_);
553 result = pthread_create(&data_->thread_, &attr, ThreadEntry, this);
555 ASSERT_EQ(0, result);
556 result = pthread_attr_destroy(&attr);
557 ASSERT_EQ(0, result);
558 ASSERT(data_->thread_ != kNoThread);
563 void Thread::Join() {
564 pthread_join(data_->thread_, NULL);
568 void Thread::YieldCPU() {
569 int result = sched_yield();
570 ASSERT_EQ(0, result);
575 static Thread::LocalStorageKey PthreadKeyToLocalKey(pthread_key_t pthread_key) {
577 // We need to cast pthread_key_t to Thread::LocalStorageKey in two steps
578 // because pthread_key_t is a pointer type on Cygwin. This will probably not
579 // work on 64-bit platforms, but Cygwin doesn't support 64-bit anyway.
580 STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t));
581 intptr_t ptr_key = reinterpret_cast<intptr_t>(pthread_key);
582 return static_cast<Thread::LocalStorageKey>(ptr_key);
584 return static_cast<Thread::LocalStorageKey>(pthread_key);
589 static pthread_key_t LocalKeyToPthreadKey(Thread::LocalStorageKey local_key) {
591 STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t));
592 intptr_t ptr_key = static_cast<intptr_t>(local_key);
593 return reinterpret_cast<pthread_key_t>(ptr_key);
595 return static_cast<pthread_key_t>(local_key);
600 #ifdef V8_FAST_TLS_SUPPORTED
602 static base::Atomic32 tls_base_offset_initialized = 0;
603 intptr_t kMacTlsBaseOffset = 0;
605 // It's safe to do the initialization more that once, but it has to be
606 // done at least once.
607 static void InitializeTlsBaseOffset() {
608 const size_t kBufferSize = 128;
609 char buffer[kBufferSize];
610 size_t buffer_size = kBufferSize;
611 int ctl_name[] = { CTL_KERN , KERN_OSRELEASE };
612 if (sysctl(ctl_name, 2, buffer, &buffer_size, NULL, 0) != 0) {
613 V8_Fatal(__FILE__, __LINE__, "V8 failed to get kernel version");
615 // The buffer now contains a string of the form XX.YY.ZZ, where
616 // XX is the major kernel version component.
617 // Make sure the buffer is 0-terminated.
618 buffer[kBufferSize - 1] = '\0';
619 char* period_pos = strchr(buffer, '.');
621 int kernel_version_major =
622 static_cast<int>(strtol(buffer, NULL, 10)); // NOLINT
623 // The constants below are taken from pthreads.s from the XNU kernel
624 // sources archive at www.opensource.apple.com.
625 if (kernel_version_major < 11) {
626 // 8.x.x (Tiger), 9.x.x (Leopard), 10.x.x (Snow Leopard) have the
628 #if V8_HOST_ARCH_IA32
629 kMacTlsBaseOffset = 0x48;
631 kMacTlsBaseOffset = 0x60;
634 // 11.x.x (Lion) changed the offset.
635 kMacTlsBaseOffset = 0;
638 base::Release_Store(&tls_base_offset_initialized, 1);
642 static void CheckFastTls(Thread::LocalStorageKey key) {
643 void* expected = reinterpret_cast<void*>(0x1234CAFE);
644 Thread::SetThreadLocal(key, expected);
645 void* actual = Thread::GetExistingThreadLocal(key);
646 if (expected != actual) {
647 V8_Fatal(__FILE__, __LINE__,
648 "V8 failed to initialize fast TLS on current kernel");
650 Thread::SetThreadLocal(key, NULL);
653 #endif // V8_FAST_TLS_SUPPORTED
656 Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
657 #ifdef V8_FAST_TLS_SUPPORTED
658 bool check_fast_tls = false;
659 if (tls_base_offset_initialized == 0) {
660 check_fast_tls = true;
661 InitializeTlsBaseOffset();
665 int result = pthread_key_create(&key, NULL);
666 ASSERT_EQ(0, result);
668 LocalStorageKey local_key = PthreadKeyToLocalKey(key);
669 #ifdef V8_FAST_TLS_SUPPORTED
670 // If we just initialized fast TLS support, make sure it works.
671 if (check_fast_tls) CheckFastTls(local_key);
677 void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
678 pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
679 int result = pthread_key_delete(pthread_key);
680 ASSERT_EQ(0, result);
685 void* Thread::GetThreadLocal(LocalStorageKey key) {
686 pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
687 return pthread_getspecific(pthread_key);
691 void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
692 pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
693 int result = pthread_setspecific(pthread_key, value);
694 ASSERT_EQ(0, result);
699 } } // namespace v8::internal