13ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// Copyright 2012 the V8 project authors. All rights reserved. 2a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Redistribution and use in source and binary forms, with or without 3a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// modification, are permitted provided that the following conditions are 4a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// met: 5a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 6a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// * Redistributions of source code must retain the above copyright 7a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// notice, this list of conditions and the following disclaimer. 8a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// * Redistributions in binary form must reproduce the above 9a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// copyright notice, this list of conditions and the following 10a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// disclaimer in the documentation and/or other materials provided 11a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// with the distribution. 12a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// * Neither the name of Google Inc. nor the names of its 13a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// contributors may be used to endorse or promote products derived 14a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// from this software without specific prior written permission. 15a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 16a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 28a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Platform specific code for Linux goes here. For the POSIX comaptible parts 29a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// the implementation is in platform-posix.cc. 30a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 31a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <pthread.h> 32a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <semaphore.h> 33a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <signal.h> 349fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block#include <sys/prctl.h> 35a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <sys/time.h> 36a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <sys/resource.h> 375913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck#include <sys/syscall.h> 38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <sys/types.h> 39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <stdlib.h> 40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Ubuntu Dapper requires memory pages to be marked as 42a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// executable. Otherwise, OS raises an exception when executing code 43a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// in that page. 44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <sys/types.h> // mmap & munmap 45a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <sys/mman.h> // mmap & munmap 46a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <sys/stat.h> // open 47a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <fcntl.h> // open 48a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <unistd.h> // sysconf 49a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef __GLIBC__ 50a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <execinfo.h> // backtrace, backtrace_symbols 51a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif // def __GLIBC__ 52a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <strings.h> // index 53a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <errno.h> 54a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <stdarg.h> 55a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 56a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#undef MAP_TYPE 57a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 58a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "v8.h" 59a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#include "platform-posix.h" 61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "platform.h" 62a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "v8threads.h" 63b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch#include "vm-state-inl.h" 64a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 65a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace v8 { 67a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace internal { 68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 69a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 0 is never a valid thread id on Linux since tids and pids share a 70a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// name space and pid 0 is reserved (see man 2 kill). 71a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic const pthread_t kNoThread = (pthread_t) 0; 72a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdouble ceiling(double x) { 75a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return ceil(x); 76a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 77a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 78a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7944f0eee88ff00398ff7f715fab053374d808c90dSteve Blockstatic Mutex* limit_mutex = NULL; 8044f0eee88ff00398ff7f715fab053374d808c90dSteve Block 8144f0eee88ff00398ff7f715fab053374d808c90dSteve Block 823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid OS::SetUp() { 833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch // Seed the random number generator. We preserve microsecond resolution. 843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch uint64_t seed = Ticks() ^ (getpid() << 16); 85a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block srandom(static_cast<unsigned int>(seed)); 8644f0eee88ff00398ff7f715fab053374d808c90dSteve Block limit_mutex = CreateMutex(); 87257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 88257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch#ifdef __arm__ 89257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // When running on ARM hardware check that the EABI used by V8 and 90257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch // by the C code is the same. 91257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch bool hard_float = OS::ArmUsingHardFloat(); 92257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if (hard_float) { 93257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch#if !USE_EABI_HARDFLOAT 94257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch PrintF("ERROR: Binary compiled with -mfloat-abi=hard but without " 95257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch "-DUSE_EABI_HARDFLOAT\n"); 96257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch exit(1); 97257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch#endif 98257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } else { 99257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch#if USE_EABI_HARDFLOAT 100257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch PrintF("ERROR: Binary not compiled with -mfloat-abi=hard but with " 101257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch "-DUSE_EABI_HARDFLOAT\n"); 102257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch exit(1); 103257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch#endif 104257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 105257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch#endif 106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid OS::PostSetUp() { 1103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Math functions depend on CPU features therefore they are initialized after 1113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // CPU. 1123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch MathSetup(); 1133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 1143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 1153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 116d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockuint64_t OS::CpuFeaturesImpliedByPlatform() { 117d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block return 0; // Linux runs on anything. 118d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block} 119d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 120d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 121d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#ifdef __arm__ 1223e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhustatic bool CPUInfoContainsString(const char * search_string) { 123d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block const char* file_name = "/proc/cpuinfo"; 124d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // This is written as a straight shot one pass parser 125d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // and not using STL string and ifstream because, 126d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // on Linux, it's reading from a (non-mmap-able) 127d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // character special device. 128d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block FILE* f = NULL; 129d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block const char* what = search_string; 130d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 131d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block if (NULL == (f = fopen(file_name, "r"))) 132d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block return false; 133d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 134d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block int k; 135d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block while (EOF != (k = fgetc(f))) { 136d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block if (k == *what) { 137d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block ++what; 138d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block while ((*what != '\0') && (*what == fgetc(f))) { 139d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block ++what; 140d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } 141d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block if (*what == '\0') { 142d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block fclose(f); 143d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block return true; 144d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } else { 145d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block what = search_string; 146d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } 147d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } 148d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block } 149d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block fclose(f); 150d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 151d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Did not find string in the proc file. 152d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block return false; 153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1543e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu 155257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 1563e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhubool OS::ArmCpuHasFeature(CpuFeature feature) { 1571a80c996a0cb6c5ac739148352552ab47038ccc3Ben Murdoch const char* search_string = NULL; 1583e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu // Simple detection of VFP at runtime for Linux. 1593e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu // It is based on /proc/cpuinfo, which reveals hardware configuration 1603e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu // to user-space applications. According to ARM (mid 2009), no similar 1613e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu // facility is universally available on the ARM architectures, 1623e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu // so it's up to individual OSes to provide such. 1633e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu switch (feature) { 1643e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu case VFP3: 1651a80c996a0cb6c5ac739148352552ab47038ccc3Ben Murdoch search_string = "vfpv3"; 1663e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu break; 1673e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu case ARMv7: 1681a80c996a0cb6c5ac739148352552ab47038ccc3Ben Murdoch search_string = "ARMv7"; 1693e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu break; 1703e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu default: 1713e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu UNREACHABLE(); 1723e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu } 1733e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu 1741a80c996a0cb6c5ac739148352552ab47038ccc3Ben Murdoch if (CPUInfoContainsString(search_string)) { 1751a80c996a0cb6c5ac739148352552ab47038ccc3Ben Murdoch return true; 1761a80c996a0cb6c5ac739148352552ab47038ccc3Ben Murdoch } 1771a80c996a0cb6c5ac739148352552ab47038ccc3Ben Murdoch 1781a80c996a0cb6c5ac739148352552ab47038ccc3Ben Murdoch if (feature == VFP3) { 1791a80c996a0cb6c5ac739148352552ab47038ccc3Ben Murdoch // Some old kernels will report vfp not vfpv3. Here we make a last attempt 1801a80c996a0cb6c5ac739148352552ab47038ccc3Ben Murdoch // to detect vfpv3 by checking for vfp *and* neon, since neon is only 1811a80c996a0cb6c5ac739148352552ab47038ccc3Ben Murdoch // available on architectures with vfpv3. 1821a80c996a0cb6c5ac739148352552ab47038ccc3Ben Murdoch // Checking neon on its own is not enough as it is possible to have neon 1831a80c996a0cb6c5ac739148352552ab47038ccc3Ben Murdoch // without vfp. 1841a80c996a0cb6c5ac739148352552ab47038ccc3Ben Murdoch if (CPUInfoContainsString("vfp") && CPUInfoContainsString("neon")) { 1853e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu return true; 1863e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu } 1873e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu } 1883e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu 1893e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu return false; 1903e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu} 191257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 192257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 193af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsiehbool OS::ArmUsingHardFloat() { 194af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh // GCC versions 4.6 and above define __ARM_PCS or __ARM_PCS_VFP to specify 195af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh // the Floating Point ABI used (PCS stands for Procedure Call Standard). 196af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh // We use these as well as a couple of other defines to statically determine 197af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh // what FP ABI used. 198af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh // GCC versions 4.4 and below don't support hard-fp. 199af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh // GCC versions 4.5 may support hard-fp without defining __ARM_PCS or 200af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh // __ARM_PCS_VFP. 201af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh 202af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh#define GCC_VERSION (__GNUC__ * 10000 \ 203af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh + __GNUC_MINOR__ * 100 \ 204af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh + __GNUC_PATCHLEVEL__) 205af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh#if GCC_VERSION >= 40600 206af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh#if defined(__ARM_PCS_VFP) 207af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh return true; 208257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch#else 209af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh return false; 210af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh#endif 211257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 212af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh#elif GCC_VERSION < 40500 213af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh return false; 214257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 215af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh#else 216af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh#if defined(__ARM_PCS_VFP) 217af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh return true; 218af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh#elif defined(__ARM_PCS) || defined(__SOFTFP) || !defined(__VFP_FP__) 219af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh return false; 220af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh#else 221af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh#error "Your version of GCC does not report the FP ABI compiled for." \ 222af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh "Please report it on this issue" \ 223af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh "http://code.google.com/p/v8/issues/detail?id=2140" 224af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh 225af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh#endif 226af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh#endif 227af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh#undef GCC_VERSION 228257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch} 229af537b8206a515f942e5ee0338113bd485b55eb7Andrew Hsieh 230d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#endif // def __arm__ 231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 23344f0eee88ff00398ff7f715fab053374d808c90dSteve Block#ifdef __mips__ 23444f0eee88ff00398ff7f715fab053374d808c90dSteve Blockbool OS::MipsCpuHasFeature(CpuFeature feature) { 23544f0eee88ff00398ff7f715fab053374d808c90dSteve Block const char* search_string = NULL; 23644f0eee88ff00398ff7f715fab053374d808c90dSteve Block const char* file_name = "/proc/cpuinfo"; 23744f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Simple detection of FPU at runtime for Linux. 23844f0eee88ff00398ff7f715fab053374d808c90dSteve Block // It is based on /proc/cpuinfo, which reveals hardware configuration 23944f0eee88ff00398ff7f715fab053374d808c90dSteve Block // to user-space applications. According to MIPS (early 2010), no similar 24044f0eee88ff00398ff7f715fab053374d808c90dSteve Block // facility is universally available on the MIPS architectures, 24144f0eee88ff00398ff7f715fab053374d808c90dSteve Block // so it's up to individual OSes to provide such. 24244f0eee88ff00398ff7f715fab053374d808c90dSteve Block // 24344f0eee88ff00398ff7f715fab053374d808c90dSteve Block // This is written as a straight shot one pass parser 24444f0eee88ff00398ff7f715fab053374d808c90dSteve Block // and not using STL string and ifstream because, 24544f0eee88ff00398ff7f715fab053374d808c90dSteve Block // on Linux, it's reading from a (non-mmap-able) 24644f0eee88ff00398ff7f715fab053374d808c90dSteve Block // character special device. 24744f0eee88ff00398ff7f715fab053374d808c90dSteve Block 24844f0eee88ff00398ff7f715fab053374d808c90dSteve Block switch (feature) { 24944f0eee88ff00398ff7f715fab053374d808c90dSteve Block case FPU: 25044f0eee88ff00398ff7f715fab053374d808c90dSteve Block search_string = "FPU"; 25144f0eee88ff00398ff7f715fab053374d808c90dSteve Block break; 25244f0eee88ff00398ff7f715fab053374d808c90dSteve Block default: 25344f0eee88ff00398ff7f715fab053374d808c90dSteve Block UNREACHABLE(); 25444f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 25544f0eee88ff00398ff7f715fab053374d808c90dSteve Block 25644f0eee88ff00398ff7f715fab053374d808c90dSteve Block FILE* f = NULL; 25744f0eee88ff00398ff7f715fab053374d808c90dSteve Block const char* what = search_string; 25844f0eee88ff00398ff7f715fab053374d808c90dSteve Block 25944f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (NULL == (f = fopen(file_name, "r"))) 26044f0eee88ff00398ff7f715fab053374d808c90dSteve Block return false; 26144f0eee88ff00398ff7f715fab053374d808c90dSteve Block 26244f0eee88ff00398ff7f715fab053374d808c90dSteve Block int k; 26344f0eee88ff00398ff7f715fab053374d808c90dSteve Block while (EOF != (k = fgetc(f))) { 26444f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (k == *what) { 26544f0eee88ff00398ff7f715fab053374d808c90dSteve Block ++what; 26644f0eee88ff00398ff7f715fab053374d808c90dSteve Block while ((*what != '\0') && (*what == fgetc(f))) { 26744f0eee88ff00398ff7f715fab053374d808c90dSteve Block ++what; 26844f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 26944f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (*what == '\0') { 27044f0eee88ff00398ff7f715fab053374d808c90dSteve Block fclose(f); 27144f0eee88ff00398ff7f715fab053374d808c90dSteve Block return true; 27244f0eee88ff00398ff7f715fab053374d808c90dSteve Block } else { 27344f0eee88ff00398ff7f715fab053374d808c90dSteve Block what = search_string; 27444f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 27544f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 27644f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 27744f0eee88ff00398ff7f715fab053374d808c90dSteve Block fclose(f); 27844f0eee88ff00398ff7f715fab053374d808c90dSteve Block 27944f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Did not find string in the proc file. 28044f0eee88ff00398ff7f715fab053374d808c90dSteve Block return false; 28144f0eee88ff00398ff7f715fab053374d808c90dSteve Block} 28244f0eee88ff00398ff7f715fab053374d808c90dSteve Block#endif // def __mips__ 28344f0eee88ff00398ff7f715fab053374d808c90dSteve Block 28444f0eee88ff00398ff7f715fab053374d808c90dSteve Block 285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockint OS::ActivationFrameAlignment() { 286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef V8_TARGET_ARCH_ARM 287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // On EABI ARM targets this is required for fp correctness in the 288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // runtime system. 289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return 8; 2903100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#elif V8_TARGET_ARCH_MIPS 2913100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu return 8; 2923100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#endif 2936ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // With gcc 4.4 the tree vectorization optimizer can generate code 294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // that requires 16 byte alignment such as movdqa on x86. 295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return 16; 296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 299f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarkevoid OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) { 30044f0eee88ff00398ff7f715fab053374d808c90dSteve Block#if (defined(V8_TARGET_ARCH_ARM) && defined(__arm__)) || \ 30144f0eee88ff00398ff7f715fab053374d808c90dSteve Block (defined(V8_TARGET_ARCH_MIPS) && defined(__mips__)) 30244f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Only use on ARM or MIPS hardware. 303b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch MemoryBarrier(); 304f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke#else 305f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke __asm__ __volatile__("" : : : "memory"); 306f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke // An x86 store acts as a release barrier. 307f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke#endif 308f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke *ptr = value; 309f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke} 310f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke 311f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke 312d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarkeconst char* OS::LocalTimezone(double time) { 313d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke if (isnan(time)) return ""; 314d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke time_t tv = static_cast<time_t>(floor(time/msPerSecond)); 315d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke struct tm* t = localtime(&tv); 316d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke if (NULL == t) return ""; 317d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke return t->tm_zone; 318d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke} 319d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 320d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 321d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarkedouble OS::LocalTimeOffset() { 322d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke time_t tv = time(NULL); 323d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke struct tm* t = localtime(&tv); 324d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke // tm_gmtoff includes any daylight savings offset, so subtract it. 325d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke return static_cast<double>(t->tm_gmtoff * msPerSecond - 326d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke (t->tm_isdst > 0 ? 3600 * msPerSecond : 0)); 327d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke} 328d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 329d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke 330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// We keep the lowest and highest addresses mapped as a quick way of 331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// determining that pointers are outside the heap (used mostly in assertions 3323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// and verification). The estimate is conservative, i.e., not all addresses in 333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 'allocated' space are actually allocated to our heap. The range is 334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// [lowest, highest), inclusive on the low and and exclusive on the high end. 335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void* lowest_ever_allocated = reinterpret_cast<void*>(-1); 336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void* highest_ever_allocated = reinterpret_cast<void*>(0); 337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void UpdateAllocatedSpaceLimits(void* address, int size) { 34044f0eee88ff00398ff7f715fab053374d808c90dSteve Block ASSERT(limit_mutex != NULL); 34144f0eee88ff00398ff7f715fab053374d808c90dSteve Block ScopedLock lock(limit_mutex); 34244f0eee88ff00398ff7f715fab053374d808c90dSteve Block 343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block lowest_ever_allocated = Min(lowest_ever_allocated, address); 344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block highest_ever_allocated = 345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Max(highest_ever_allocated, 346a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size)); 347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool OS::IsOutsideAllocatedSpace(void* address) { 351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return address < lowest_ever_allocated || address >= highest_ever_allocated; 352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocksize_t OS::AllocateAlignment() { 356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return sysconf(_SC_PAGESIZE); 357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid* OS::Allocate(const size_t requested, 361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block size_t* allocated, 362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block bool is_executable) { 3633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const size_t msize = RoundUp(requested, AllocateAlignment()); 364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0); 3653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch void* addr = OS::GetRandomMmapAddr(); 3663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch void* mbase = mmap(addr, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (mbase == MAP_FAILED) { 36844f0eee88ff00398ff7f715fab053374d808c90dSteve Block LOG(i::Isolate::Current(), 36944f0eee88ff00398ff7f715fab053374d808c90dSteve Block StringEvent("OS::Allocate", "mmap failed")); 370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return NULL; 371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block *allocated = msize; 373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block UpdateAllocatedSpaceLimits(mbase, msize); 374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return mbase; 375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::Free(void* address, const size_t size) { 379a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // TODO(1240712): munmap has a return value which is ignored here. 380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int result = munmap(address, size); 381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block USE(result); 382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(result == 0); 383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::Sleep(int milliseconds) { 387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block unsigned int ms = static_cast<unsigned int>(milliseconds); 388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block usleep(1000 * ms); 389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::Abort() { 393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Redirect to std abort to signal abnormal program termination. 3943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (FLAG_break_on_abort) { 3953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch DebugBreak(); 3963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block abort(); 398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::DebugBreak() { 402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// TODO(lrn): Introduce processor define for runtime system (!= V8_ARCH_x, 403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// which is the architecture of generated code). 404756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick#if (defined(__arm__) || defined(__thumb__)) 405756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick# if defined(CAN_USE_ARMV5_INSTRUCTIONS) 406a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block asm("bkpt 0"); 407756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick# endif 4083100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#elif defined(__mips__) 4093100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu asm("break"); 410a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#else 411a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block asm("int $3"); 412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif 413a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 414a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 415a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 416a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass PosixMemoryMappedFile : public OS::MemoryMappedFile { 417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public: 418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block PosixMemoryMappedFile(FILE* file, void* memory, int size) 419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block : file_(file), memory_(memory), size_(size) { } 420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block virtual ~PosixMemoryMappedFile(); 421a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block virtual void* memory() { return memory_; } 4221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block virtual int size() { return size_; } 423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private: 424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block FILE* file_; 425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block void* memory_; 426a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int size_; 427a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 428a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 4301e0659c275bb392c045087af4f6b0d7565cb3d77Steve BlockOS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) { 431e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch FILE* file = fopen(name, "r+"); 4321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (file == NULL) return NULL; 4331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 4341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block fseek(file, 0, SEEK_END); 4351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block int size = ftell(file); 4361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 4371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block void* memory = 4383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch mmap(OS::GetRandomMmapAddr(), 4393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch size, 4403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch PROT_READ | PROT_WRITE, 4413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch MAP_SHARED, 4423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch fileno(file), 4433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 0); 4441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block return new PosixMemoryMappedFile(file, memory, size); 4451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block} 4461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 4471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block 448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockOS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size, 449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block void* initial) { 450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block FILE* file = fopen(name, "w+"); 451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (file == NULL) return NULL; 452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int result = fwrite(initial, size, 1, file); 453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (result < 1) { 454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block fclose(file); 455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return NULL; 456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block void* memory = 4583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch mmap(OS::GetRandomMmapAddr(), 4593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch size, 4603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch PROT_READ | PROT_WRITE, 4613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch MAP_SHARED, 4623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch fileno(file), 4633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 0); 464a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return new PosixMemoryMappedFile(file, memory, size); 465a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 466a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 467a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockPosixMemoryMappedFile::~PosixMemoryMappedFile() { 4693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (memory_) OS::Free(memory_, size_); 470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block fclose(file_); 471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 473a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 474a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::LogSharedLibraryAddresses() { 475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // This function assumes that the layout of the file is as follows: 476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // hex_start_addr-hex_end_addr rwxp <unused data> [binary_file_name] 477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If we encounter an unexpected situation we abort scanning further entries. 478d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block FILE* fp = fopen("/proc/self/maps", "r"); 479a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (fp == NULL) return; 480a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Allocate enough room to be able to store a full file name. 482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const int kLibNameLen = FILENAME_MAX + 1; 483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen)); 484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 48544f0eee88ff00398ff7f715fab053374d808c90dSteve Block i::Isolate* isolate = ISOLATE; 486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // This loop will terminate once the scanning hits an EOF. 487a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block while (true) { 488a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block uintptr_t start, end; 489a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block char attr_r, attr_w, attr_x, attr_p; 490a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Parse the addresses and permission bits at the beginning of the line. 491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (fscanf(fp, "%" V8PRIxPTR "-%" V8PRIxPTR, &start, &end) != 2) break; 492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (fscanf(fp, " %c%c%c%c", &attr_r, &attr_w, &attr_x, &attr_p) != 4) break; 493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 494a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int c; 4956ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (attr_r == 'r' && attr_w != 'w' && attr_x == 'x') { 4966ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Found a read-only executable entry. Skip characters until we reach 497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // the beginning of the filename or the end of the line. 498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block do { 499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block c = getc(fp); 500a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } while ((c != EOF) && (c != '\n') && (c != '/')); 501a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (c == EOF) break; // EOF: Was unexpected, just exit. 502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 503a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Process the filename if found. 504a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (c == '/') { 505a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ungetc(c, fp); // Push the '/' back into the stream to be read below. 506a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 507a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Read to the end of the line. Exit if the read fails. 508a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (fgets(lib_name, kLibNameLen, fp) == NULL) break; 509a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 510a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Drop the newline character read by fgets. We do not need to check 511a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // for a zero-length string because we know that we at least read the 512a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // '/' character. 513a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block lib_name[strlen(lib_name) - 1] = '\0'; 514a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 515a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // No library name found, just record the raw address range. 516a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block snprintf(lib_name, kLibNameLen, 517a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "%08" V8PRIxPTR "-%08" V8PRIxPTR, start, end); 518a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 51944f0eee88ff00398ff7f715fab053374d808c90dSteve Block LOG(isolate, SharedLibraryEvent(lib_name, start, end)); 520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 5213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Entry not describing executable data. Skip to end of line to set up 522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // reading the next entry. 523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block do { 524a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block c = getc(fp); 525a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } while ((c != EOF) && (c != '\n')); 526a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (c == EOF) break; 527a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 528a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 529a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block free(lib_name); 530a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block fclose(fp); 531a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 532a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 533a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 534f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochstatic const char kGCFakeMmap[] = "/tmp/__v8_gc__"; 535f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 536f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 537f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochvoid OS::SignalCodeMovingGC() { 538f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch // Support for ll_prof.py. 539f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch // 540f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch // The Linux profiler built into the kernel logs all mmap's with 541f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch // PROT_EXEC so that analysis tools can properly attribute ticks. We 542f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch // do a mmap with a name known by ll_prof.py and immediately munmap 543f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch // it. This injects a GC marker into the stream of events generated 544f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch // by the kernel and allows us to synchronize V8 code log and the 545f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch // kernel log. 546f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch int size = sysconf(_SC_PAGESIZE); 547f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch FILE* f = fopen(kGCFakeMmap, "w+"); 5483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch void* addr = mmap(OS::GetRandomMmapAddr(), 5493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch size, 5503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch PROT_READ | PROT_EXEC, 5513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch MAP_PRIVATE, 5523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch fileno(f), 5533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 0); 554f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ASSERT(addr != MAP_FAILED); 5553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch OS::Free(addr, size); 556f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch fclose(f); 557f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch} 558f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 559f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 560a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockint OS::StackWalk(Vector<OS::StackFrame> frames) { 561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // backtrace is a glibc extension. 562a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef __GLIBC__ 563a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int frames_size = frames.length(); 56425f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen ScopedVector<void*> addresses(frames_size); 565a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 56625f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen int frames_count = backtrace(addresses.start(), frames_size); 567a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 56825f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen char** symbols = backtrace_symbols(addresses.start(), frames_count); 569a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (symbols == NULL) { 570a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return kStackWalkError; 571a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 572a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 573a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (int i = 0; i < frames_count; i++) { 574a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frames[i].address = addresses[i]; 575a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Format a text representation of the frame based on the information 576a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // available. 577a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block SNPrintF(MutableCStrVector(frames[i].text, kStackWalkMaxTextLen), 578a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "%s", 579a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block symbols[i]); 580a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Make sure line termination is in place. 581a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block frames[i].text[kStackWalkMaxTextLen - 1] = '\0'; 582a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 583a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 584a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block free(symbols); 585a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 586a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return frames_count; 587a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#else // ndef __GLIBC__ 588a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return 0; 589a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif // ndef __GLIBC__ 590a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 591a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 592a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 593a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Constants used for mmap. 594a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic const int kMmapFd = -1; 595a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic const int kMmapFdOffset = 0; 596a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 5973ef787dbeca8a5fb1086949cda830dccee07bfbdBen MurdochVirtualMemory::VirtualMemory() : address_(NULL), size_(0) { } 598a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 599a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockVirtualMemory::VirtualMemory(size_t size) { 6003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch address_ = ReserveRegion(size); 601a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block size_ = size; 602a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 603a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 604a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 6053ef787dbeca8a5fb1086949cda830dccee07bfbdBen MurdochVirtualMemory::VirtualMemory(size_t size, size_t alignment) 6063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch : address_(NULL), size_(0) { 6073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment()))); 6083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch size_t request_size = RoundUp(size + alignment, 6093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch static_cast<intptr_t>(OS::AllocateAlignment())); 6103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch void* reservation = mmap(OS::GetRandomMmapAddr(), 6113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch request_size, 6123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch PROT_NONE, 6133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, 6143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch kMmapFd, 6153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch kMmapFdOffset); 6163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (reservation == MAP_FAILED) return; 6173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Address base = static_cast<Address>(reservation); 6193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Address aligned_base = RoundUp(base, alignment); 6203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT_LE(base, aligned_base); 6213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Unmap extra memory reserved before and after the desired block. 6233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (aligned_base != base) { 6243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch size_t prefix_size = static_cast<size_t>(aligned_base - base); 6253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch OS::Free(base, prefix_size); 6263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch request_size -= prefix_size; 6273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 6283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch size_t aligned_size = RoundUp(size, OS::AllocateAlignment()); 6303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT_LE(aligned_size, request_size); 6313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (aligned_size != request_size) { 6333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch size_t suffix_size = request_size - aligned_size; 6343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch OS::Free(aligned_base + aligned_size, suffix_size); 6353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch request_size -= suffix_size; 6363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 6373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(aligned_size == request_size); 6393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch address_ = static_cast<void*>(aligned_base); 6413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch size_ = aligned_size; 6423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 6433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 645a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockVirtualMemory::~VirtualMemory() { 646a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (IsReserved()) { 6473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch bool result = ReleaseRegion(address(), size()); 6483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ASSERT(result); 6493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch USE(result); 650a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 651a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 652a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 653a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 654a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool VirtualMemory::IsReserved() { 6553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch return address_ != NULL; 6563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 6573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid VirtualMemory::Reset() { 6603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch address_ = NULL; 6613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch size_ = 0; 662a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 663a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 664a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 665a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool VirtualMemory::Commit(void* address, size_t size, bool is_executable) { 6663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch return CommitRegion(address, size, is_executable); 6673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 6683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool VirtualMemory::Uncommit(void* address, size_t size) { 6713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch return UncommitRegion(address, size); 6723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 6733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool VirtualMemory::Guard(void* address) { 6763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch OS::Guard(address, OS::CommitPageSize()); 6773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch return true; 6783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 6793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid* VirtualMemory::ReserveRegion(size_t size) { 6823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch void* result = mmap(OS::GetRandomMmapAddr(), 6833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch size, 6843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch PROT_NONE, 6853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, 6863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch kMmapFd, 6873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch kMmapFdOffset); 6883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (result == MAP_FAILED) return NULL; 6903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch return result; 6923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 6933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 6953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) { 696a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0); 6973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (MAP_FAILED == mmap(base, 6983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch size, 6993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch prot, 700a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 7013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch kMmapFd, 7023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch kMmapFdOffset)) { 703a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return false; 704a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 705a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch UpdateAllocatedSpaceLimits(base, size); 707a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return true; 708a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 709a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 710a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool VirtualMemory::UncommitRegion(void* base, size_t size) { 7123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch return mmap(base, 7133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch size, 7143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch PROT_NONE, 715a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_FIXED, 7163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch kMmapFd, 7173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch kMmapFdOffset) != MAP_FAILED; 7183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 7193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 7203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 7213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool VirtualMemory::ReleaseRegion(void* base, size_t size) { 7223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch return munmap(base, size) == 0; 723a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 724a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 725a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7268b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdochclass Thread::PlatformData : public Malloced { 727a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public: 7288b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch PlatformData() : thread_(kNoThread) {} 729a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 730a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block pthread_t thread_; // Thread handle for pthread. 731a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 732a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7333fb3ca8c7ca439d408449a395897395c0faae8d1Ben MurdochThread::Thread(const Options& options) 7348b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch : data_(new PlatformData()), 7353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch stack_size_(options.stack_size()) { 7363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch set_name(options.name()); 737a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 738a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 739a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 740a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockThread::~Thread() { 7418b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch delete data_; 742a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 743a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 744a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 745a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void* ThreadEntry(void* arg) { 746a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Thread* thread = reinterpret_cast<Thread*>(arg); 747a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // This is also initialized by the first argument to pthread_create() but we 748a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // don't know which thread will run first (the original thread or the new 749a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // one) so we initialize it here too. 75069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch#ifdef PR_SET_NAME 7519fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block prctl(PR_SET_NAME, 7529fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block reinterpret_cast<unsigned long>(thread->name()), // NOLINT 7539fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 0, 0, 0); 75469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch#endif 7558b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch thread->data()->thread_ = pthread_self(); 7568b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch ASSERT(thread->data()->thread_ != kNoThread); 757a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block thread->Run(); 758a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return NULL; 759a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 760a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 7619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 7629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid Thread::set_name(const char* name) { 7639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block strncpy(name_, name, sizeof(name_)); 7649fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block name_[sizeof(name_) - 1] = '\0'; 7659fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block} 7669fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block 767a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 768a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Thread::Start() { 76944f0eee88ff00398ff7f715fab053374d808c90dSteve Block pthread_attr_t* attr_ptr = NULL; 77044f0eee88ff00398ff7f715fab053374d808c90dSteve Block pthread_attr_t attr; 77144f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (stack_size_ > 0) { 77244f0eee88ff00398ff7f715fab053374d808c90dSteve Block pthread_attr_init(&attr); 77344f0eee88ff00398ff7f715fab053374d808c90dSteve Block pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_)); 77444f0eee88ff00398ff7f715fab053374d808c90dSteve Block attr_ptr = &attr; 77544f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 7763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch int result = pthread_create(&data_->thread_, attr_ptr, ThreadEntry, this); 7773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch CHECK_EQ(0, result); 7788b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch ASSERT(data_->thread_ != kNoThread); 779a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 780a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 781a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 782a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Thread::Join() { 7838b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch pthread_join(data_->thread_, NULL); 784a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 785a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 786a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 787a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockThread::LocalStorageKey Thread::CreateThreadLocalKey() { 788a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block pthread_key_t key; 789a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int result = pthread_key_create(&key, NULL); 790a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block USE(result); 791a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(result == 0); 792a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return static_cast<LocalStorageKey>(key); 793a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 794a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 795a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 796a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Thread::DeleteThreadLocalKey(LocalStorageKey key) { 797a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block pthread_key_t pthread_key = static_cast<pthread_key_t>(key); 798a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int result = pthread_key_delete(pthread_key); 799a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block USE(result); 800a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(result == 0); 801a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 802a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 803a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 804a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid* Thread::GetThreadLocal(LocalStorageKey key) { 805a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block pthread_key_t pthread_key = static_cast<pthread_key_t>(key); 806a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return pthread_getspecific(pthread_key); 807a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 808a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 809a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 810a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Thread::SetThreadLocal(LocalStorageKey key, void* value) { 811a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block pthread_key_t pthread_key = static_cast<pthread_key_t>(key); 812a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block pthread_setspecific(pthread_key, value); 813a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 814a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 815a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 816a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Thread::YieldCPU() { 817a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block sched_yield(); 818a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 819a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 820a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 821a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass LinuxMutex : public Mutex { 822a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public: 823a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block LinuxMutex() { 824a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block pthread_mutexattr_t attrs; 825a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int result = pthread_mutexattr_init(&attrs); 826a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(result == 0); 827a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE); 828a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(result == 0); 829a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block result = pthread_mutex_init(&mutex_, &attrs); 830a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ASSERT(result == 0); 8313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch USE(result); 832a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 833a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 834a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block virtual ~LinuxMutex() { pthread_mutex_destroy(&mutex_); } 835a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 836a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block virtual int Lock() { 837a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int result = pthread_mutex_lock(&mutex_); 838a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return result; 839a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 840a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 841a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block virtual int Unlock() { 842a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int result = pthread_mutex_unlock(&mutex_); 843a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return result; 844a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 845a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 846b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch virtual bool TryLock() { 847b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch int result = pthread_mutex_trylock(&mutex_); 848b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Return false if the lock is busy and locking failed. 849b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (result == EBUSY) { 850b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch return false; 851b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 852b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(result == 0); // Verify no other errors. 853b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch return true; 854b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 855b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 856a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private: 857a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block pthread_mutex_t mutex_; // Pthread mutex for POSIX platforms. 858a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 859a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 860a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 861a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockMutex* OS::CreateMutex() { 862a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return new LinuxMutex(); 863a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 864a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 865a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 866a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass LinuxSemaphore : public Semaphore { 867a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public: 868a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block explicit LinuxSemaphore(int count) { sem_init(&sem_, 0, count); } 869a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block virtual ~LinuxSemaphore() { sem_destroy(&sem_); } 870a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 871a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block virtual void Wait(); 872a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block virtual bool Wait(int timeout); 873a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block virtual void Signal() { sem_post(&sem_); } 874a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private: 875a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block sem_t sem_; 876a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 877a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 878a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 879a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid LinuxSemaphore::Wait() { 880a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block while (true) { 881a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int result = sem_wait(&sem_); 882a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (result == 0) return; // Successfully got semaphore. 883a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup. 884a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 885a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 886a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 887a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 888a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifndef TIMEVAL_TO_TIMESPEC 889a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#define TIMEVAL_TO_TIMESPEC(tv, ts) do { \ 890a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block (ts)->tv_sec = (tv)->tv_sec; \ 891a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block (ts)->tv_nsec = (tv)->tv_usec * 1000; \ 892a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} while (false) 893a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif 894a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 895a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 896a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool LinuxSemaphore::Wait(int timeout) { 897a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const long kOneSecondMicros = 1000000; // NOLINT 898a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 899a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Split timeout into second and nanosecond parts. 900a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block struct timeval delta; 901a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block delta.tv_usec = timeout % kOneSecondMicros; 902a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block delta.tv_sec = timeout / kOneSecondMicros; 903a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 904a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block struct timeval current_time; 905a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Get the current time. 906a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (gettimeofday(¤t_time, NULL) == -1) { 907a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return false; 908a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 909a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 910a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Calculate time for end of timeout. 911a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block struct timeval end_time; 912a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block timeradd(¤t_time, &delta, &end_time); 913a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 914a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block struct timespec ts; 915a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block TIMEVAL_TO_TIMESPEC(&end_time, &ts); 916a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Wait for semaphore signalled or timeout. 917a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block while (true) { 918a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block int result = sem_timedwait(&sem_, &ts); 919a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (result == 0) return true; // Successfully got semaphore. 920a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (result > 0) { 921a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // For glibc prior to 2.3.4 sem_timedwait returns the error instead of -1. 922a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block errno = result; 923a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block result = -1; 924a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 925a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (result == -1 && errno == ETIMEDOUT) return false; // Timeout. 926a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup. 927a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 928a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 929a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 930a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 931a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockSemaphore* OS::CreateSemaphore(int count) { 932a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return new LinuxSemaphore(count); 933a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 934a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 935a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 9361bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turner#if !defined(__GLIBC__) && (defined(__arm__) || defined(__thumb__)) 9371bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turner// Android runs a fairly new Linux kernel, so signal info is there, 9381bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turner// but the C library doesn't have the structs defined. 939a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 9401bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turnerstruct sigcontext { 9411bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turner uint32_t trap_no; 9421bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turner uint32_t error_code; 9431bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turner uint32_t oldmask; 9441bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turner uint32_t gregs[16]; 9451bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turner uint32_t arm_cpsr; 9461bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turner uint32_t fault_address; 9471bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turner}; 9481bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turnertypedef uint32_t __sigset_t; 949a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocktypedef struct sigcontext mcontext_t; 950a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocktypedef struct ucontext { 951a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block uint32_t uc_flags; 952d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block struct ucontext* uc_link; 953a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block stack_t uc_stack; 954a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block mcontext_t uc_mcontext; 9551bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turner __sigset_t uc_sigmask; 956a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} ucontext_t; 9571bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turnerenum ArmRegisters {R15 = 15, R13 = 13, R11 = 11}; 958a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 9593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#elif !defined(__GLIBC__) && defined(__mips__) 9601bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turner// MIPS version of sigcontext, for Android bionic. 9611bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turnerstruct sigcontext { 9623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch uint32_t regmask; 9633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch uint32_t status; 9643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch uint64_t pc; 9653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch uint64_t gregs[32]; 9663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch uint64_t fpregs[32]; 9673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch uint32_t acx; 9683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch uint32_t fpc_csr; 9693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch uint32_t fpc_eir; 9703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch uint32_t used_math; 9713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch uint32_t dsp; 9723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch uint64_t mdhi; 9733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch uint64_t mdlo; 9743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch uint32_t hi1; 9753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch uint32_t lo1; 9763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch uint32_t hi2; 9773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch uint32_t lo2; 9783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch uint32_t hi3; 9793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch uint32_t lo3; 9801bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turner}; 9811bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turnertypedef uint32_t __sigset_t; 9821bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turnertypedef struct sigcontext mcontext_t; 9833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochtypedef struct ucontext { 9843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch uint32_t uc_flags; 9853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch struct ucontext* uc_link; 9863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch stack_t uc_stack; 9873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch mcontext_t uc_mcontext; 9881bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turner __sigset_t uc_sigmask; 9893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} ucontext_t; 9903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 9913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#elif !defined(__GLIBC__) && defined(__i386__) 9923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// x86 version for Android. 9931bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turnerstruct sigcontext { 9947a930e02c0b52d70d022ed255db551895dfe1157Ben Murdoch uint32_t gregs[19]; 9957a930e02c0b52d70d022ed255db551895dfe1157Ben Murdoch void* fpregs; 9967a930e02c0b52d70d022ed255db551895dfe1157Ben Murdoch uint32_t oldmask; 9977a930e02c0b52d70d022ed255db551895dfe1157Ben Murdoch uint32_t cr2; 9981bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turner}; 9993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 10001bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turnertypedef uint32_t __sigset_t; 10011bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turnertypedef struct sigcontext mcontext_t; 10023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochtypedef struct ucontext { 10037a930e02c0b52d70d022ed255db551895dfe1157Ben Murdoch uint32_t uc_flags; 10047a930e02c0b52d70d022ed255db551895dfe1157Ben Murdoch struct ucontext* uc_link; 10053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch stack_t uc_stack; 10063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch mcontext_t uc_mcontext; 10071bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turner __sigset_t uc_sigmask; 10083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} ucontext_t; 10093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochenum { REG_EBP = 6, REG_ESP = 7, REG_EIP = 14 }; 1010a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif 1011a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1012a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1013b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochstatic int GetThreadID() { 10148a0da0b040a743677f20f29548ff3380ffb9a5edDavid 'Digit' Turner // Glibc doesn't provide a wrapper for gettid(2). 10151bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turner#if defined(ANDROID) 10161bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turner return syscall(__NR_gettid); 10171bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turner#else 1018b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch return syscall(SYS_gettid); 101944f0eee88ff00398ff7f715fab053374d808c90dSteve Block#endif 1020b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 1021b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1022b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1023a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { 1024a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block USE(info); 1025a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (signal != SIGPROF) return; 102644f0eee88ff00398ff7f715fab053374d808c90dSteve Block Isolate* isolate = Isolate::UncheckedCurrent(); 102744f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) { 102844f0eee88ff00398ff7f715fab053374d808c90dSteve Block // We require a fully initialized and entered isolate. 102944f0eee88ff00398ff7f715fab053374d808c90dSteve Block return; 103044f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 10318b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch if (v8::Locker::IsActive() && 10328b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch !isolate->thread_manager()->IsLockedByCurrentThread()) { 10338b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch return; 10348b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch } 10358b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch 103644f0eee88ff00398ff7f715fab053374d808c90dSteve Block Sampler* sampler = isolate->logger()->sampler(); 103744f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (sampler == NULL || !sampler->IsActive()) return; 1038a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 10396ded16be15dd865a9b21ea304d5273c8be299c87Steve Block TickSample sample_obj; 104044f0eee88ff00398ff7f715fab053374d808c90dSteve Block TickSample* sample = CpuProfiler::TickSampleEvent(isolate); 10416ded16be15dd865a9b21ea304d5273c8be299c87Steve Block if (sample == NULL) sample = &sample_obj; 1042a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1043b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Extracting the sample from the context is extremely machine dependent. 1044b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); 1045b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch mcontext_t& mcontext = ucontext->uc_mcontext; 104644f0eee88ff00398ff7f715fab053374d808c90dSteve Block sample->state = isolate->current_vm_state(); 1047a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#if V8_HOST_ARCH_IA32 1048b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]); 1049b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]); 1050b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]); 1051a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#elif V8_HOST_ARCH_X64 1052b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]); 1053b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]); 1054b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]); 1055a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#elif V8_HOST_ARCH_ARM 1056a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// An undefined macro evaluates to 0, so this applies to Android's Bionic also. 10571bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turner#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3)) 1058b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch sample->pc = reinterpret_cast<Address>(mcontext.gregs[R15]); 1059b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch sample->sp = reinterpret_cast<Address>(mcontext.gregs[R13]); 1060b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch sample->fp = reinterpret_cast<Address>(mcontext.gregs[R11]); 1061a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#else 1062b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch sample->pc = reinterpret_cast<Address>(mcontext.arm_pc); 1063b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch sample->sp = reinterpret_cast<Address>(mcontext.arm_sp); 1064b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch sample->fp = reinterpret_cast<Address>(mcontext.arm_fp); 10651bbccaca327b1fed6859a62f6d3ed75a75e4856aDavid 'Digit' Turner#endif // (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3)) 10663100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu#elif V8_HOST_ARCH_MIPS 10673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch sample->pc = reinterpret_cast<Address>(mcontext.pc); 10683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch sample->sp = reinterpret_cast<Address>(mcontext.gregs[29]); 10693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch sample->fp = reinterpret_cast<Address>(mcontext.gregs[30]); 10703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#endif // V8_HOST_ARCH_* 107144f0eee88ff00398ff7f715fab053374d808c90dSteve Block sampler->SampleStack(sample); 107244f0eee88ff00398ff7f715fab053374d808c90dSteve Block sampler->Tick(sample); 1073a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1074a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1075a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1076a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass Sampler::PlatformData : public Malloced { 1077a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public: 107844f0eee88ff00398ff7f715fab053374d808c90dSteve Block PlatformData() : vm_tid_(GetThreadID()) {} 107944f0eee88ff00398ff7f715fab053374d808c90dSteve Block 108044f0eee88ff00398ff7f715fab053374d808c90dSteve Block int vm_tid() const { return vm_tid_; } 108144f0eee88ff00398ff7f715fab053374d808c90dSteve Block 108244f0eee88ff00398ff7f715fab053374d808c90dSteve Block private: 108344f0eee88ff00398ff7f715fab053374d808c90dSteve Block const int vm_tid_; 108444f0eee88ff00398ff7f715fab053374d808c90dSteve Block}; 108544f0eee88ff00398ff7f715fab053374d808c90dSteve Block 108644f0eee88ff00398ff7f715fab053374d808c90dSteve Block 108744f0eee88ff00398ff7f715fab053374d808c90dSteve Blockclass SignalSender : public Thread { 108844f0eee88ff00398ff7f715fab053374d808c90dSteve Block public: 1089b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch enum SleepInterval { 109044f0eee88ff00398ff7f715fab053374d808c90dSteve Block HALF_INTERVAL, 109144f0eee88ff00398ff7f715fab053374d808c90dSteve Block FULL_INTERVAL 1092b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch }; 1093b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 10943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch static const int kSignalSenderStackSize = 64 * KB; 10953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 109644f0eee88ff00398ff7f715fab053374d808c90dSteve Block explicit SignalSender(int interval) 10973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch : Thread(Thread::Options("SignalSender", kSignalSenderStackSize)), 10985913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck vm_tgid_(getpid()), 109944f0eee88ff00398ff7f715fab053374d808c90dSteve Block interval_(interval) {} 110044f0eee88ff00398ff7f715fab053374d808c90dSteve Block 1101053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block static void InstallSignalHandler() { 1102053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block struct sigaction sa; 1103053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block sa.sa_sigaction = ProfilerSignalHandler; 1104053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block sigemptyset(&sa.sa_mask); 1105053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block sa.sa_flags = SA_RESTART | SA_SIGINFO; 1106053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block signal_handler_installed_ = 1107053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0); 1108053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block } 1109053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block 1110053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block static void RestoreSignalHandler() { 1111053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block if (signal_handler_installed_) { 1112053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block sigaction(SIGPROF, &old_signal_handler_, 0); 1113053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block signal_handler_installed_ = false; 1114053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block } 1115053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block } 1116053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block 111744f0eee88ff00398ff7f715fab053374d808c90dSteve Block static void AddActiveSampler(Sampler* sampler) { 11183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ScopedLock lock(mutex_.Pointer()); 111944f0eee88ff00398ff7f715fab053374d808c90dSteve Block SamplerRegistry::AddActiveSampler(sampler); 112044f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (instance_ == NULL) { 1121053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block // Start a thread that will send SIGPROF signal to VM threads, 1122053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block // when CPU profiling will be enabled. 112344f0eee88ff00398ff7f715fab053374d808c90dSteve Block instance_ = new SignalSender(sampler->interval()); 112444f0eee88ff00398ff7f715fab053374d808c90dSteve Block instance_->Start(); 112544f0eee88ff00398ff7f715fab053374d808c90dSteve Block } else { 112644f0eee88ff00398ff7f715fab053374d808c90dSteve Block ASSERT(instance_->interval_ == sampler->interval()); 112744f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 1128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 1129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 113044f0eee88ff00398ff7f715fab053374d808c90dSteve Block static void RemoveActiveSampler(Sampler* sampler) { 11313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ScopedLock lock(mutex_.Pointer()); 113244f0eee88ff00398ff7f715fab053374d808c90dSteve Block SamplerRegistry::RemoveActiveSampler(sampler); 113344f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) { 11343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_); 113544f0eee88ff00398ff7f715fab053374d808c90dSteve Block delete instance_; 113644f0eee88ff00398ff7f715fab053374d808c90dSteve Block instance_ = NULL; 1137053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block RestoreSignalHandler(); 113844f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 113944f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 114044f0eee88ff00398ff7f715fab053374d808c90dSteve Block 114144f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Implement Thread::Run(). 114244f0eee88ff00398ff7f715fab053374d808c90dSteve Block virtual void Run() { 114344f0eee88ff00398ff7f715fab053374d808c90dSteve Block SamplerRegistry::State state; 114444f0eee88ff00398ff7f715fab053374d808c90dSteve Block while ((state = SamplerRegistry::GetState()) != 114544f0eee88ff00398ff7f715fab053374d808c90dSteve Block SamplerRegistry::HAS_NO_SAMPLERS) { 114644f0eee88ff00398ff7f715fab053374d808c90dSteve Block bool cpu_profiling_enabled = 114744f0eee88ff00398ff7f715fab053374d808c90dSteve Block (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS); 114844f0eee88ff00398ff7f715fab053374d808c90dSteve Block bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled(); 11493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch if (cpu_profiling_enabled && !signal_handler_installed_) { 1150053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block InstallSignalHandler(); 11513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch } else if (!cpu_profiling_enabled && signal_handler_installed_) { 1152053d10c438f14580aaf4ab1b2aad93a5a4fe8b82Steve Block RestoreSignalHandler(); 11533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch } 115444f0eee88ff00398ff7f715fab053374d808c90dSteve Block // When CPU profiling is enabled both JavaScript and C++ code is 115544f0eee88ff00398ff7f715fab053374d808c90dSteve Block // profiled. We must not suspend. 115644f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (!cpu_profiling_enabled) { 115744f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (rate_limiter_.SuspendIfNecessary()) continue; 115844f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 115944f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (cpu_profiling_enabled && runtime_profiler_enabled) { 116044f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) { 116144f0eee88ff00398ff7f715fab053374d808c90dSteve Block return; 116244f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 1163b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Sleep(HALF_INTERVAL); 116444f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) { 116544f0eee88ff00398ff7f715fab053374d808c90dSteve Block return; 116644f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 1167b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Sleep(HALF_INTERVAL); 1168b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 116944f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (cpu_profiling_enabled) { 117044f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, 117144f0eee88ff00398ff7f715fab053374d808c90dSteve Block this)) { 117244f0eee88ff00398ff7f715fab053374d808c90dSteve Block return; 117344f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 117444f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 117544f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (runtime_profiler_enabled) { 117644f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, 117744f0eee88ff00398ff7f715fab053374d808c90dSteve Block NULL)) { 117844f0eee88ff00398ff7f715fab053374d808c90dSteve Block return; 117944f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 118044f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 1181b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch Sleep(FULL_INTERVAL); 11823e5fa29ddb82551500b118e9bf37af3966277b70Teng-Hui Zhu } 11835913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck } 11845913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck } 11855913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck 118644f0eee88ff00398ff7f715fab053374d808c90dSteve Block static void DoCpuProfile(Sampler* sampler, void* raw_sender) { 118744f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (!sampler->IsProfiling()) return; 118844f0eee88ff00398ff7f715fab053374d808c90dSteve Block SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender); 118944f0eee88ff00398ff7f715fab053374d808c90dSteve Block sender->SendProfilingSignal(sampler->platform_data()->vm_tid()); 119044f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 119144f0eee88ff00398ff7f715fab053374d808c90dSteve Block 119244f0eee88ff00398ff7f715fab053374d808c90dSteve Block static void DoRuntimeProfile(Sampler* sampler, void* ignored) { 119344f0eee88ff00398ff7f715fab053374d808c90dSteve Block if (!sampler->isolate()->IsInitialized()) return; 119444f0eee88ff00398ff7f715fab053374d808c90dSteve Block sampler->isolate()->runtime_profiler()->NotifyTick(); 119544f0eee88ff00398ff7f715fab053374d808c90dSteve Block } 119644f0eee88ff00398ff7f715fab053374d808c90dSteve Block 119744f0eee88ff00398ff7f715fab053374d808c90dSteve Block void SendProfilingSignal(int tid) { 1198e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch if (!signal_handler_installed_) return; 1199b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Glibc doesn't provide a wrapper for tgkill(2). 120044f0eee88ff00398ff7f715fab053374d808c90dSteve Block#if defined(ANDROID) 120144f0eee88ff00398ff7f715fab053374d808c90dSteve Block syscall(__NR_tgkill, vm_tgid_, tid, SIGPROF); 120244f0eee88ff00398ff7f715fab053374d808c90dSteve Block#else 120344f0eee88ff00398ff7f715fab053374d808c90dSteve Block syscall(SYS_tgkill, vm_tgid_, tid, SIGPROF); 120444f0eee88ff00398ff7f715fab053374d808c90dSteve Block#endif 1205b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1206b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1207b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch void Sleep(SleepInterval full_or_half) { 1208b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Convert ms to us and subtract 100 us to compensate delays 1209b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // occuring during signal delivery. 121044f0eee88ff00398ff7f715fab053374d808c90dSteve Block useconds_t interval = interval_ * 1000 - 100; 1211b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (full_or_half == HALF_INTERVAL) interval /= 2; 12123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#if defined(ANDROID) 12133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch usleep(interval); 12143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#else 1215b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch int result = usleep(interval); 1216b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch#ifdef DEBUG 1217b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (result != 0 && errno != EINTR) { 1218b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch fprintf(stderr, 1219b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch "SignalSender usleep error; interval = %u, errno = %d\n", 1220b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch interval, 1221b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch errno); 1222b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(result == 0 || errno == EINTR); 1223b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 12243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#endif // DEBUG 1225b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch USE(result); 12263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#endif // ANDROID 1227b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 1228b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 122944f0eee88ff00398ff7f715fab053374d808c90dSteve Block const int vm_tgid_; 123044f0eee88ff00398ff7f715fab053374d808c90dSteve Block const int interval_; 1231b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch RuntimeProfilerRateLimiter rate_limiter_; 123244f0eee88ff00398ff7f715fab053374d808c90dSteve Block 123344f0eee88ff00398ff7f715fab053374d808c90dSteve Block // Protects the process wide state below. 12343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch static LazyMutex mutex_; 123544f0eee88ff00398ff7f715fab053374d808c90dSteve Block static SignalSender* instance_; 123644f0eee88ff00398ff7f715fab053374d808c90dSteve Block static bool signal_handler_installed_; 123744f0eee88ff00398ff7f715fab053374d808c90dSteve Block static struct sigaction old_signal_handler_; 123844f0eee88ff00398ff7f715fab053374d808c90dSteve Block 12393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch private: 124044f0eee88ff00398ff7f715fab053374d808c90dSteve Block DISALLOW_COPY_AND_ASSIGN(SignalSender); 1241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 1242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 12443ef787dbeca8a5fb1086949cda830dccee07bfbdBen MurdochLazyMutex SignalSender::mutex_ = LAZY_MUTEX_INITIALIZER; 124544f0eee88ff00398ff7f715fab053374d808c90dSteve BlockSignalSender* SignalSender::instance_ = NULL; 124644f0eee88ff00398ff7f715fab053374d808c90dSteve Blockstruct sigaction SignalSender::old_signal_handler_; 124744f0eee88ff00398ff7f715fab053374d808c90dSteve Blockbool SignalSender::signal_handler_installed_ = false; 12485913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck 12495913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck 125044f0eee88ff00398ff7f715fab053374d808c90dSteve BlockSampler::Sampler(Isolate* isolate, int interval) 125144f0eee88ff00398ff7f715fab053374d808c90dSteve Block : isolate_(isolate), 125244f0eee88ff00398ff7f715fab053374d808c90dSteve Block interval_(interval), 1253b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch profiling_(false), 12548a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang active_(false), 12558a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang samples_taken_(0) { 125644f0eee88ff00398ff7f715fab053374d808c90dSteve Block data_ = new PlatformData; 1257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockSampler::~Sampler() { 126144f0eee88ff00398ff7f715fab053374d808c90dSteve Block ASSERT(!IsActive()); 1262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block delete data_; 1263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Sampler::Start() { 1267b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch ASSERT(!IsActive()); 1268b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch SetActive(true); 126944f0eee88ff00398ff7f715fab053374d808c90dSteve Block SignalSender::AddActiveSampler(this); 1270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Sampler::Stop() { 127444f0eee88ff00398ff7f715fab053374d808c90dSteve Block ASSERT(IsActive()); 127544f0eee88ff00398ff7f715fab053374d808c90dSteve Block SignalSender::RemoveActiveSampler(this); 1276b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch SetActive(false); 1277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 1278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} } // namespace v8::internal 1281