LCOV - code coverage report
Current view: top level - src/base/platform - platform-posix.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 131 186 70.4 %
Date: 2017-10-20 Functions: 36 53 67.9 %

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

Generated by: LCOV version 1.10