1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 // Platform specific code for POSIX goes here. This is not a platform on its 29 // own but contains the parts which are the same across POSIX platforms Linux, 30 // Mac OS, FreeBSD and OpenBSD. 31 32 #include <dlfcn.h> 33 #include <pthread.h> 34 #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) 35 #include <pthread_np.h> // for pthread_set_name_np 36 #endif 37 #include <sched.h> // for sched_yield 38 #include <unistd.h> 39 #include <errno.h> 40 #include <time.h> 41 42 #include <sys/mman.h> 43 #include <sys/socket.h> 44 #include <sys/resource.h> 45 #include <sys/time.h> 46 #include <sys/types.h> 47 #include <sys/stat.h> 48 #if defined(__linux__) 49 #include <sys/prctl.h> // for prctl 50 #endif 51 #if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || \ 52 defined(__NetBSD__) || defined(__OpenBSD__) 53 #include <sys/sysctl.h> // for sysctl 54 #endif 55 56 #include <arpa/inet.h> 57 #include <netinet/in.h> 58 #include <netdb.h> 59 60 #undef MAP_TYPE 61 62 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT) 63 #define LOG_TAG "v8" 64 #include <android/log.h> 65 #endif 66 67 #include "v8.h" 68 69 #include "codegen.h" 70 #include "isolate-inl.h" 71 #include "platform.h" 72 73 namespace v8 { 74 namespace internal { 75 76 // 0 is never a valid thread id. 77 static const pthread_t kNoThread = (pthread_t) 0; 78 79 80 uint64_t OS::CpuFeaturesImpliedByPlatform() { 81 #if V8_OS_MACOSX 82 // Mac OS X requires all these to install so we can assume they are present. 83 // These constants are defined by the CPUid instructions. 84 const uint64_t one = 1; 85 return (one << SSE2) | (one << CMOV); 86 #else 87 return 0; // Nothing special about the other systems. 88 #endif 89 } 90 91 92 // Maximum size of the virtual memory. 0 means there is no artificial 93 // limit. 94 95 intptr_t OS::MaxVirtualMemory() { 96 struct rlimit limit; 97 int result = getrlimit(RLIMIT_DATA, &limit); 98 if (result != 0) return 0; 99 return limit.rlim_cur; 100 } 101 102 103 uint64_t OS::TotalPhysicalMemory() { 104 #if V8_OS_MACOSX 105 int mib[2]; 106 mib[0] = CTL_HW; 107 mib[1] = HW_MEMSIZE; 108 int64_t size = 0; 109 size_t len = sizeof(size); 110 if (sysctl(mib, 2, &size, &len, NULL, 0) != 0) { 111 UNREACHABLE(); 112 return 0; 113 } 114 return static_cast<uint64_t>(size); 115 #elif V8_OS_FREEBSD 116 int pages, page_size; 117 size_t size = sizeof(pages); 118 sysctlbyname("vm.stats.vm.v_page_count", &pages, &size, NULL, 0); 119 sysctlbyname("vm.stats.vm.v_page_size", &page_size, &size, NULL, 0); 120 if (pages == -1 || page_size == -1) { 121 UNREACHABLE(); 122 return 0; 123 } 124 return static_cast<uint64_t>(pages) * page_size; 125 #elif V8_OS_CYGWIN 126 MEMORYSTATUS memory_info; 127 memory_info.dwLength = sizeof(memory_info); 128 if (!GlobalMemoryStatus(&memory_info)) { 129 UNREACHABLE(); 130 return 0; 131 } 132 return static_cast<uint64_t>(memory_info.dwTotalPhys); 133 #else 134 intptr_t pages = sysconf(_SC_PHYS_PAGES); 135 intptr_t page_size = sysconf(_SC_PAGESIZE); 136 if (pages == -1 || page_size == -1) { 137 UNREACHABLE(); 138 return 0; 139 } 140 return static_cast<uint64_t>(pages) * page_size; 141 #endif 142 } 143 144 145 int OS::ActivationFrameAlignment() { 146 #if V8_TARGET_ARCH_ARM 147 // On EABI ARM targets this is required for fp correctness in the 148 // runtime system. 149 return 8; 150 #elif V8_TARGET_ARCH_MIPS 151 return 8; 152 #else 153 // Otherwise we just assume 16 byte alignment, i.e.: 154 // - With gcc 4.4 the tree vectorization optimizer can generate code 155 // that requires 16 byte alignment such as movdqa on x86. 156 // - Mac OS X and Solaris (64-bit) activation frames must be 16 byte-aligned; 157 // see "Mac OS X ABI Function Call Guide" 158 return 16; 159 #endif 160 } 161 162 163 intptr_t OS::CommitPageSize() { 164 static intptr_t page_size = getpagesize(); 165 return page_size; 166 } 167 168 169 void OS::Free(void* address, const size_t size) { 170 // TODO(1240712): munmap has a return value which is ignored here. 171 int result = munmap(address, size); 172 USE(result); 173 ASSERT(result == 0); 174 } 175 176 177 // Get rid of writable permission on code allocations. 178 void OS::ProtectCode(void* address, const size_t size) { 179 #if defined(__CYGWIN__) 180 DWORD old_protect; 181 VirtualProtect(address, size, PAGE_EXECUTE_READ, &old_protect); 182 #elif defined(__native_client__) 183 // The Native Client port of V8 uses an interpreter, so 184 // code pages don't need PROT_EXEC. 185 mprotect(address, size, PROT_READ); 186 #else 187 mprotect(address, size, PROT_READ | PROT_EXEC); 188 #endif 189 } 190 191 192 // Create guard pages. 193 void OS::Guard(void* address, const size_t size) { 194 #if defined(__CYGWIN__) 195 DWORD oldprotect; 196 VirtualProtect(address, size, PAGE_NOACCESS, &oldprotect); 197 #else 198 mprotect(address, size, PROT_NONE); 199 #endif 200 } 201 202 203 void* OS::GetRandomMmapAddr() { 204 #if defined(__native_client__) 205 // TODO(bradchen): restore randomization once Native Client gets 206 // smarter about using mmap address hints. 207 // See http://code.google.com/p/nativeclient/issues/3341 208 return NULL; 209 #endif 210 Isolate* isolate = Isolate::UncheckedCurrent(); 211 // Note that the current isolate isn't set up in a call path via 212 // CpuFeatures::Probe. We don't care about randomization in this case because 213 // the code page is immediately freed. 214 if (isolate != NULL) { 215 uintptr_t raw_addr; 216 isolate->random_number_generator()->NextBytes(&raw_addr, sizeof(raw_addr)); 217 #if V8_TARGET_ARCH_X64 218 // Currently available CPUs have 48 bits of virtual addressing. Truncate 219 // the hint address to 46 bits to give the kernel a fighting chance of 220 // fulfilling our placement request. 221 raw_addr &= V8_UINT64_C(0x3ffffffff000); 222 #else 223 raw_addr &= 0x3ffff000; 224 225 # ifdef __sun 226 // For our Solaris/illumos mmap hint, we pick a random address in the bottom 227 // half of the top half of the address space (that is, the third quarter). 228 // Because we do not MAP_FIXED, this will be treated only as a hint -- the 229 // system will not fail to mmap() because something else happens to already 230 // be mapped at our random address. We deliberately set the hint high enough 231 // to get well above the system's break (that is, the heap); Solaris and 232 // illumos will try the hint and if that fails allocate as if there were 233 // no hint at all. The high hint prevents the break from getting hemmed in 234 // at low values, ceding half of the address space to the system heap. 235 raw_addr += 0x80000000; 236 # else 237 // The range 0x20000000 - 0x60000000 is relatively unpopulated across a 238 // variety of ASLR modes (PAE kernel, NX compat mode, etc) and on macos 239 // 10.6 and 10.7. 240 raw_addr += 0x20000000; 241 # endif 242 #endif 243 return reinterpret_cast<void*>(raw_addr); 244 } 245 return NULL; 246 } 247 248 249 size_t OS::AllocateAlignment() { 250 return getpagesize(); 251 } 252 253 254 void OS::Sleep(int milliseconds) { 255 useconds_t ms = static_cast<useconds_t>(milliseconds); 256 usleep(1000 * ms); 257 } 258 259 260 void OS::Abort() { 261 // Redirect to std abort to signal abnormal program termination. 262 if (FLAG_break_on_abort) { 263 DebugBreak(); 264 } 265 abort(); 266 } 267 268 269 void OS::DebugBreak() { 270 #if V8_HOST_ARCH_ARM 271 asm("bkpt 0"); 272 #elif V8_HOST_ARCH_MIPS 273 asm("break"); 274 #elif V8_HOST_ARCH_IA32 275 #if defined(__native_client__) 276 asm("hlt"); 277 #else 278 asm("int $3"); 279 #endif // __native_client__ 280 #elif V8_HOST_ARCH_X64 281 asm("int $3"); 282 #else 283 #error Unsupported host architecture. 284 #endif 285 } 286 287 288 // ---------------------------------------------------------------------------- 289 // Math functions 290 291 double modulo(double x, double y) { 292 return fmod(x, y); 293 } 294 295 296 #define UNARY_MATH_FUNCTION(name, generator) \ 297 static UnaryMathFunction fast_##name##_function = NULL; \ 298 void init_fast_##name##_function() { \ 299 fast_##name##_function = generator; \ 300 } \ 301 double fast_##name(double x) { \ 302 return (*fast_##name##_function)(x); \ 303 } 304 305 UNARY_MATH_FUNCTION(sin, CreateTranscendentalFunction(TranscendentalCache::SIN)) 306 UNARY_MATH_FUNCTION(cos, CreateTranscendentalFunction(TranscendentalCache::COS)) 307 UNARY_MATH_FUNCTION(tan, CreateTranscendentalFunction(TranscendentalCache::TAN)) 308 UNARY_MATH_FUNCTION(log, CreateTranscendentalFunction(TranscendentalCache::LOG)) 309 UNARY_MATH_FUNCTION(exp, CreateExpFunction()) 310 UNARY_MATH_FUNCTION(sqrt, CreateSqrtFunction()) 311 312 #undef UNARY_MATH_FUNCTION 313 314 315 void lazily_initialize_fast_exp() { 316 if (fast_exp_function == NULL) { 317 init_fast_exp_function(); 318 } 319 } 320 321 322 double OS::nan_value() { 323 // NAN from math.h is defined in C99 and not in POSIX. 324 return NAN; 325 } 326 327 328 int OS::GetCurrentProcessId() { 329 return static_cast<int>(getpid()); 330 } 331 332 333 // ---------------------------------------------------------------------------- 334 // POSIX date/time support. 335 // 336 337 int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) { 338 struct rusage usage; 339 340 if (getrusage(RUSAGE_SELF, &usage) < 0) return -1; 341 *secs = usage.ru_utime.tv_sec; 342 *usecs = usage.ru_utime.tv_usec; 343 return 0; 344 } 345 346 347 double OS::TimeCurrentMillis() { 348 return Time::Now().ToJsTime(); 349 } 350 351 352 double OS::DaylightSavingsOffset(double time) { 353 if (std::isnan(time)) return nan_value(); 354 time_t tv = static_cast<time_t>(floor(time/msPerSecond)); 355 struct tm* t = localtime(&tv); 356 if (NULL == t) return nan_value(); 357 return t->tm_isdst > 0 ? 3600 * msPerSecond : 0; 358 } 359 360 361 int OS::GetLastError() { 362 return errno; 363 } 364 365 366 // ---------------------------------------------------------------------------- 367 // POSIX stdio support. 368 // 369 370 FILE* OS::FOpen(const char* path, const char* mode) { 371 FILE* file = fopen(path, mode); 372 if (file == NULL) return NULL; 373 struct stat file_stat; 374 if (fstat(fileno(file), &file_stat) != 0) return NULL; 375 bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0); 376 if (is_regular_file) return file; 377 fclose(file); 378 return NULL; 379 } 380 381 382 bool OS::Remove(const char* path) { 383 return (remove(path) == 0); 384 } 385 386 387 FILE* OS::OpenTemporaryFile() { 388 return tmpfile(); 389 } 390 391 392 const char* const OS::LogFileOpenMode = "w"; 393 394 395 void OS::Print(const char* format, ...) { 396 va_list args; 397 va_start(args, format); 398 VPrint(format, args); 399 va_end(args); 400 } 401 402 403 void OS::VPrint(const char* format, va_list args) { 404 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT) 405 __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args); 406 #else 407 vprintf(format, args); 408 #endif 409 } 410 411 412 void OS::FPrint(FILE* out, const char* format, ...) { 413 va_list args; 414 va_start(args, format); 415 VFPrint(out, format, args); 416 va_end(args); 417 } 418 419 420 void OS::VFPrint(FILE* out, const char* format, va_list args) { 421 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT) 422 __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args); 423 #else 424 vfprintf(out, format, args); 425 #endif 426 } 427 428 429 void OS::PrintError(const char* format, ...) { 430 va_list args; 431 va_start(args, format); 432 VPrintError(format, args); 433 va_end(args); 434 } 435 436 437 void OS::VPrintError(const char* format, va_list args) { 438 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT) 439 __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, format, args); 440 #else 441 vfprintf(stderr, format, args); 442 #endif 443 } 444 445 446 int OS::SNPrintF(Vector<char> str, const char* format, ...) { 447 va_list args; 448 va_start(args, format); 449 int result = VSNPrintF(str, format, args); 450 va_end(args); 451 return result; 452 } 453 454 455 int OS::VSNPrintF(Vector<char> str, 456 const char* format, 457 va_list args) { 458 int n = vsnprintf(str.start(), str.length(), format, args); 459 if (n < 0 || n >= str.length()) { 460 // If the length is zero, the assignment fails. 461 if (str.length() > 0) 462 str[str.length() - 1] = '\0'; 463 return -1; 464 } else { 465 return n; 466 } 467 } 468 469 470 #if V8_TARGET_ARCH_IA32 471 static void MemMoveWrapper(void* dest, const void* src, size_t size) { 472 memmove(dest, src, size); 473 } 474 475 476 // Initialize to library version so we can call this at any time during startup. 477 static OS::MemMoveFunction memmove_function = &MemMoveWrapper; 478 479 // Defined in codegen-ia32.cc. 480 OS::MemMoveFunction CreateMemMoveFunction(); 481 482 // Copy memory area. No restrictions. 483 void OS::MemMove(void* dest, const void* src, size_t size) { 484 if (size == 0) return; 485 // Note: here we rely on dependent reads being ordered. This is true 486 // on all architectures we currently support. 487 (*memmove_function)(dest, src, size); 488 } 489 490 #elif defined(V8_HOST_ARCH_ARM) 491 void OS::MemCopyUint16Uint8Wrapper(uint16_t* dest, 492 const uint8_t* src, 493 size_t chars) { 494 uint16_t *limit = dest + chars; 495 while (dest < limit) { 496 *dest++ = static_cast<uint16_t>(*src++); 497 } 498 } 499 500 501 OS::MemCopyUint8Function OS::memcopy_uint8_function = &OS::MemCopyUint8Wrapper; 502 OS::MemCopyUint16Uint8Function OS::memcopy_uint16_uint8_function = 503 &OS::MemCopyUint16Uint8Wrapper; 504 // Defined in codegen-arm.cc. 505 OS::MemCopyUint8Function CreateMemCopyUint8Function( 506 OS::MemCopyUint8Function stub); 507 OS::MemCopyUint16Uint8Function CreateMemCopyUint16Uint8Function( 508 OS::MemCopyUint16Uint8Function stub); 509 #endif 510 511 512 void OS::PostSetUp() { 513 #if V8_TARGET_ARCH_IA32 514 OS::MemMoveFunction generated_memmove = CreateMemMoveFunction(); 515 if (generated_memmove != NULL) { 516 memmove_function = generated_memmove; 517 } 518 #elif defined(V8_HOST_ARCH_ARM) 519 OS::memcopy_uint8_function = 520 CreateMemCopyUint8Function(&OS::MemCopyUint8Wrapper); 521 OS::memcopy_uint16_uint8_function = 522 CreateMemCopyUint16Uint8Function(&OS::MemCopyUint16Uint8Wrapper); 523 #endif 524 init_fast_sin_function(); 525 init_fast_cos_function(); 526 init_fast_tan_function(); 527 init_fast_log_function(); 528 // fast_exp is initialized lazily. 529 init_fast_sqrt_function(); 530 } 531 532 533 // ---------------------------------------------------------------------------- 534 // POSIX string support. 535 // 536 537 char* OS::StrChr(char* str, int c) { 538 return strchr(str, c); 539 } 540 541 542 void OS::StrNCpy(Vector<char> dest, const char* src, size_t n) { 543 strncpy(dest.start(), src, n); 544 } 545 546 547 // ---------------------------------------------------------------------------- 548 // POSIX thread support. 549 // 550 551 class Thread::PlatformData : public Malloced { 552 public: 553 PlatformData() : thread_(kNoThread) {} 554 pthread_t thread_; // Thread handle for pthread. 555 }; 556 557 Thread::Thread(const Options& options) 558 : data_(new PlatformData), 559 stack_size_(options.stack_size()), 560 start_semaphore_(NULL) { 561 if (stack_size_ > 0 && stack_size_ < PTHREAD_STACK_MIN) { 562 stack_size_ = PTHREAD_STACK_MIN; 563 } 564 set_name(options.name()); 565 } 566 567 568 Thread::~Thread() { 569 delete data_; 570 } 571 572 573 static void SetThreadName(const char* name) { 574 #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) 575 pthread_set_name_np(pthread_self(), name); 576 #elif defined(__NetBSD__) 577 STATIC_ASSERT(Thread::kMaxThreadNameLength <= PTHREAD_MAX_NAMELEN_NP); 578 pthread_setname_np(pthread_self(), "%s", name); 579 #elif defined(__APPLE__) 580 // pthread_setname_np is only available in 10.6 or later, so test 581 // for it at runtime. 582 int (*dynamic_pthread_setname_np)(const char*); 583 *reinterpret_cast<void**>(&dynamic_pthread_setname_np) = 584 dlsym(RTLD_DEFAULT, "pthread_setname_np"); 585 if (dynamic_pthread_setname_np == NULL) 586 return; 587 588 // Mac OS X does not expose the length limit of the name, so hardcode it. 589 static const int kMaxNameLength = 63; 590 STATIC_ASSERT(Thread::kMaxThreadNameLength <= kMaxNameLength); 591 dynamic_pthread_setname_np(name); 592 #elif defined(PR_SET_NAME) 593 prctl(PR_SET_NAME, 594 reinterpret_cast<unsigned long>(name), // NOLINT 595 0, 0, 0); 596 #endif 597 } 598 599 600 static void* ThreadEntry(void* arg) { 601 Thread* thread = reinterpret_cast<Thread*>(arg); 602 // This is also initialized by the first argument to pthread_create() but we 603 // don't know which thread will run first (the original thread or the new 604 // one) so we initialize it here too. 605 thread->data()->thread_ = pthread_self(); 606 SetThreadName(thread->name()); 607 ASSERT(thread->data()->thread_ != kNoThread); 608 thread->NotifyStartedAndRun(); 609 return NULL; 610 } 611 612 613 void Thread::set_name(const char* name) { 614 strncpy(name_, name, sizeof(name_)); 615 name_[sizeof(name_) - 1] = '\0'; 616 } 617 618 619 void Thread::Start() { 620 int result; 621 pthread_attr_t attr; 622 memset(&attr, 0, sizeof(attr)); 623 result = pthread_attr_init(&attr); 624 ASSERT_EQ(0, result); 625 // Native client uses default stack size. 626 #if !defined(__native_client__) 627 if (stack_size_ > 0) { 628 result = pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_)); 629 ASSERT_EQ(0, result); 630 } 631 #endif 632 result = pthread_create(&data_->thread_, &attr, ThreadEntry, this); 633 ASSERT_EQ(0, result); 634 result = pthread_attr_destroy(&attr); 635 ASSERT_EQ(0, result); 636 ASSERT(data_->thread_ != kNoThread); 637 USE(result); 638 } 639 640 641 void Thread::Join() { 642 pthread_join(data_->thread_, NULL); 643 } 644 645 646 void Thread::YieldCPU() { 647 int result = sched_yield(); 648 ASSERT_EQ(0, result); 649 USE(result); 650 } 651 652 653 static Thread::LocalStorageKey PthreadKeyToLocalKey(pthread_key_t pthread_key) { 654 #if defined(__CYGWIN__) 655 // We need to cast pthread_key_t to Thread::LocalStorageKey in two steps 656 // because pthread_key_t is a pointer type on Cygwin. This will probably not 657 // work on 64-bit platforms, but Cygwin doesn't support 64-bit anyway. 658 STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t)); 659 intptr_t ptr_key = reinterpret_cast<intptr_t>(pthread_key); 660 return static_cast<Thread::LocalStorageKey>(ptr_key); 661 #else 662 return static_cast<Thread::LocalStorageKey>(pthread_key); 663 #endif 664 } 665 666 667 static pthread_key_t LocalKeyToPthreadKey(Thread::LocalStorageKey local_key) { 668 #if defined(__CYGWIN__) 669 STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t)); 670 intptr_t ptr_key = static_cast<intptr_t>(local_key); 671 return reinterpret_cast<pthread_key_t>(ptr_key); 672 #else 673 return static_cast<pthread_key_t>(local_key); 674 #endif 675 } 676 677 678 #ifdef V8_FAST_TLS_SUPPORTED 679 680 static Atomic32 tls_base_offset_initialized = 0; 681 intptr_t kMacTlsBaseOffset = 0; 682 683 // It's safe to do the initialization more that once, but it has to be 684 // done at least once. 685 static void InitializeTlsBaseOffset() { 686 const size_t kBufferSize = 128; 687 char buffer[kBufferSize]; 688 size_t buffer_size = kBufferSize; 689 int ctl_name[] = { CTL_KERN , KERN_OSRELEASE }; 690 if (sysctl(ctl_name, 2, buffer, &buffer_size, NULL, 0) != 0) { 691 V8_Fatal(__FILE__, __LINE__, "V8 failed to get kernel version"); 692 } 693 // The buffer now contains a string of the form XX.YY.ZZ, where 694 // XX is the major kernel version component. 695 // Make sure the buffer is 0-terminated. 696 buffer[kBufferSize - 1] = '\0'; 697 char* period_pos = strchr(buffer, '.'); 698 *period_pos = '\0'; 699 int kernel_version_major = 700 static_cast<int>(strtol(buffer, NULL, 10)); // NOLINT 701 // The constants below are taken from pthreads.s from the XNU kernel 702 // sources archive at www.opensource.apple.com. 703 if (kernel_version_major < 11) { 704 // 8.x.x (Tiger), 9.x.x (Leopard), 10.x.x (Snow Leopard) have the 705 // same offsets. 706 #if V8_HOST_ARCH_IA32 707 kMacTlsBaseOffset = 0x48; 708 #else 709 kMacTlsBaseOffset = 0x60; 710 #endif 711 } else { 712 // 11.x.x (Lion) changed the offset. 713 kMacTlsBaseOffset = 0; 714 } 715 716 Release_Store(&tls_base_offset_initialized, 1); 717 } 718 719 720 static void CheckFastTls(Thread::LocalStorageKey key) { 721 void* expected = reinterpret_cast<void*>(0x1234CAFE); 722 Thread::SetThreadLocal(key, expected); 723 void* actual = Thread::GetExistingThreadLocal(key); 724 if (expected != actual) { 725 V8_Fatal(__FILE__, __LINE__, 726 "V8 failed to initialize fast TLS on current kernel"); 727 } 728 Thread::SetThreadLocal(key, NULL); 729 } 730 731 #endif // V8_FAST_TLS_SUPPORTED 732 733 734 Thread::LocalStorageKey Thread::CreateThreadLocalKey() { 735 #ifdef V8_FAST_TLS_SUPPORTED 736 bool check_fast_tls = false; 737 if (tls_base_offset_initialized == 0) { 738 check_fast_tls = true; 739 InitializeTlsBaseOffset(); 740 } 741 #endif 742 pthread_key_t key; 743 int result = pthread_key_create(&key, NULL); 744 ASSERT_EQ(0, result); 745 USE(result); 746 LocalStorageKey local_key = PthreadKeyToLocalKey(key); 747 #ifdef V8_FAST_TLS_SUPPORTED 748 // If we just initialized fast TLS support, make sure it works. 749 if (check_fast_tls) CheckFastTls(local_key); 750 #endif 751 return local_key; 752 } 753 754 755 void Thread::DeleteThreadLocalKey(LocalStorageKey key) { 756 pthread_key_t pthread_key = LocalKeyToPthreadKey(key); 757 int result = pthread_key_delete(pthread_key); 758 ASSERT_EQ(0, result); 759 USE(result); 760 } 761 762 763 void* Thread::GetThreadLocal(LocalStorageKey key) { 764 pthread_key_t pthread_key = LocalKeyToPthreadKey(key); 765 return pthread_getspecific(pthread_key); 766 } 767 768 769 void Thread::SetThreadLocal(LocalStorageKey key, void* value) { 770 pthread_key_t pthread_key = LocalKeyToPthreadKey(key); 771 int result = pthread_setspecific(pthread_key, value); 772 ASSERT_EQ(0, result); 773 USE(result); 774 } 775 776 777 } } // namespace v8::internal 778