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 #if !defined(V8_OS_NACL) && !defined(_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 103 void OS::Free(void* address, const size_t size) { 104 // TODO(1240712): munmap has a return value which is ignored here. 105 int result = munmap(address, size); 106 USE(result); 107 DCHECK(result == 0); 108 } 109 110 111 // Get rid of writable permission on code allocations. 112 void OS::ProtectCode(void* address, const size_t size) { 113 #if V8_OS_CYGWIN 114 DWORD old_protect; 115 VirtualProtect(address, size, PAGE_EXECUTE_READ, &old_protect); 116 #elif V8_OS_NACL 117 // The Native Client port of V8 uses an interpreter, so 118 // code pages don't need PROT_EXEC. 119 mprotect(address, size, PROT_READ); 120 #else 121 mprotect(address, size, PROT_READ | PROT_EXEC); 122 #endif 123 } 124 125 126 // Create guard pages. 127 void OS::Guard(void* address, const size_t size) { 128 #if V8_OS_CYGWIN 129 DWORD oldprotect; 130 VirtualProtect(address, size, PAGE_NOACCESS, &oldprotect); 131 #else 132 mprotect(address, size, PROT_NONE); 133 #endif 134 } 135 136 137 static LazyInstance<RandomNumberGenerator>::type 138 platform_random_number_generator = LAZY_INSTANCE_INITIALIZER; 139 140 141 void OS::Initialize(int64_t random_seed, bool hard_abort, 142 const char* const gc_fake_mmap) { 143 if (random_seed) { 144 platform_random_number_generator.Pointer()->SetSeed(random_seed); 145 } 146 g_hard_abort = hard_abort; 147 g_gc_fake_mmap = gc_fake_mmap; 148 } 149 150 151 const char* OS::GetGCFakeMMapFile() { 152 return g_gc_fake_mmap; 153 } 154 155 156 void* OS::GetRandomMmapAddr() { 157 #if V8_OS_NACL 158 // TODO(bradchen): restore randomization once Native Client gets 159 // smarter about using mmap address hints. 160 // See http://code.google.com/p/nativeclient/issues/3341 161 return NULL; 162 #endif 163 #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \ 164 defined(THREAD_SANITIZER) 165 // Dynamic tools do not support custom mmap addresses. 166 return NULL; 167 #endif 168 uintptr_t raw_addr; 169 platform_random_number_generator.Pointer()->NextBytes(&raw_addr, 170 sizeof(raw_addr)); 171 #if V8_TARGET_ARCH_X64 172 // Currently available CPUs have 48 bits of virtual addressing. Truncate 173 // the hint address to 46 bits to give the kernel a fighting chance of 174 // fulfilling our placement request. 175 raw_addr &= V8_UINT64_C(0x3ffffffff000); 176 #elif V8_TARGET_ARCH_PPC64 177 #if V8_OS_AIX 178 // AIX: 64 bits of virtual addressing, but we limit address range to: 179 // a) minimize Segment Lookaside Buffer (SLB) misses and 180 raw_addr &= V8_UINT64_C(0x3ffff000); 181 // Use extra address space to isolate the mmap regions. 182 raw_addr += V8_UINT64_C(0x400000000000); 183 #elif V8_TARGET_BIG_ENDIAN 184 // Big-endian Linux: 44 bits of virtual addressing. 185 raw_addr &= V8_UINT64_C(0x03fffffff000); 186 #else 187 // Little-endian Linux: 48 bits of virtual addressing. 188 raw_addr &= V8_UINT64_C(0x3ffffffff000); 189 #endif 190 #elif V8_TARGET_ARCH_S390X 191 // Linux on Z uses bits 22-32 for Region Indexing, which translates to 42 bits 192 // of virtual addressing. Truncate to 40 bits to allow kernel chance to 193 // fulfill request. 194 raw_addr &= V8_UINT64_C(0xfffffff000); 195 #elif V8_TARGET_ARCH_S390 196 // 31 bits of virtual addressing. Truncate to 29 bits to allow kernel chance 197 // to fulfill request. 198 raw_addr &= 0x1ffff000; 199 #else 200 raw_addr &= 0x3ffff000; 201 202 # ifdef __sun 203 // For our Solaris/illumos mmap hint, we pick a random address in the bottom 204 // half of the top half of the address space (that is, the third quarter). 205 // Because we do not MAP_FIXED, this will be treated only as a hint -- the 206 // system will not fail to mmap() because something else happens to already 207 // be mapped at our random address. We deliberately set the hint high enough 208 // to get well above the system's break (that is, the heap); Solaris and 209 // illumos will try the hint and if that fails allocate as if there were 210 // no hint at all. The high hint prevents the break from getting hemmed in 211 // at low values, ceding half of the address space to the system heap. 212 raw_addr += 0x80000000; 213 #elif V8_OS_AIX 214 // The range 0x30000000 - 0xD0000000 is available on AIX; 215 // choose the upper range. 216 raw_addr += 0x90000000; 217 # else 218 // The range 0x20000000 - 0x60000000 is relatively unpopulated across a 219 // variety of ASLR modes (PAE kernel, NX compat mode, etc) and on macos 220 // 10.6 and 10.7. 221 raw_addr += 0x20000000; 222 # endif 223 #endif 224 return reinterpret_cast<void*>(raw_addr); 225 } 226 227 228 size_t OS::AllocateAlignment() { 229 return static_cast<size_t>(sysconf(_SC_PAGESIZE)); 230 } 231 232 233 void OS::Sleep(TimeDelta interval) { 234 usleep(static_cast<useconds_t>(interval.InMicroseconds())); 235 } 236 237 238 void OS::Abort() { 239 if (g_hard_abort) { 240 V8_IMMEDIATE_CRASH(); 241 } 242 // Redirect to std abort to signal abnormal program termination. 243 abort(); 244 } 245 246 247 void OS::DebugBreak() { 248 #if V8_HOST_ARCH_ARM 249 asm("bkpt 0"); 250 #elif V8_HOST_ARCH_ARM64 251 asm("brk 0"); 252 #elif V8_HOST_ARCH_MIPS 253 asm("break"); 254 #elif V8_HOST_ARCH_MIPS64 255 asm("break"); 256 #elif V8_HOST_ARCH_PPC 257 asm("twge 2,2"); 258 #elif V8_HOST_ARCH_IA32 259 #if V8_OS_NACL 260 asm("hlt"); 261 #else 262 asm("int $3"); 263 #endif // V8_OS_NACL 264 #elif V8_HOST_ARCH_X64 265 asm("int $3"); 266 #elif V8_HOST_ARCH_S390 267 // Software breakpoint instruction is 0x0001 268 asm volatile(".word 0x0001"); 269 #else 270 #error Unsupported host architecture. 271 #endif 272 } 273 274 275 class PosixMemoryMappedFile final : public OS::MemoryMappedFile { 276 public: 277 PosixMemoryMappedFile(FILE* file, void* memory, size_t size) 278 : file_(file), memory_(memory), size_(size) {} 279 ~PosixMemoryMappedFile() final; 280 void* memory() const final { return memory_; } 281 size_t size() const final { return size_; } 282 283 private: 284 FILE* const file_; 285 void* const memory_; 286 size_t const size_; 287 }; 288 289 290 // static 291 OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) { 292 if (FILE* file = fopen(name, "r+")) { 293 if (fseek(file, 0, SEEK_END) == 0) { 294 long size = ftell(file); // NOLINT(runtime/int) 295 if (size >= 0) { 296 void* const memory = 297 mmap(OS::GetRandomMmapAddr(), size, PROT_READ | PROT_WRITE, 298 MAP_SHARED, fileno(file), 0); 299 if (memory != MAP_FAILED) { 300 return new PosixMemoryMappedFile(file, memory, size); 301 } 302 } 303 } 304 fclose(file); 305 } 306 return nullptr; 307 } 308 309 310 // static 311 OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, 312 size_t size, void* initial) { 313 if (FILE* file = fopen(name, "w+")) { 314 size_t result = fwrite(initial, 1, size, file); 315 if (result == size && !ferror(file)) { 316 void* memory = mmap(OS::GetRandomMmapAddr(), result, 317 PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0); 318 if (memory != MAP_FAILED) { 319 return new PosixMemoryMappedFile(file, memory, result); 320 } 321 } 322 fclose(file); 323 } 324 return nullptr; 325 } 326 327 328 PosixMemoryMappedFile::~PosixMemoryMappedFile() { 329 if (memory_) OS::Free(memory_, size_); 330 fclose(file_); 331 } 332 333 334 int OS::GetCurrentProcessId() { 335 return static_cast<int>(getpid()); 336 } 337 338 339 int OS::GetCurrentThreadId() { 340 #if V8_OS_MACOSX || (V8_OS_ANDROID && defined(__APPLE__)) 341 return static_cast<int>(pthread_mach_thread_np(pthread_self())); 342 #elif V8_OS_LINUX 343 return static_cast<int>(syscall(__NR_gettid)); 344 #elif V8_OS_ANDROID 345 return static_cast<int>(gettid()); 346 #elif V8_OS_AIX 347 return static_cast<int>(thread_self()); 348 #elif V8_OS_SOLARIS 349 return static_cast<int>(pthread_self()); 350 #else 351 return static_cast<int>(reinterpret_cast<intptr_t>(pthread_self())); 352 #endif 353 } 354 355 356 // ---------------------------------------------------------------------------- 357 // POSIX date/time support. 358 // 359 360 int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) { 361 #if V8_OS_NACL 362 // Optionally used in Logger::ResourceEvent. 363 return -1; 364 #else 365 struct rusage usage; 366 367 if (getrusage(RUSAGE_SELF, &usage) < 0) return -1; 368 *secs = static_cast<uint32_t>(usage.ru_utime.tv_sec); 369 *usecs = static_cast<uint32_t>(usage.ru_utime.tv_usec); 370 return 0; 371 #endif 372 } 373 374 375 double OS::TimeCurrentMillis() { 376 return Time::Now().ToJsTime(); 377 } 378 379 380 class TimezoneCache {}; 381 382 383 TimezoneCache* OS::CreateTimezoneCache() { 384 return NULL; 385 } 386 387 388 void OS::DisposeTimezoneCache(TimezoneCache* cache) { 389 DCHECK(cache == NULL); 390 } 391 392 393 void OS::ClearTimezoneCache(TimezoneCache* cache) { 394 DCHECK(cache == NULL); 395 } 396 397 398 double OS::DaylightSavingsOffset(double time, TimezoneCache*) { 399 if (std::isnan(time)) return std::numeric_limits<double>::quiet_NaN(); 400 time_t tv = static_cast<time_t>(std::floor(time/msPerSecond)); 401 struct tm* t = localtime(&tv); // NOLINT(runtime/threadsafe_fn) 402 if (NULL == t) return std::numeric_limits<double>::quiet_NaN(); 403 return t->tm_isdst > 0 ? 3600 * msPerSecond : 0; 404 } 405 406 407 int OS::GetLastError() { 408 return errno; 409 } 410 411 412 // ---------------------------------------------------------------------------- 413 // POSIX stdio support. 414 // 415 416 FILE* OS::FOpen(const char* path, const char* mode) { 417 FILE* file = fopen(path, mode); 418 if (file == NULL) return NULL; 419 struct stat file_stat; 420 if (fstat(fileno(file), &file_stat) != 0) return NULL; 421 bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0); 422 if (is_regular_file) return file; 423 fclose(file); 424 return NULL; 425 } 426 427 428 bool OS::Remove(const char* path) { 429 return (remove(path) == 0); 430 } 431 432 char OS::DirectorySeparator() { return '/'; } 433 434 bool OS::isDirectorySeparator(const char ch) { 435 return ch == DirectorySeparator(); 436 } 437 438 439 FILE* OS::OpenTemporaryFile() { 440 return tmpfile(); 441 } 442 443 444 const char* const OS::LogFileOpenMode = "w"; 445 446 447 void OS::Print(const char* format, ...) { 448 va_list args; 449 va_start(args, format); 450 VPrint(format, args); 451 va_end(args); 452 } 453 454 455 void OS::VPrint(const char* format, va_list args) { 456 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT) 457 __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args); 458 #else 459 vprintf(format, args); 460 #endif 461 } 462 463 464 void OS::FPrint(FILE* out, const char* format, ...) { 465 va_list args; 466 va_start(args, format); 467 VFPrint(out, format, args); 468 va_end(args); 469 } 470 471 472 void OS::VFPrint(FILE* out, const char* format, va_list args) { 473 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT) 474 __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args); 475 #else 476 vfprintf(out, format, args); 477 #endif 478 } 479 480 481 void OS::PrintError(const char* format, ...) { 482 va_list args; 483 va_start(args, format); 484 VPrintError(format, args); 485 va_end(args); 486 } 487 488 489 void OS::VPrintError(const char* format, va_list args) { 490 #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT) 491 __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, format, args); 492 #else 493 vfprintf(stderr, format, args); 494 #endif 495 } 496 497 498 int OS::SNPrintF(char* str, int length, const char* format, ...) { 499 va_list args; 500 va_start(args, format); 501 int result = VSNPrintF(str, length, format, args); 502 va_end(args); 503 return result; 504 } 505 506 507 int OS::VSNPrintF(char* str, 508 int length, 509 const char* format, 510 va_list args) { 511 int n = vsnprintf(str, length, format, args); 512 if (n < 0 || n >= length) { 513 // If the length is zero, the assignment fails. 514 if (length > 0) 515 str[length - 1] = '\0'; 516 return -1; 517 } else { 518 return n; 519 } 520 } 521 522 523 // ---------------------------------------------------------------------------- 524 // POSIX string support. 525 // 526 527 char* OS::StrChr(char* str, int c) { 528 return strchr(str, c); 529 } 530 531 532 void OS::StrNCpy(char* dest, int length, const char* src, size_t n) { 533 strncpy(dest, src, n); 534 } 535 536 537 // ---------------------------------------------------------------------------- 538 // POSIX thread support. 539 // 540 541 class Thread::PlatformData { 542 public: 543 PlatformData() : thread_(kNoThread) {} 544 pthread_t thread_; // Thread handle for pthread. 545 // Synchronizes thread creation 546 Mutex thread_creation_mutex_; 547 }; 548 549 Thread::Thread(const Options& options) 550 : data_(new PlatformData), 551 stack_size_(options.stack_size()), 552 start_semaphore_(NULL) { 553 if (stack_size_ > 0 && static_cast<size_t>(stack_size_) < PTHREAD_STACK_MIN) { 554 stack_size_ = PTHREAD_STACK_MIN; 555 } 556 set_name(options.name()); 557 } 558 559 560 Thread::~Thread() { 561 delete data_; 562 } 563 564 565 static void SetThreadName(const char* name) { 566 #if V8_OS_DRAGONFLYBSD || V8_OS_FREEBSD || V8_OS_OPENBSD 567 pthread_set_name_np(pthread_self(), name); 568 #elif V8_OS_NETBSD 569 STATIC_ASSERT(Thread::kMaxThreadNameLength <= PTHREAD_MAX_NAMELEN_NP); 570 pthread_setname_np(pthread_self(), "%s", name); 571 #elif V8_OS_MACOSX 572 // pthread_setname_np is only available in 10.6 or later, so test 573 // for it at runtime. 574 int (*dynamic_pthread_setname_np)(const char*); 575 *reinterpret_cast<void**>(&dynamic_pthread_setname_np) = 576 dlsym(RTLD_DEFAULT, "pthread_setname_np"); 577 if (dynamic_pthread_setname_np == NULL) 578 return; 579 580 // Mac OS X does not expose the length limit of the name, so hardcode it. 581 static const int kMaxNameLength = 63; 582 STATIC_ASSERT(Thread::kMaxThreadNameLength <= kMaxNameLength); 583 dynamic_pthread_setname_np(name); 584 #elif defined(PR_SET_NAME) 585 prctl(PR_SET_NAME, 586 reinterpret_cast<unsigned long>(name), // NOLINT 587 0, 0, 0); 588 #endif 589 } 590 591 592 static void* ThreadEntry(void* arg) { 593 Thread* thread = reinterpret_cast<Thread*>(arg); 594 // We take the lock here to make sure that pthread_create finished first since 595 // we don't know which thread will run first (the original thread or the new 596 // one). 597 { LockGuard<Mutex> lock_guard(&thread->data()->thread_creation_mutex_); } 598 SetThreadName(thread->name()); 599 DCHECK(thread->data()->thread_ != kNoThread); 600 thread->NotifyStartedAndRun(); 601 return NULL; 602 } 603 604 605 void Thread::set_name(const char* name) { 606 strncpy(name_, name, sizeof(name_)); 607 name_[sizeof(name_) - 1] = '\0'; 608 } 609 610 611 void Thread::Start() { 612 int result; 613 pthread_attr_t attr; 614 memset(&attr, 0, sizeof(attr)); 615 result = pthread_attr_init(&attr); 616 DCHECK_EQ(0, result); 617 // Native client uses default stack size. 618 #if !V8_OS_NACL 619 size_t stack_size = stack_size_; 620 #if V8_OS_AIX 621 if (stack_size == 0) { 622 // Default on AIX is 96KB -- bump up to 2MB 623 stack_size = 2 * 1024 * 1024; 624 } 625 #endif 626 if (stack_size > 0) { 627 result = pthread_attr_setstacksize(&attr, stack_size); 628 DCHECK_EQ(0, result); 629 } 630 #endif 631 { 632 LockGuard<Mutex> lock_guard(&data_->thread_creation_mutex_); 633 result = pthread_create(&data_->thread_, &attr, ThreadEntry, this); 634 } 635 DCHECK_EQ(0, result); 636 result = pthread_attr_destroy(&attr); 637 DCHECK_EQ(0, result); 638 DCHECK(data_->thread_ != kNoThread); 639 USE(result); 640 } 641 642 643 void Thread::Join() { 644 pthread_join(data_->thread_, NULL); 645 } 646 647 648 static Thread::LocalStorageKey PthreadKeyToLocalKey(pthread_key_t pthread_key) { 649 #if V8_OS_CYGWIN 650 // We need to cast pthread_key_t to Thread::LocalStorageKey in two steps 651 // because pthread_key_t is a pointer type on Cygwin. This will probably not 652 // work on 64-bit platforms, but Cygwin doesn't support 64-bit anyway. 653 STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t)); 654 intptr_t ptr_key = reinterpret_cast<intptr_t>(pthread_key); 655 return static_cast<Thread::LocalStorageKey>(ptr_key); 656 #else 657 return static_cast<Thread::LocalStorageKey>(pthread_key); 658 #endif 659 } 660 661 662 static pthread_key_t LocalKeyToPthreadKey(Thread::LocalStorageKey local_key) { 663 #if V8_OS_CYGWIN 664 STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t)); 665 intptr_t ptr_key = static_cast<intptr_t>(local_key); 666 return reinterpret_cast<pthread_key_t>(ptr_key); 667 #else 668 return static_cast<pthread_key_t>(local_key); 669 #endif 670 } 671 672 673 #ifdef V8_FAST_TLS_SUPPORTED 674 675 static Atomic32 tls_base_offset_initialized = 0; 676 intptr_t kMacTlsBaseOffset = 0; 677 678 // It's safe to do the initialization more that once, but it has to be 679 // done at least once. 680 static void InitializeTlsBaseOffset() { 681 const size_t kBufferSize = 128; 682 char buffer[kBufferSize]; 683 size_t buffer_size = kBufferSize; 684 int ctl_name[] = { CTL_KERN , KERN_OSRELEASE }; 685 if (sysctl(ctl_name, 2, buffer, &buffer_size, NULL, 0) != 0) { 686 V8_Fatal(__FILE__, __LINE__, "V8 failed to get kernel version"); 687 } 688 // The buffer now contains a string of the form XX.YY.ZZ, where 689 // XX is the major kernel version component. 690 // Make sure the buffer is 0-terminated. 691 buffer[kBufferSize - 1] = '\0'; 692 char* period_pos = strchr(buffer, '.'); 693 *period_pos = '\0'; 694 int kernel_version_major = 695 static_cast<int>(strtol(buffer, NULL, 10)); // NOLINT 696 // The constants below are taken from pthreads.s from the XNU kernel 697 // sources archive at www.opensource.apple.com. 698 if (kernel_version_major < 11) { 699 // 8.x.x (Tiger), 9.x.x (Leopard), 10.x.x (Snow Leopard) have the 700 // same offsets. 701 #if V8_HOST_ARCH_IA32 702 kMacTlsBaseOffset = 0x48; 703 #else 704 kMacTlsBaseOffset = 0x60; 705 #endif 706 } else { 707 // 11.x.x (Lion) changed the offset. 708 kMacTlsBaseOffset = 0; 709 } 710 711 Release_Store(&tls_base_offset_initialized, 1); 712 } 713 714 715 static void CheckFastTls(Thread::LocalStorageKey key) { 716 void* expected = reinterpret_cast<void*>(0x1234CAFE); 717 Thread::SetThreadLocal(key, expected); 718 void* actual = Thread::GetExistingThreadLocal(key); 719 if (expected != actual) { 720 V8_Fatal(__FILE__, __LINE__, 721 "V8 failed to initialize fast TLS on current kernel"); 722 } 723 Thread::SetThreadLocal(key, NULL); 724 } 725 726 #endif // V8_FAST_TLS_SUPPORTED 727 728 729 Thread::LocalStorageKey Thread::CreateThreadLocalKey() { 730 #ifdef V8_FAST_TLS_SUPPORTED 731 bool check_fast_tls = false; 732 if (tls_base_offset_initialized == 0) { 733 check_fast_tls = true; 734 InitializeTlsBaseOffset(); 735 } 736 #endif 737 pthread_key_t key; 738 int result = pthread_key_create(&key, NULL); 739 DCHECK_EQ(0, result); 740 USE(result); 741 LocalStorageKey local_key = PthreadKeyToLocalKey(key); 742 #ifdef V8_FAST_TLS_SUPPORTED 743 // If we just initialized fast TLS support, make sure it works. 744 if (check_fast_tls) CheckFastTls(local_key); 745 #endif 746 return local_key; 747 } 748 749 750 void Thread::DeleteThreadLocalKey(LocalStorageKey key) { 751 pthread_key_t pthread_key = LocalKeyToPthreadKey(key); 752 int result = pthread_key_delete(pthread_key); 753 DCHECK_EQ(0, result); 754 USE(result); 755 } 756 757 758 void* Thread::GetThreadLocal(LocalStorageKey key) { 759 pthread_key_t pthread_key = LocalKeyToPthreadKey(key); 760 return pthread_getspecific(pthread_key); 761 } 762 763 764 void Thread::SetThreadLocal(LocalStorageKey key, void* value) { 765 pthread_key_t pthread_key = LocalKeyToPthreadKey(key); 766 int result = pthread_setspecific(pthread_key, value); 767 DCHECK_EQ(0, result); 768 USE(result); 769 } 770 771 } // namespace base 772 } // namespace v8 773