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 <stdio.h> 17 #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 #ifndef _AIX 59 #include <sys/syscall.h> 60 #endif 61 62 namespace v8 { 63 namespace base { 64 65 namespace { 66 67 // 0 is never a valid thread id. 68 const pthread_t kNoThread = (pthread_t) 0; 69 70 bool g_hard_abort = false; 71 72 const char* g_gc_fake_mmap = NULL; 73 74 } // namespace 75 76 77 int 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 #elif V8_TARGET_ARCH_S390 85 return 8; 86 #else 87 // Otherwise we just assume 16 byte alignment, i.e.: 88 // - With gcc 4.4 the tree vectorization optimizer can generate code 89 // that requires 16 byte alignment such as movdqa on x86. 90 // - Mac OS X, PPC and Solaris (64-bit) activation frames must 91 // be 16 byte-aligned; see "Mac OS X ABI Function Call Guide" 92 return 16; 93 #endif 94 } 95 96 97 intptr_t OS::CommitPageSize() { 98 static intptr_t page_size = getpagesize(); 99 return page_size; 100 } 101 102 void* OS::AllocateGuarded(const size_t requested) { 103 size_t allocated = 0; 104 const bool is_executable = false; 105 void* mbase = OS::Allocate(requested, &allocated, is_executable); 106 if (allocated != requested) { 107 OS::Free(mbase, allocated); 108 return nullptr; 109 } 110 if (mbase == nullptr) { 111 return nullptr; 112 } 113 OS::Guard(mbase, requested); 114 return mbase; 115 } 116 117 void OS::Free(void* address, const size_t size) { 118 // TODO(1240712): munmap has a return value which is ignored here. 119 int result = munmap(address, size); 120 USE(result); 121 DCHECK(result == 0); 122 } 123 124 125 // Get rid of writable permission on code allocations. 126 void OS::ProtectCode(void* address, const size_t size) { 127 #if V8_OS_CYGWIN 128 DWORD old_protect; 129 VirtualProtect(address, size, PAGE_EXECUTE_READ, &old_protect); 130 #else 131 mprotect(address, size, PROT_READ | PROT_EXEC); 132 #endif 133 } 134 135 136 // Create guard pages. 137 void OS::Guard(void* address, const size_t size) { 138 #if V8_OS_CYGWIN 139 DWORD oldprotect; 140 VirtualProtect(address, size, PAGE_NOACCESS, &oldprotect); 141 #else 142 mprotect(address, size, PROT_NONE); 143 #endif 144 } 145 146 // Make a region of memory readable and writable. 147 void OS::Unprotect(void* address, const size_t size) { 148 #if V8_OS_CYGWIN 149 DWORD oldprotect; 150 VirtualProtect(address, size, PAGE_READWRITE, &oldprotect); 151 #else 152 mprotect(address, size, PROT_READ | PROT_WRITE); 153 #endif 154 } 155 156 static LazyInstance<RandomNumberGenerator>::type 157 platform_random_number_generator = LAZY_INSTANCE_INITIALIZER; 158 159 160 void OS::Initialize(int64_t random_seed, bool hard_abort, 161 const char* const gc_fake_mmap) { 162 if (random_seed) { 163 platform_random_number_generator.Pointer()->SetSeed(random_seed); 164 } 165 g_hard_abort = hard_abort; 166 g_gc_fake_mmap = gc_fake_mmap; 167 } 168 169 170 const char* OS::GetGCFakeMMapFile() { 171 return g_gc_fake_mmap; 172 } 173 174 175 void* OS::GetRandomMmapAddr() { 176 #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \ 177 defined(THREAD_SANITIZER) 178 // Dynamic tools do not support custom mmap addresses. 179 return NULL; 180 #endif 181 uintptr_t raw_addr; 182 platform_random_number_generator.Pointer()->NextBytes(&raw_addr, 183 sizeof(raw_addr)); 184 #if V8_TARGET_ARCH_X64 185 // Currently available CPUs have 48 bits of virtual addressing. Truncate 186 // the hint address to 46 bits to give the kernel a fighting chance of 187 // fulfilling our placement request. 188 raw_addr &= V8_UINT64_C(0x3ffffffff000); 189 #elif V8_TARGET_ARCH_PPC64 190 #if V8_OS_AIX 191 // AIX: 64 bits of virtual addressing, but we limit address range to: 192 // a) minimize Segment Lookaside Buffer (SLB) misses and 193 raw_addr &= V8_UINT64_C(0x3ffff000); 194 // Use extra address space to isolate the mmap regions. 195 raw_addr += V8_UINT64_C(0x400000000000); 196 #elif V8_TARGET_BIG_ENDIAN 197 // Big-endian Linux: 44 bits of virtual addressing. 198 raw_addr &= V8_UINT64_C(0x03fffffff000); 199 #else 200 // Little-endian Linux: 48 bits of virtual addressing. 201 raw_addr &= V8_UINT64_C(0x3ffffffff000); 202 #endif 203 #elif V8_TARGET_ARCH_S390X 204 // Linux on Z uses bits 22-32 for Region Indexing, which translates to 42 bits 205 // of virtual addressing. Truncate to 40 bits to allow kernel chance to 206 // fulfill request. 207 raw_addr &= V8_UINT64_C(0xfffffff000); 208 #elif V8_TARGET_ARCH_S390 209 // 31 bits of virtual addressing. Truncate to 29 bits to allow kernel chance 210 // to fulfill request. 211 raw_addr &= 0x1ffff000; 212 #else 213 raw_addr &= 0x3ffff000; 214 215 # ifdef __sun 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; 226 #elif V8_OS_AIX 227 // The range 0x30000000 - 0xD0000000 is available on AIX; 228 // choose the upper range. 229 raw_addr += 0x90000000; 230 # else 231 // The range 0x20000000 - 0x60000000 is relatively unpopulated across a 232 // variety of ASLR modes (PAE kernel, NX compat mode, etc) and on macos 233 // 10.6 and 10.7. 234 raw_addr += 0x20000000; 235 # endif 236 #endif 237 return reinterpret_cast<void*>(raw_addr); 238 } 239 240 241 size_t OS::AllocateAlignment() { 242 return static_cast<size_t>(sysconf(_SC_PAGESIZE)); 243 } 244 245 246 void OS::Sleep(TimeDelta interval) { 247 usleep(static_cast<useconds_t>(interval.InMicroseconds())); 248 } 249 250 251 void OS::Abort() { 252 if (g_hard_abort) { 253 V8_IMMEDIATE_CRASH(); 254 } 255 // Redirect to std abort to signal abnormal program termination. 256 abort(); 257 } 258 259 260 void OS::DebugBreak() { 261 #if V8_HOST_ARCH_ARM 262 asm("bkpt 0"); 263 #elif V8_HOST_ARCH_ARM64 264 asm("brk 0"); 265 #elif V8_HOST_ARCH_MIPS 266 asm("break"); 267 #elif V8_HOST_ARCH_MIPS64 268 asm("break"); 269 #elif V8_HOST_ARCH_PPC 270 asm("twge 2,2"); 271 #elif V8_HOST_ARCH_IA32 272 asm("int $3"); 273 #elif V8_HOST_ARCH_X64 274 asm("int $3"); 275 #elif V8_HOST_ARCH_S390 276 // Software breakpoint instruction is 0x0001 277 asm volatile(".word 0x0001"); 278 #else 279 #error Unsupported host architecture. 280 #endif 281 } 282 283 284 class PosixMemoryMappedFile final : public OS::MemoryMappedFile { 285 public: 286 PosixMemoryMappedFile(FILE* file, void* memory, size_t size) 287 : file_(file), memory_(memory), size_(size) {} 288 ~PosixMemoryMappedFile() final; 289 void* memory() const final { return memory_; } 290 size_t size() const final { return size_; } 291 292 private: 293 FILE* const file_; 294 void* const memory_; 295 size_t const size_; 296 }; 297 298 299 // static 300 OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) { 301 if (FILE* file = fopen(name, "r+")) { 302 if (fseek(file, 0, SEEK_END) == 0) { 303 long size = ftell(file); // NOLINT(runtime/int) 304 if (size >= 0) { 305 void* const memory = 306 mmap(OS::GetRandomMmapAddr(), size, PROT_READ | PROT_WRITE, 307 MAP_SHARED, fileno(file), 0); 308 if (memory != MAP_FAILED) { 309 return new PosixMemoryMappedFile(file, memory, size); 310 } 311 } 312 } 313 fclose(file); 314 } 315 return nullptr; 316 } 317 318 319 // static 320 OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, 321 size_t size, void* initial) { 322 if (FILE* file = fopen(name, "w+")) { 323 size_t result = fwrite(initial, 1, size, file); 324 if (result == size && !ferror(file)) { 325 void* memory = mmap(OS::GetRandomMmapAddr(), result, 326 PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0); 327 if (memory != MAP_FAILED) { 328 return new PosixMemoryMappedFile(file, memory, result); 329 } 330 } 331 fclose(file); 332 } 333 return nullptr; 334 } 335 336 337 PosixMemoryMappedFile::~PosixMemoryMappedFile() { 338 if (memory_) OS::Free(memory_, size_); 339 fclose(file_); 340 } 341 342 343 int OS::GetCurrentProcessId() { 344 return static_cast<int>(getpid()); 345 } 346 347 348 int OS::GetCurrentThreadId() { 349 #if V8_OS_MACOSX || (V8_OS_ANDROID && defined(__APPLE__)) 350 return static_cast<int>(pthread_mach_thread_np(pthread_self())); 351 #elif V8_OS_LINUX 352 return static_cast<int>(syscall(__NR_gettid)); 353 #elif V8_OS_ANDROID 354 return static_cast<int>(gettid()); 355 #elif V8_OS_AIX 356 return static_cast<int>(thread_self()); 357 #elif V8_OS_SOLARIS 358 return static_cast<int>(pthread_self()); 359 #else 360 return static_cast<int>(reinterpret_cast<intptr_t>(pthread_self())); 361 #endif 362 } 363 364 365 // ---------------------------------------------------------------------------- 366 // POSIX date/time support. 367 // 368 369 int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) { 370 struct rusage usage; 371 372 if (getrusage(RUSAGE_SELF, &usage) < 0) return -1; 373 *secs = static_cast<uint32_t>(usage.ru_utime.tv_sec); 374 *usecs = static_cast<uint32_t>(usage.ru_utime.tv_usec); 375 return 0; 376 } 377 378 379 double OS::TimeCurrentMillis() { 380 return Time::Now().ToJsTime(); 381 } 382 383 384 class TimezoneCache {}; 385 386 387 TimezoneCache* OS::CreateTimezoneCache() { 388 return NULL; 389 } 390 391 392 void OS::DisposeTimezoneCache(TimezoneCache* cache) { 393 DCHECK(cache == NULL); 394 } 395 396 397 void OS::ClearTimezoneCache(TimezoneCache* cache) { 398 DCHECK(cache == NULL); 399 } 400 401 402 double OS::DaylightSavingsOffset(double time, TimezoneCache*) { 403 if (std::isnan(time)) return std::numeric_limits<double>::quiet_NaN(); 404 time_t tv = static_cast<time_t>(std::floor(time/msPerSecond)); 405 struct tm tm; 406 struct tm* t = localtime_r(&tv, &tm); 407 if (NULL == t) return std::numeric_limits<double>::quiet_NaN(); 408 return t->tm_isdst > 0 ? 3600 * msPerSecond : 0; 409 } 410 411 412 int OS::GetLastError() { 413 return errno; 414 } 415 416 417 // ---------------------------------------------------------------------------- 418 // POSIX stdio support. 419 // 420 421 FILE* OS::FOpen(const char* path, const char* mode) { 422 FILE* file = fopen(path, mode); 423 if (file == NULL) return NULL; 424 struct stat file_stat; 425 if (fstat(fileno(file), &file_stat) != 0) return NULL; 426 bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0); 427 if (is_regular_file) return file; 428 fclose(file); 429 return NULL; 430 } 431 432 433 bool OS::Remove(const char* path) { 434 return (remove(path) == 0); 435 } 436 437 char OS::DirectorySeparator() { return '/'; } 438 439 bool OS::isDirectorySeparator(const char ch) { 440 return ch == DirectorySeparator(); 441 } 442 443 444 FILE* OS::OpenTemporaryFile() { 445 return tmpfile(); 446 } 447 448 449 const char* const OS::LogFileOpenMode = "w"; 450 451 452 void OS::Print(const char* format, ...) { 453 va_list args; 454 va_start(args, format); 455 VPrint(format, args); 456 va_end(args); 457 } 458 459 460 void OS::VPrint(const char* format, va_list args) { 461 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT) 462 __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args); 463 #else 464 vprintf(format, args); 465 #endif 466 } 467 468 469 void OS::FPrint(FILE* out, const char* format, ...) { 470 va_list args; 471 va_start(args, format); 472 VFPrint(out, format, args); 473 va_end(args); 474 } 475 476 477 void OS::VFPrint(FILE* out, const char* format, va_list args) { 478 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT) 479 __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args); 480 #else 481 vfprintf(out, format, args); 482 #endif 483 } 484 485 486 void OS::PrintError(const char* format, ...) { 487 va_list args; 488 va_start(args, format); 489 VPrintError(format, args); 490 va_end(args); 491 } 492 493 494 void OS::VPrintError(const char* format, va_list args) { 495 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT) 496 __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, format, args); 497 #else 498 vfprintf(stderr, format, args); 499 #endif 500 } 501 502 503 int OS::SNPrintF(char* str, int length, const char* format, ...) { 504 va_list args; 505 va_start(args, format); 506 int result = VSNPrintF(str, length, format, args); 507 va_end(args); 508 return result; 509 } 510 511 512 int OS::VSNPrintF(char* str, 513 int length, 514 const char* format, 515 va_list args) { 516 int n = vsnprintf(str, length, format, args); 517 if (n < 0 || n >= length) { 518 // If the length is zero, the assignment fails. 519 if (length > 0) 520 str[length - 1] = '\0'; 521 return -1; 522 } else { 523 return n; 524 } 525 } 526 527 528 // ---------------------------------------------------------------------------- 529 // POSIX string support. 530 // 531 532 char* OS::StrChr(char* str, int c) { 533 return strchr(str, c); 534 } 535 536 537 void OS::StrNCpy(char* dest, int length, const char* src, size_t n) { 538 strncpy(dest, src, n); 539 } 540 541 542 // ---------------------------------------------------------------------------- 543 // POSIX thread support. 544 // 545 546 class Thread::PlatformData { 547 public: 548 PlatformData() : thread_(kNoThread) {} 549 pthread_t thread_; // Thread handle for pthread. 550 // Synchronizes thread creation 551 Mutex thread_creation_mutex_; 552 }; 553 554 Thread::Thread(const Options& options) 555 : data_(new PlatformData), 556 stack_size_(options.stack_size()), 557 start_semaphore_(NULL) { 558 if (stack_size_ > 0 && static_cast<size_t>(stack_size_) < PTHREAD_STACK_MIN) { 559 stack_size_ = PTHREAD_STACK_MIN; 560 } 561 set_name(options.name()); 562 } 563 564 565 Thread::~Thread() { 566 delete data_; 567 } 568 569 570 static void SetThreadName(const char* name) { 571 #if V8_OS_DRAGONFLYBSD || V8_OS_FREEBSD || V8_OS_OPENBSD 572 pthread_set_name_np(pthread_self(), name); 573 #elif V8_OS_NETBSD 574 STATIC_ASSERT(Thread::kMaxThreadNameLength <= PTHREAD_MAX_NAMELEN_NP); 575 pthread_setname_np(pthread_self(), "%s", name); 576 #elif V8_OS_MACOSX 577 // pthread_setname_np is only available in 10.6 or later, so test 578 // for it at runtime. 579 int (*dynamic_pthread_setname_np)(const char*); 580 *reinterpret_cast<void**>(&dynamic_pthread_setname_np) = 581 dlsym(RTLD_DEFAULT, "pthread_setname_np"); 582 if (dynamic_pthread_setname_np == NULL) 583 return; 584 585 // Mac OS X does not expose the length limit of the name, so hardcode it. 586 static const int kMaxNameLength = 63; 587 STATIC_ASSERT(Thread::kMaxThreadNameLength <= kMaxNameLength); 588 dynamic_pthread_setname_np(name); 589 #elif defined(PR_SET_NAME) 590 prctl(PR_SET_NAME, 591 reinterpret_cast<unsigned long>(name), // NOLINT 592 0, 0, 0); 593 #endif 594 } 595 596 597 static void* ThreadEntry(void* arg) { 598 Thread* thread = reinterpret_cast<Thread*>(arg); 599 // We take the lock here to make sure that pthread_create finished first since 600 // we don't know which thread will run first (the original thread or the new 601 // one). 602 { LockGuard<Mutex> lock_guard(&thread->data()->thread_creation_mutex_); } 603 SetThreadName(thread->name()); 604 DCHECK(thread->data()->thread_ != kNoThread); 605 thread->NotifyStartedAndRun(); 606 return NULL; 607 } 608 609 610 void Thread::set_name(const char* name) { 611 strncpy(name_, name, sizeof(name_)); 612 name_[sizeof(name_) - 1] = '\0'; 613 } 614 615 616 void Thread::Start() { 617 int result; 618 pthread_attr_t attr; 619 memset(&attr, 0, sizeof(attr)); 620 result = pthread_attr_init(&attr); 621 DCHECK_EQ(0, result); 622 size_t stack_size = stack_size_; 623 if (stack_size == 0) { 624 #if V8_OS_MACOSX 625 // Default on Mac OS X is 512kB -- bump up to 1MB 626 stack_size = 1 * 1024 * 1024; 627 #elif V8_OS_AIX 628 // Default on AIX is 96kB -- bump up to 2MB 629 stack_size = 2 * 1024 * 1024; 630 #endif 631 } 632 if (stack_size > 0) { 633 result = pthread_attr_setstacksize(&attr, stack_size); 634 DCHECK_EQ(0, result); 635 } 636 { 637 LockGuard<Mutex> lock_guard(&data_->thread_creation_mutex_); 638 result = pthread_create(&data_->thread_, &attr, ThreadEntry, this); 639 } 640 DCHECK_EQ(0, result); 641 result = pthread_attr_destroy(&attr); 642 DCHECK_EQ(0, result); 643 DCHECK(data_->thread_ != kNoThread); 644 USE(result); 645 } 646 647 648 void Thread::Join() { 649 pthread_join(data_->thread_, NULL); 650 } 651 652 653 static Thread::LocalStorageKey PthreadKeyToLocalKey(pthread_key_t pthread_key) { 654 #if V8_OS_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 V8_OS_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 DCHECK_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 DCHECK_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 DCHECK_EQ(0, result); 773 USE(result); 774 } 775 776 } // namespace base 777 } // namespace v8 778