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