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 FreeBSD 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>
34a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <sys/time.h>
35a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <sys/resource.h>
36a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <sys/types.h>
37a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <sys/ucontext.h>
38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <stdlib.h>
39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <sys/types.h>  // mmap & munmap
41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <sys/mman.h>   // mmap & munmap
42a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <sys/stat.h>   // open
43a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <sys/fcntl.h>  // open
44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <unistd.h>     // getpagesize
4544f0eee88ff00398ff7f715fab053374d808c90dSteve Block// If you don't have execinfo.h then you need devel/libexecinfo from ports.
46a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <execinfo.h>   // backtrace, backtrace_symbols
47a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <strings.h>    // index
48a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <errno.h>
49a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <stdarg.h>
50a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <limits.h>
51a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
52a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#undef MAP_TYPE
53a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
54a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "v8.h"
55257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch#include "v8threads.h"
56a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#include "platform-posix.h"
58a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "platform.h"
59b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch#include "vm-state-inl.h"
60a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
62a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace v8 {
63a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace internal {
64a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
65a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 0 is never a valid thread id on FreeBSD since tids and pids share a
66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// name space and pid 0 is used to kill the group (see man 2 kill).
67a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic const pthread_t kNoThread = (pthread_t) 0;
68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
69a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
70a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdouble ceiling(double x) {
71a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Correct as on OS X
72a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (-1.0 < x && x < 0.0) {
73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        return -0.0;
74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
75a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        return ceil(x);
76a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
77a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
78a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
79a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8044f0eee88ff00398ff7f715fab053374d808c90dSteve Blockstatic Mutex* limit_mutex = NULL;
8144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
8244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid OS::SetUp() {
84a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Seed the random number generator.
85a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Convert the current time to a 64-bit integer first, before converting it
86a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // to an unsigned. Going directly can cause an overflow and the seed to be
87a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // set to all ones. The seed will be identical for different instances that
88a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // call this setup code within the same millisecond.
89a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
90a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  srandom(static_cast<unsigned int>(seed));
9144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  limit_mutex = CreateMutex();
92a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
93a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
94a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid OS::PostSetUp() {
963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Math functions depend on CPU features therefore they are initialized after
973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // CPU.
983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  MathSetup();
993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
1003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1027f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochvoid OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) {
1037f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __asm__ __volatile__("" : : : "memory");
1047f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  *ptr = value;
1057f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch}
1067f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
1077f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
108d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockuint64_t OS::CpuFeaturesImpliedByPlatform() {
109d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return 0;  // FreeBSD runs on anything.
110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockint OS::ActivationFrameAlignment() {
114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // 16 byte alignment on FreeBSD
115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return 16;
116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
119d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarkeconst char* OS::LocalTimezone(double time) {
120d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  if (isnan(time)) return "";
121d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  time_t tv = static_cast<time_t>(floor(time/msPerSecond));
122d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  struct tm* t = localtime(&tv);
123d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  if (NULL == t) return "";
124d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  return t->tm_zone;
125d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke}
126d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
127d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
128d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarkedouble OS::LocalTimeOffset() {
129d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  time_t tv = time(NULL);
130d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  struct tm* t = localtime(&tv);
131d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // tm_gmtoff includes any daylight savings offset, so subtract it.
132d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  return static_cast<double>(t->tm_gmtoff * msPerSecond -
133d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                             (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
134d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke}
135d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
136d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// We keep the lowest and highest addresses mapped as a quick way of
138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// determining that pointers are outside the heap (used mostly in assertions
1393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// and verification).  The estimate is conservative, i.e., not all addresses in
140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 'allocated' space are actually allocated to our heap.  The range is
141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// [lowest, highest), inclusive on the low and and exclusive on the high end.
142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void* highest_ever_allocated = reinterpret_cast<void*>(0);
144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void UpdateAllocatedSpaceLimits(void* address, int size) {
14744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ASSERT(limit_mutex != NULL);
14844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ScopedLock lock(limit_mutex);
14944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  lowest_ever_allocated = Min(lowest_ever_allocated, address);
151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  highest_ever_allocated =
152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Max(highest_ever_allocated,
153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool OS::IsOutsideAllocatedSpace(void* address) {
158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return address < lowest_ever_allocated || address >= highest_ever_allocated;
159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocksize_t OS::AllocateAlignment() {
163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return getpagesize();
164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid* OS::Allocate(const size_t requested,
168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                   size_t* allocated,
169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                   bool executable) {
170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const size_t msize = RoundUp(requested, getpagesize());
171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (mbase == MAP_FAILED) {
17544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    LOG(ISOLATE, StringEvent("OS::Allocate", "mmap failed"));
176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return NULL;
177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  *allocated = msize;
179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  UpdateAllocatedSpaceLimits(mbase, msize);
180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return mbase;
181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::Free(void* buf, const size_t length) {
185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // TODO(1240712): munmap has a return value which is ignored here.
186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int result = munmap(buf, length);
187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  USE(result);
188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(result == 0);
189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::Sleep(int milliseconds) {
193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  unsigned int ms = static_cast<unsigned int>(milliseconds);
194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  usleep(1000 * ms);
195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::Abort() {
199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Redirect to std abort to signal abnormal program termination.
200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  abort();
201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::DebugBreak() {
205756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick#if (defined(__arm__) || defined(__thumb__))
206756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick# if defined(CAN_USE_ARMV5_INSTRUCTIONS)
207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  asm("bkpt 0");
208756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick# endif
209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#else
210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  asm("int $3");
211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass PosixMemoryMappedFile : public OS::MemoryMappedFile {
216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  PosixMemoryMappedFile(FILE* file, void* memory, int size)
218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    : file_(file), memory_(memory), size_(size) { }
219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual ~PosixMemoryMappedFile();
220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual void* memory() { return memory_; }
2211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  virtual int size() { return size_; }
222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  FILE* file_;
224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void* memory_;
225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int size_;
226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2291e0659c275bb392c045087af4f6b0d7565cb3d77Steve BlockOS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
230e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  FILE* file = fopen(name, "r+");
2311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  if (file == NULL) return NULL;
2321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  fseek(file, 0, SEEK_END);
2341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  int size = ftell(file);
2351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  void* memory =
2371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
2381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  return new PosixMemoryMappedFile(file, memory, size);
2391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block}
2401e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockOS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    void* initial) {
244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  FILE* file = fopen(name, "w+");
245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (file == NULL) return NULL;
246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int result = fwrite(initial, size, 1, file);
247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (result < 1) {
248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    fclose(file);
249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return NULL;
250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void* memory =
252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return new PosixMemoryMappedFile(file, memory, size);
254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockPosixMemoryMappedFile::~PosixMemoryMappedFile() {
258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (memory_) munmap(memory_, size_);
259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  fclose(file_);
260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic unsigned StringToLong(char* buffer) {
264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return static_cast<unsigned>(strtol(buffer, NULL, 16));  // NOLINT
265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::LogSharedLibraryAddresses() {
269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static const int MAP_LENGTH = 1024;
270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int fd = open("/proc/self/maps", O_RDONLY);
271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (fd < 0) return;
272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  while (true) {
273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    char addr_buffer[11];
274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    addr_buffer[0] = '0';
275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    addr_buffer[1] = 'x';
276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    addr_buffer[10] = 0;
277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int result = read(fd, addr_buffer + 2, 8);
278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (result < 8) break;
279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    unsigned start = StringToLong(addr_buffer);
280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    result = read(fd, addr_buffer + 2, 1);
281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (result < 1) break;
282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (addr_buffer[2] != '-') break;
283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    result = read(fd, addr_buffer + 2, 8);
284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (result < 8) break;
285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    unsigned end = StringToLong(addr_buffer);
286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    char buffer[MAP_LENGTH];
287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int bytes_read = -1;
288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    do {
289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      bytes_read++;
290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (bytes_read >= MAP_LENGTH - 1)
291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        break;
292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      result = read(fd, buffer + bytes_read, 1);
293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (result < 1) break;
294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } while (buffer[bytes_read] != '\n');
295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    buffer[bytes_read] = 0;
296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Ignore mappings that are not executable.
297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (buffer[3] != 'x') continue;
298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    char* start_of_path = index(buffer, '/');
299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // There may be no filename in this line.  Skip to next.
300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (start_of_path == NULL) continue;
301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    buffer[bytes_read] = 0;
30244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    LOG(i::Isolate::Current(), SharedLibraryEvent(start_of_path, start, end));
303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  close(fd);
305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
308f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochvoid OS::SignalCodeMovingGC() {
309f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch}
310f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
311f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockint OS::StackWalk(Vector<OS::StackFrame> frames) {
313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int frames_size = frames.length();
31425f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen  ScopedVector<void*> addresses(frames_size);
315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
31625f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen  int frames_count = backtrace(addresses.start(), frames_size);
317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
318f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke  char** symbols = backtrace_symbols(addresses.start(), frames_count);
319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (symbols == NULL) {
320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return kStackWalkError;
321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < frames_count; i++) {
324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frames[i].address = addresses[i];
325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Format a text representation of the frame based on the information
326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // available.
327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    SNPrintF(MutableCStrVector(frames[i].text, kStackWalkMaxTextLen),
328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block             "%s",
329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block             symbols[i]);
330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Make sure line termination is in place.
331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frames[i].text[kStackWalkMaxTextLen - 1] = '\0';
332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  free(symbols);
335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return frames_count;
337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Constants used for mmap.
341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic const int kMmapFd = -1;
342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic const int kMmapFdOffset = 0;
343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3443ef787dbeca8a5fb1086949cda830dccee07bfbdBen MurdochVirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
346a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockVirtualMemory::VirtualMemory(size_t size) {
3473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  address_ = ReserveRegion(size);
348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  size_ = size;
349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3523ef787dbeca8a5fb1086949cda830dccee07bfbdBen MurdochVirtualMemory::VirtualMemory(size_t size, size_t alignment)
3533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    : address_(NULL), size_(0) {
3543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
3553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  size_t request_size = RoundUp(size + alignment,
3563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                static_cast<intptr_t>(OS::AllocateAlignment()));
3573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  void* reservation = mmap(OS::GetRandomMmapAddr(),
3583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           request_size,
3593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           PROT_NONE,
3603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
3613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           kMmapFd,
3623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           kMmapFdOffset);
3633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (reservation == MAP_FAILED) return;
3643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Address base = static_cast<Address>(reservation);
3663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Address aligned_base = RoundUp(base, alignment);
3673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT_LE(base, aligned_base);
3683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Unmap extra memory reserved before and after the desired block.
3703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (aligned_base != base) {
3713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    size_t prefix_size = static_cast<size_t>(aligned_base - base);
3723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    OS::Free(base, prefix_size);
3733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    request_size -= prefix_size;
3743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
3753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  size_t aligned_size = RoundUp(size, OS::AllocateAlignment());
3773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT_LE(aligned_size, request_size);
3783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (aligned_size != request_size) {
3803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    size_t suffix_size = request_size - aligned_size;
3813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    OS::Free(aligned_base + aligned_size, suffix_size);
3823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    request_size -= suffix_size;
3833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
3843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT(aligned_size == request_size);
3863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  address_ = static_cast<void*>(aligned_base);
3883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  size_ = aligned_size;
3893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
3903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockVirtualMemory::~VirtualMemory() {
393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (IsReserved()) {
3943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    bool result = ReleaseRegion(address(), size());
3953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ASSERT(result);
3963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    USE(result);
397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool VirtualMemory::IsReserved() {
4023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return address_ != NULL;
403592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch}
404592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
405592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
4063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid VirtualMemory::Reset() {
4073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  address_ = NULL;
4083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  size_ = 0;
4093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
4103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
4133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return CommitRegion(address, size, is_executable);
4143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
4153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool VirtualMemory::Uncommit(void* address, size_t size) {
4183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return UncommitRegion(address, size);
4193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
4203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool VirtualMemory::Guard(void* address) {
4233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  OS::Guard(address, OS::CommitPageSize());
4243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return true;
4253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
4263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid* VirtualMemory::ReserveRegion(size_t size) {
4293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  void* result = mmap(OS::GetRandomMmapAddr(),
4303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      size,
4313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      PROT_NONE,
4323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
4333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      kMmapFd,
4343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      kMmapFdOffset);
4353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (result == MAP_FAILED) return NULL;
4373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return result;
4393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
4403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
4433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
4443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (MAP_FAILED == mmap(base,
4453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                         size,
4463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                         prot,
447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                         MAP_PRIVATE | MAP_ANON | MAP_FIXED,
4483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                         kMmapFd,
4493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                         kMmapFdOffset)) {
450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return false;
451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  UpdateAllocatedSpaceLimits(base, size);
454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return true;
455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool VirtualMemory::UncommitRegion(void* base, size_t size) {
4593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return mmap(base,
4603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch              size,
4613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch              PROT_NONE,
462a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block              MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | MAP_FIXED,
4633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch              kMmapFd,
4643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch              kMmapFdOffset) != MAP_FAILED;
4653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
4663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool VirtualMemory::ReleaseRegion(void* base, size_t size) {
4693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return munmap(base, size) == 0;
470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4738b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdochclass Thread::PlatformData : public Malloced {
474a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_t thread_;  // Thread handle for pthread.
476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
478a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4793fb3ca8c7ca439d408449a395897395c0faae8d1Ben MurdochThread::Thread(const Options& options)
4808b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    : data_(new PlatformData),
4813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      stack_size_(options.stack_size()) {
4823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  set_name(options.name());
483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockThread::~Thread() {
4878b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  delete data_;
488a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
489a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
490a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void* ThreadEntry(void* arg) {
492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Thread* thread = reinterpret_cast<Thread*>(arg);
493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // This is also initialized by the first argument to pthread_create() but we
494a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // don't know which thread will run first (the original thread or the new
495a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // one) so we initialize it here too.
496257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  thread->data()->thread_ = pthread_self();
497257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(thread->data()->thread_ != kNoThread);
498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  thread->Run();
499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return NULL;
500a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
501a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5039fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid Thread::set_name(const char* name) {
5049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  strncpy(name_, name, sizeof(name_));
5059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  name_[sizeof(name_) - 1] = '\0';
5069fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block}
5079fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
5089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
509a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Thread::Start() {
51044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  pthread_attr_t* attr_ptr = NULL;
51144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  pthread_attr_t attr;
51244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (stack_size_ > 0) {
51344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    pthread_attr_init(&attr);
51444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
51544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    attr_ptr = &attr;
51644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
517257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  pthread_create(&data_->thread_, attr_ptr, ThreadEntry, this);
518257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(data_->thread_ != kNoThread);
519a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Thread::Join() {
523257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  pthread_join(data_->thread_, NULL);
524a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
525a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
526a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
527a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockThread::LocalStorageKey Thread::CreateThreadLocalKey() {
528a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_key_t key;
529a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int result = pthread_key_create(&key, NULL);
530a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  USE(result);
531a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(result == 0);
532a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return static_cast<LocalStorageKey>(key);
533a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
534a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
535a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
536a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Thread::DeleteThreadLocalKey(LocalStorageKey key) {
537a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
538a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int result = pthread_key_delete(pthread_key);
539a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  USE(result);
540a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(result == 0);
541a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
542a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
543a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
544a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid* Thread::GetThreadLocal(LocalStorageKey key) {
545a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
546a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return pthread_getspecific(pthread_key);
547a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
548a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
549a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
550a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Thread::SetThreadLocal(LocalStorageKey key, void* value) {
551a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
552a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_setspecific(pthread_key, value);
553a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
554a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
555a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
556a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Thread::YieldCPU() {
557a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  sched_yield();
558a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
559a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
560a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass FreeBSDMutex : public Mutex {
562a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
563a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  FreeBSDMutex() {
564a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    pthread_mutexattr_t attrs;
565a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int result = pthread_mutexattr_init(&attrs);
566a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(result == 0);
567a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
568a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(result == 0);
569a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    result = pthread_mutex_init(&mutex_, &attrs);
570a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(result == 0);
571a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
572a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
573a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual ~FreeBSDMutex() { pthread_mutex_destroy(&mutex_); }
574a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
575a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual int Lock() {
576a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int result = pthread_mutex_lock(&mutex_);
577a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return result;
578a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
579a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
580a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual int Unlock() {
581a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int result = pthread_mutex_unlock(&mutex_);
582a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return result;
583a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
584a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
58544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  virtual bool TryLock() {
58644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    int result = pthread_mutex_trylock(&mutex_);
58744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Return false if the lock is busy and locking failed.
58844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (result == EBUSY) {
58944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      return false;
59044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    }
59144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    ASSERT(result == 0);  // Verify no other errors.
59244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    return true;
59344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
59444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
595a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
596a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_mutex_t mutex_;   // Pthread mutex for POSIX platforms.
597a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
598a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
599a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
600a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockMutex* OS::CreateMutex() {
601a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return new FreeBSDMutex();
602a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
603a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
604a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
605a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass FreeBSDSemaphore : public Semaphore {
606a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
607a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  explicit FreeBSDSemaphore(int count) {  sem_init(&sem_, 0, count); }
608a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual ~FreeBSDSemaphore() { sem_destroy(&sem_); }
609a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
610a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual void Wait();
611a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual bool Wait(int timeout);
612a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual void Signal() { sem_post(&sem_); }
613a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
614a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  sem_t sem_;
615a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
616a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
617a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
618a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid FreeBSDSemaphore::Wait() {
619a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  while (true) {
620a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int result = sem_wait(&sem_);
621a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (result == 0) return;  // Successfully got semaphore.
622a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
623a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
624a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
625a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
626a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
627a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool FreeBSDSemaphore::Wait(int timeout) {
628a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const long kOneSecondMicros = 1000000;  // NOLINT
629a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
630a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Split timeout into second and nanosecond parts.
631a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  struct timeval delta;
632a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  delta.tv_usec = timeout % kOneSecondMicros;
633a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  delta.tv_sec = timeout / kOneSecondMicros;
634a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
635a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  struct timeval current_time;
636a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the current time.
637a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (gettimeofday(&current_time, NULL) == -1) {
638a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return false;
639a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
640a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
641a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Calculate time for end of timeout.
642a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  struct timeval end_time;
643a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  timeradd(&current_time, &delta, &end_time);
644a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
645a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  struct timespec ts;
646a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  TIMEVAL_TO_TIMESPEC(&end_time, &ts);
647a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  while (true) {
648a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int result = sem_timedwait(&sem_, &ts);
649a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (result == 0) return true;  // Successfully got semaphore.
650a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (result == -1 && errno == ETIMEDOUT) return false;  // Timeout.
651a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
652a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
653a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
654a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
655a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
656a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockSemaphore* OS::CreateSemaphore(int count) {
657a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return new FreeBSDSemaphore(count);
658a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
659a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
660a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
66144f0eee88ff00398ff7f715fab053374d808c90dSteve Blockstatic pthread_t GetThreadID() {
66244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  pthread_t thread_id = pthread_self();
66344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  return thread_id;
66444f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
66544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
66644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
66744f0eee88ff00398ff7f715fab053374d808c90dSteve Blockclass Sampler::PlatformData : public Malloced {
66844f0eee88ff00398ff7f715fab053374d808c90dSteve Block public:
66944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  PlatformData() : vm_tid_(GetThreadID()) {}
67044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
67144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  pthread_t vm_tid() const { return vm_tid_; }
67244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
67344f0eee88ff00398ff7f715fab053374d808c90dSteve Block private:
67444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  pthread_t vm_tid_;
67544f0eee88ff00398ff7f715fab053374d808c90dSteve Block};
67644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
677a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
678a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
679a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  USE(info);
680a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (signal != SIGPROF) return;
68144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Isolate* isolate = Isolate::UncheckedCurrent();
68244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
68344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // We require a fully initialized and entered isolate.
68444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    return;
68544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
6868b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  if (v8::Locker::IsActive() &&
6878b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      !isolate->thread_manager()->IsLockedByCurrentThread()) {
6888b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    return;
6898b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  }
6908b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch
69144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Sampler* sampler = isolate->logger()->sampler();
69244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (sampler == NULL || !sampler->IsActive()) return;
693a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
69444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  TickSample sample_obj;
69544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  TickSample* sample = CpuProfiler::TickSampleEvent(isolate);
69644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (sample == NULL) sample = &sample_obj;
6976ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
69844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Extracting the sample from the context is extremely machine dependent.
69944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
70044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  mcontext_t& mcontext = ucontext->uc_mcontext;
70144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->state = isolate->current_vm_state();
702a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#if V8_HOST_ARCH_IA32
70344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->pc = reinterpret_cast<Address>(mcontext.mc_eip);
70444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->sp = reinterpret_cast<Address>(mcontext.mc_esp);
70544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->fp = reinterpret_cast<Address>(mcontext.mc_ebp);
706a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#elif V8_HOST_ARCH_X64
70744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->pc = reinterpret_cast<Address>(mcontext.mc_rip);
70844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->sp = reinterpret_cast<Address>(mcontext.mc_rsp);
70944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->fp = reinterpret_cast<Address>(mcontext.mc_rbp);
710a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#elif V8_HOST_ARCH_ARM
71144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->pc = reinterpret_cast<Address>(mcontext.mc_r15);
71244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->sp = reinterpret_cast<Address>(mcontext.mc_r13);
71344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->fp = reinterpret_cast<Address>(mcontext.mc_r11);
714a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
71544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sampler->SampleStack(sample);
71644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sampler->Tick(sample);
717a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
718a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
719a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
72044f0eee88ff00398ff7f715fab053374d808c90dSteve Blockclass SignalSender : public Thread {
721a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
72244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  enum SleepInterval {
72344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    HALF_INTERVAL,
72444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    FULL_INTERVAL
72544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  };
72644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
7273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  static const int kSignalSenderStackSize = 64 * KB;
7283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
72944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  explicit SignalSender(int interval)
7303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      : Thread(Thread::Options("SignalSender", kSignalSenderStackSize)),
73144f0eee88ff00398ff7f715fab053374d808c90dSteve Block        interval_(interval) {}
73244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
73344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static void AddActiveSampler(Sampler* sampler) {
7343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ScopedLock lock(mutex_.Pointer());
73544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    SamplerRegistry::AddActiveSampler(sampler);
73644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (instance_ == NULL) {
73744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      // Install a signal handler.
73844f0eee88ff00398ff7f715fab053374d808c90dSteve Block      struct sigaction sa;
73944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      sa.sa_sigaction = ProfilerSignalHandler;
74044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      sigemptyset(&sa.sa_mask);
74144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      sa.sa_flags = SA_RESTART | SA_SIGINFO;
74244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      signal_handler_installed_ =
74344f0eee88ff00398ff7f715fab053374d808c90dSteve Block          (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
74444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
74544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      // Start a thread that sends SIGPROF signal to VM threads.
74644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      instance_ = new SignalSender(sampler->interval());
74744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      instance_->Start();
74844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    } else {
74944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ASSERT(instance_->interval_ == sampler->interval());
75044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    }
751a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
752a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
75344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static void RemoveActiveSampler(Sampler* sampler) {
7543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ScopedLock lock(mutex_.Pointer());
75544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    SamplerRegistry::RemoveActiveSampler(sampler);
75644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
7573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
75844f0eee88ff00398ff7f715fab053374d808c90dSteve Block      delete instance_;
75944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      instance_ = NULL;
76044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
76144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      // Restore the old signal handler.
76244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      if (signal_handler_installed_) {
76344f0eee88ff00398ff7f715fab053374d808c90dSteve Block        sigaction(SIGPROF, &old_signal_handler_, 0);
76444f0eee88ff00398ff7f715fab053374d808c90dSteve Block        signal_handler_installed_ = false;
76544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      }
76644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    }
76744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
76844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
76944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Implement Thread::Run().
77044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  virtual void Run() {
77144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    SamplerRegistry::State state;
77244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    while ((state = SamplerRegistry::GetState()) !=
77344f0eee88ff00398ff7f715fab053374d808c90dSteve Block           SamplerRegistry::HAS_NO_SAMPLERS) {
77444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      bool cpu_profiling_enabled =
77544f0eee88ff00398ff7f715fab053374d808c90dSteve Block          (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS);
77644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled();
77744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      // When CPU profiling is enabled both JavaScript and C++ code is
77844f0eee88ff00398ff7f715fab053374d808c90dSteve Block      // profiled. We must not suspend.
77944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      if (!cpu_profiling_enabled) {
78044f0eee88ff00398ff7f715fab053374d808c90dSteve Block        if (rate_limiter_.SuspendIfNecessary()) continue;
78144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      }
78244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      if (cpu_profiling_enabled && runtime_profiler_enabled) {
78344f0eee88ff00398ff7f715fab053374d808c90dSteve Block        if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) {
78444f0eee88ff00398ff7f715fab053374d808c90dSteve Block          return;
78544f0eee88ff00398ff7f715fab053374d808c90dSteve Block        }
78644f0eee88ff00398ff7f715fab053374d808c90dSteve Block        Sleep(HALF_INTERVAL);
78744f0eee88ff00398ff7f715fab053374d808c90dSteve Block        if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) {
78844f0eee88ff00398ff7f715fab053374d808c90dSteve Block          return;
78944f0eee88ff00398ff7f715fab053374d808c90dSteve Block        }
79044f0eee88ff00398ff7f715fab053374d808c90dSteve Block        Sleep(HALF_INTERVAL);
79144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      } else {
79244f0eee88ff00398ff7f715fab053374d808c90dSteve Block        if (cpu_profiling_enabled) {
79344f0eee88ff00398ff7f715fab053374d808c90dSteve Block          if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile,
79444f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                                      this)) {
79544f0eee88ff00398ff7f715fab053374d808c90dSteve Block            return;
79644f0eee88ff00398ff7f715fab053374d808c90dSteve Block          }
79744f0eee88ff00398ff7f715fab053374d808c90dSteve Block        }
79844f0eee88ff00398ff7f715fab053374d808c90dSteve Block        if (runtime_profiler_enabled) {
79944f0eee88ff00398ff7f715fab053374d808c90dSteve Block          if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile,
80044f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                                      NULL)) {
80144f0eee88ff00398ff7f715fab053374d808c90dSteve Block            return;
80244f0eee88ff00398ff7f715fab053374d808c90dSteve Block          }
80344f0eee88ff00398ff7f715fab053374d808c90dSteve Block        }
80444f0eee88ff00398ff7f715fab053374d808c90dSteve Block        Sleep(FULL_INTERVAL);
80544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      }
80644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    }
80744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
80844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
80944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static void DoCpuProfile(Sampler* sampler, void* raw_sender) {
81044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (!sampler->IsProfiling()) return;
81144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender);
81244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    sender->SendProfilingSignal(sampler->platform_data()->vm_tid());
81344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
81444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
81544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static void DoRuntimeProfile(Sampler* sampler, void* ignored) {
81644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (!sampler->isolate()->IsInitialized()) return;
81744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    sampler->isolate()->runtime_profiler()->NotifyTick();
81844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
81944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
82044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  void SendProfilingSignal(pthread_t tid) {
82144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (!signal_handler_installed_) return;
82244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    pthread_kill(tid, SIGPROF);
82344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
82444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
82544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  void Sleep(SleepInterval full_or_half) {
82644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Convert ms to us and subtract 100 us to compensate delays
82744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // occuring during signal delivery.
82844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    useconds_t interval = interval_ * 1000 - 100;
82944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (full_or_half == HALF_INTERVAL) interval /= 2;
83044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    int result = usleep(interval);
83144f0eee88ff00398ff7f715fab053374d808c90dSteve Block#ifdef DEBUG
83244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (result != 0 && errno != EINTR) {
83344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      fprintf(stderr,
83444f0eee88ff00398ff7f715fab053374d808c90dSteve Block              "SignalSender usleep error; interval = %u, errno = %d\n",
83544f0eee88ff00398ff7f715fab053374d808c90dSteve Block              interval,
83644f0eee88ff00398ff7f715fab053374d808c90dSteve Block              errno);
83744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ASSERT(result == 0 || errno == EINTR);
83844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    }
83944f0eee88ff00398ff7f715fab053374d808c90dSteve Block#endif
84044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    USE(result);
84144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
84244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
84344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const int interval_;
84444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  RuntimeProfilerRateLimiter rate_limiter_;
84544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
84644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Protects the process wide state below.
8473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  static LazyMutex mutex_;
84844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static SignalSender* instance_;
84944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static bool signal_handler_installed_;
85044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static struct sigaction old_signal_handler_;
85144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
8523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch private:
85344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  DISALLOW_COPY_AND_ASSIGN(SignalSender);
854a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
855a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8563ef787dbeca8a5fb1086949cda830dccee07bfbdBen MurdochLazyMutex SignalSender::mutex_ = LAZY_MUTEX_INITIALIZER;
85744f0eee88ff00398ff7f715fab053374d808c90dSteve BlockSignalSender* SignalSender::instance_ = NULL;
85844f0eee88ff00398ff7f715fab053374d808c90dSteve Blockstruct sigaction SignalSender::old_signal_handler_;
85944f0eee88ff00398ff7f715fab053374d808c90dSteve Blockbool SignalSender::signal_handler_installed_ = false;
860a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
86144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
86244f0eee88ff00398ff7f715fab053374d808c90dSteve BlockSampler::Sampler(Isolate* isolate, int interval)
86344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    : isolate_(isolate),
86444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      interval_(interval),
865b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      profiling_(false),
8668a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      active_(false),
8678a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      samples_taken_(0) {
86844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  data_ = new PlatformData;
869a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
870a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
871a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
872a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockSampler::~Sampler() {
87344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ASSERT(!IsActive());
874a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  delete data_;
875a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
876a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
877a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
878a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Sampler::Start() {
87944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ASSERT(!IsActive());
88044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  SetActive(true);
88144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  SignalSender::AddActiveSampler(this);
882a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
883a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
884a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
885a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Sampler::Stop() {
88644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ASSERT(IsActive());
88744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  SignalSender::RemoveActiveSampler(this);
88844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  SetActive(false);
889a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
890a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
891a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
892a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} }  // namespace v8::internal
893