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(&current_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(&current_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