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 <time.h> 17 #include <unistd.h> 18 19 #include <sys/mman.h> 20 #include <sys/resource.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 #undef MAP_TYPE 30 31 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT) 32 #define LOG_TAG "v8" 33 #include <android/log.h> // NOLINT 34 #endif 35 36 #include <cmath> 37 #include <cstdlib> 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 !V8_OS_NACL 58 #include <sys/syscall.h> 59 #endif 60 61 namespace v8 { 62 namespace base { 63 64 namespace { 65 66 // 0 is never a valid thread id. 67 const pthread_t kNoThread = (pthread_t) 0; 68 69 bool g_hard_abort = false; 70 71 const char* g_gc_fake_mmap = NULL; 72 73 } // namespace 74 75 76 int OS::ActivationFrameAlignment() { 77 #if V8_TARGET_ARCH_ARM 78 // On EABI ARM targets this is required for fp correctness in the 79 // runtime system. 80 return 8; 81 #elif V8_TARGET_ARCH_MIPS 82 return 8; 83 #else 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" 89 return 16; 90 #endif 91 } 92 93 94 intptr_t OS::CommitPageSize() { 95 static intptr_t page_size = getpagesize(); 96 return page_size; 97 } 98 99 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); 103 USE(result); 104 DCHECK(result == 0); 105 } 106 107 108 // Get rid of writable permission on code allocations. 109 void OS::ProtectCode(void* address, const size_t size) { 110 #if V8_OS_CYGWIN 111 DWORD old_protect; 112 VirtualProtect(address, size, PAGE_EXECUTE_READ, &old_protect); 113 #elif V8_OS_NACL 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); 117 #else 118 mprotect(address, size, PROT_READ | PROT_EXEC); 119 #endif 120 } 121 122 123 // Create guard pages. 124 void OS::Guard(void* address, const size_t size) { 125 #if V8_OS_CYGWIN 126 DWORD oldprotect; 127 VirtualProtect(address, size, PAGE_NOACCESS, &oldprotect); 128 #else 129 mprotect(address, size, PROT_NONE); 130 #endif 131 } 132 133 134 static LazyInstance<RandomNumberGenerator>::type 135 platform_random_number_generator = LAZY_INSTANCE_INITIALIZER; 136 137 138 void OS::Initialize(int64_t random_seed, bool hard_abort, 139 const char* const gc_fake_mmap) { 140 if (random_seed) { 141 platform_random_number_generator.Pointer()->SetSeed(random_seed); 142 } 143 g_hard_abort = hard_abort; 144 g_gc_fake_mmap = gc_fake_mmap; 145 } 146 147 148 const char* OS::GetGCFakeMMapFile() { 149 return g_gc_fake_mmap; 150 } 151 152 153 void* OS::GetRandomMmapAddr() { 154 #if V8_OS_NACL 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 158 return NULL; 159 #endif 160 #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \ 161 defined(THREAD_SANITIZER) 162 // Dynamic tools do not support custom mmap addresses. 163 return NULL; 164 #endif 165 uintptr_t raw_addr; 166 platform_random_number_generator.Pointer()->NextBytes(&raw_addr, 167 sizeof(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); 173 #else 174 raw_addr &= 0x3ffff000; 175 176 # ifdef __sun 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; 187 # else 188 // The range 0x20000000 - 0x60000000 is relatively unpopulated across a 189 // variety of ASLR modes (PAE kernel, NX compat mode, etc) and on macos 190 // 10.6 and 10.7. 191 raw_addr += 0x20000000; 192 # endif 193 #endif 194 return reinterpret_cast<void*>(raw_addr); 195 } 196 197 198 size_t OS::AllocateAlignment() { 199 return static_cast<size_t>(sysconf(_SC_PAGESIZE)); 200 } 201 202 203 void OS::Sleep(int milliseconds) { 204 useconds_t ms = static_cast<useconds_t>(milliseconds); 205 usleep(1000 * ms); 206 } 207 208 209 void OS::Abort() { 210 if (g_hard_abort) { 211 V8_IMMEDIATE_CRASH(); 212 } 213 // Redirect to std abort to signal abnormal program termination. 214 abort(); 215 } 216 217 218 void OS::DebugBreak() { 219 #if V8_HOST_ARCH_ARM 220 asm("bkpt 0"); 221 #elif V8_HOST_ARCH_ARM64 222 asm("brk 0"); 223 #elif V8_HOST_ARCH_MIPS 224 asm("break"); 225 #elif V8_HOST_ARCH_MIPS64 226 asm("break"); 227 #elif V8_HOST_ARCH_IA32 228 #if V8_OS_NACL 229 asm("hlt"); 230 #else 231 asm("int $3"); 232 #endif // V8_OS_NACL 233 #elif V8_HOST_ARCH_X64 234 asm("int $3"); 235 #else 236 #error Unsupported host architecture. 237 #endif 238 } 239 240 241 // ---------------------------------------------------------------------------- 242 // Math functions 243 244 double OS::nan_value() { 245 // NAN from math.h is defined in C99 and not in POSIX. 246 return NAN; 247 } 248 249 250 int OS::GetCurrentProcessId() { 251 return static_cast<int>(getpid()); 252 } 253 254 255 int OS::GetCurrentThreadId() { 256 #if defined(ANDROID) 257 return static_cast<int>(syscall(__NR_gettid)); 258 #elif defined(SYS_gettid) 259 return static_cast<int>(syscall(SYS_gettid)); 260 #else 261 // PNaCL doesn't have a way to get an integral thread ID, but it doesn't 262 // really matter, because we only need it in PerfJitLogger::LogRecordedBuffer. 263 return 0; 264 #endif 265 } 266 267 268 // ---------------------------------------------------------------------------- 269 // POSIX date/time support. 270 // 271 272 int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) { 273 #if V8_OS_NACL 274 // Optionally used in Logger::ResourceEvent. 275 return -1; 276 #else 277 struct rusage usage; 278 279 if (getrusage(RUSAGE_SELF, &usage) < 0) return -1; 280 *secs = usage.ru_utime.tv_sec; 281 *usecs = usage.ru_utime.tv_usec; 282 return 0; 283 #endif 284 } 285 286 287 double OS::TimeCurrentMillis() { 288 return Time::Now().ToJsTime(); 289 } 290 291 292 class TimezoneCache {}; 293 294 295 TimezoneCache* OS::CreateTimezoneCache() { 296 return NULL; 297 } 298 299 300 void OS::DisposeTimezoneCache(TimezoneCache* cache) { 301 DCHECK(cache == NULL); 302 } 303 304 305 void OS::ClearTimezoneCache(TimezoneCache* cache) { 306 DCHECK(cache == NULL); 307 } 308 309 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; 316 } 317 318 319 int OS::GetLastError() { 320 return errno; 321 } 322 323 324 // ---------------------------------------------------------------------------- 325 // POSIX stdio support. 326 // 327 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; 335 fclose(file); 336 return NULL; 337 } 338 339 340 bool OS::Remove(const char* path) { 341 return (remove(path) == 0); 342 } 343 344 345 FILE* OS::OpenTemporaryFile() { 346 return tmpfile(); 347 } 348 349 350 const char* const OS::LogFileOpenMode = "w"; 351 352 353 void OS::Print(const char* format, ...) { 354 va_list args; 355 va_start(args, format); 356 VPrint(format, args); 357 va_end(args); 358 } 359 360 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); 364 #else 365 vprintf(format, args); 366 #endif 367 } 368 369 370 void OS::FPrint(FILE* out, const char* format, ...) { 371 va_list args; 372 va_start(args, format); 373 VFPrint(out, format, args); 374 va_end(args); 375 } 376 377 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); 381 #else 382 vfprintf(out, format, args); 383 #endif 384 } 385 386 387 void OS::PrintError(const char* format, ...) { 388 va_list args; 389 va_start(args, format); 390 VPrintError(format, args); 391 va_end(args); 392 } 393 394 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); 398 #else 399 vfprintf(stderr, format, args); 400 #endif 401 } 402 403 404 int OS::SNPrintF(char* str, int length, const char* format, ...) { 405 va_list args; 406 va_start(args, format); 407 int result = VSNPrintF(str, length, format, args); 408 va_end(args); 409 return result; 410 } 411 412 413 int OS::VSNPrintF(char* str, 414 int length, 415 const char* format, 416 va_list args) { 417 int n = vsnprintf(str, length, format, args); 418 if (n < 0 || n >= length) { 419 // If the length is zero, the assignment fails. 420 if (length > 0) 421 str[length - 1] = '\0'; 422 return -1; 423 } else { 424 return n; 425 } 426 } 427 428 429 // ---------------------------------------------------------------------------- 430 // POSIX string support. 431 // 432 433 char* OS::StrChr(char* str, int c) { 434 return strchr(str, c); 435 } 436 437 438 void OS::StrNCpy(char* dest, int length, const char* src, size_t n) { 439 strncpy(dest, src, n); 440 } 441 442 443 // ---------------------------------------------------------------------------- 444 // POSIX thread support. 445 // 446 447 class Thread::PlatformData { 448 public: 449 PlatformData() : thread_(kNoThread) {} 450 pthread_t thread_; // Thread handle for pthread. 451 // Synchronizes thread creation 452 Mutex thread_creation_mutex_; 453 }; 454 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; 461 } 462 set_name(options.name()); 463 } 464 465 466 Thread::~Thread() { 467 delete data_; 468 } 469 470 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); 474 #elif V8_OS_NETBSD 475 STATIC_ASSERT(Thread::kMaxThreadNameLength <= PTHREAD_MAX_NAMELEN_NP); 476 pthread_setname_np(pthread_self(), "%s", name); 477 #elif V8_OS_MACOSX 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) 484 return; 485 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) 491 prctl(PR_SET_NAME, 492 reinterpret_cast<unsigned long>(name), // NOLINT 493 0, 0, 0); 494 #endif 495 } 496 497 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 502 // one). 503 { LockGuard<Mutex> lock_guard(&thread->data()->thread_creation_mutex_); } 504 SetThreadName(thread->name()); 505 DCHECK(thread->data()->thread_ != kNoThread); 506 thread->NotifyStartedAndRun(); 507 return NULL; 508 } 509 510 511 void Thread::set_name(const char* name) { 512 strncpy(name_, name, sizeof(name_)); 513 name_[sizeof(name_) - 1] = '\0'; 514 } 515 516 517 void Thread::Start() { 518 int result; 519 pthread_attr_t attr; 520 memset(&attr, 0, sizeof(attr)); 521 result = pthread_attr_init(&attr); 522 DCHECK_EQ(0, result); 523 // Native client uses default stack size. 524 #if !V8_OS_NACL 525 if (stack_size_ > 0) { 526 result = pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_)); 527 DCHECK_EQ(0, result); 528 } 529 #endif 530 { 531 LockGuard<Mutex> lock_guard(&data_->thread_creation_mutex_); 532 result = pthread_create(&data_->thread_, &attr, ThreadEntry, this); 533 } 534 DCHECK_EQ(0, result); 535 result = pthread_attr_destroy(&attr); 536 DCHECK_EQ(0, result); 537 DCHECK(data_->thread_ != kNoThread); 538 USE(result); 539 } 540 541 542 void Thread::Join() { 543 pthread_join(data_->thread_, NULL); 544 } 545 546 547 void Thread::YieldCPU() { 548 int result = sched_yield(); 549 DCHECK_EQ(0, result); 550 USE(result); 551 } 552 553 554 static Thread::LocalStorageKey PthreadKeyToLocalKey(pthread_key_t pthread_key) { 555 #if V8_OS_CYGWIN 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); 562 #else 563 return static_cast<Thread::LocalStorageKey>(pthread_key); 564 #endif 565 } 566 567 568 static pthread_key_t LocalKeyToPthreadKey(Thread::LocalStorageKey local_key) { 569 #if V8_OS_CYGWIN 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); 573 #else 574 return static_cast<pthread_key_t>(local_key); 575 #endif 576 } 577 578 579 #ifdef V8_FAST_TLS_SUPPORTED 580 581 static Atomic32 tls_base_offset_initialized = 0; 582 intptr_t kMacTlsBaseOffset = 0; 583 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"); 593 } 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, '.'); 599 *period_pos = '\0'; 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 606 // same offsets. 607 #if V8_HOST_ARCH_IA32 608 kMacTlsBaseOffset = 0x48; 609 #else 610 kMacTlsBaseOffset = 0x60; 611 #endif 612 } else { 613 // 11.x.x (Lion) changed the offset. 614 kMacTlsBaseOffset = 0; 615 } 616 617 Release_Store(&tls_base_offset_initialized, 1); 618 } 619 620 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"); 628 } 629 Thread::SetThreadLocal(key, NULL); 630 } 631 632 #endif // V8_FAST_TLS_SUPPORTED 633 634 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(); 641 } 642 #endif 643 pthread_key_t key; 644 int result = pthread_key_create(&key, NULL); 645 DCHECK_EQ(0, result); 646 USE(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); 651 #endif 652 return local_key; 653 } 654 655 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); 660 USE(result); 661 } 662 663 664 void* Thread::GetThreadLocal(LocalStorageKey key) { 665 pthread_key_t pthread_key = LocalKeyToPthreadKey(key); 666 return pthread_getspecific(pthread_key); 667 } 668 669 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); 674 USE(result); 675 } 676 677 678 } } // namespace v8::base 679