LCOV - code coverage report
Current view: top level - src/base/platform - platform-posix.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 140 197 71.1 %
Date: 2017-04-26 Functions: 36 54 66.7 %

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

Generated by: LCOV version 1.10