Home | History | Annotate | Download | only in src
      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