platform-freebsd.cc revision 592a9fc1d8ea420377a2e7efd0600e20b058be2b
1a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Copyright 2006-2008 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
57a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "platform.h"
58b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch#include "vm-state-inl.h"
59a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
60a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace v8 {
62a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace internal {
63a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
64a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 0 is never a valid thread id on FreeBSD since tids and pids share a
65a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// name space and pid 0 is used to kill the group (see man 2 kill).
66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic const pthread_t kNoThread = (pthread_t) 0;
67a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
69a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdouble ceiling(double x) {
70a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Correct as on OS X
71a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (-1.0 < x && x < 0.0) {
72a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        return -0.0;
73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        return ceil(x);
75a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
76a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
77a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
78a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7944f0eee88ff00398ff7f715fab053374d808c90dSteve Blockstatic Mutex* limit_mutex = NULL;
8044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
8144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
82a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::Setup() {
83a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Seed the random number generator.
84a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Convert the current time to a 64-bit integer first, before converting it
85a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // to an unsigned. Going directly can cause an overflow and the seed to be
86a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // set to all ones. The seed will be identical for different instances that
87a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // call this setup code within the same millisecond.
88a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
89a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  srandom(static_cast<unsigned int>(seed));
9044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  limit_mutex = CreateMutex();
91a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
92a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
93a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
947f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochvoid OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) {
957f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __asm__ __volatile__("" : : : "memory");
967f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  *ptr = value;
977f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch}
987f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
997f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
100d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockuint64_t OS::CpuFeaturesImpliedByPlatform() {
101d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return 0;  // FreeBSD runs on anything.
102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockint OS::ActivationFrameAlignment() {
106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // 16 byte alignment on FreeBSD
107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return 16;
108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
111d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarkeconst char* OS::LocalTimezone(double time) {
112d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  if (isnan(time)) return "";
113d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  time_t tv = static_cast<time_t>(floor(time/msPerSecond));
114d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  struct tm* t = localtime(&tv);
115d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  if (NULL == t) return "";
116d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  return t->tm_zone;
117d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke}
118d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
119d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
120d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarkedouble OS::LocalTimeOffset() {
121d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  time_t tv = time(NULL);
122d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  struct tm* t = localtime(&tv);
123d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // tm_gmtoff includes any daylight savings offset, so subtract it.
124d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  return static_cast<double>(t->tm_gmtoff * msPerSecond -
125d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                             (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
126d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke}
127d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
128d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// We keep the lowest and highest addresses mapped as a quick way of
130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// determining that pointers are outside the heap (used mostly in assertions
131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// and verification).  The estimate is conservative, ie, not all addresses in
132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 'allocated' space are actually allocated to our heap.  The range is
133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// [lowest, highest), inclusive on the low and and exclusive on the high end.
134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void* highest_ever_allocated = reinterpret_cast<void*>(0);
136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void UpdateAllocatedSpaceLimits(void* address, int size) {
13944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ASSERT(limit_mutex != NULL);
14044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ScopedLock lock(limit_mutex);
14144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  lowest_ever_allocated = Min(lowest_ever_allocated, address);
143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  highest_ever_allocated =
144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Max(highest_ever_allocated,
145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool OS::IsOutsideAllocatedSpace(void* address) {
150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return address < lowest_ever_allocated || address >= highest_ever_allocated;
151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocksize_t OS::AllocateAlignment() {
155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return getpagesize();
156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid* OS::Allocate(const size_t requested,
160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                   size_t* allocated,
161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                   bool executable) {
162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const size_t msize = RoundUp(requested, getpagesize());
163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (mbase == MAP_FAILED) {
16744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    LOG(ISOLATE, StringEvent("OS::Allocate", "mmap failed"));
168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return NULL;
169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  *allocated = msize;
171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  UpdateAllocatedSpaceLimits(mbase, msize);
172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return mbase;
173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::Free(void* buf, const size_t length) {
177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // TODO(1240712): munmap has a return value which is ignored here.
178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int result = munmap(buf, length);
179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  USE(result);
180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(result == 0);
181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::Sleep(int milliseconds) {
185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  unsigned int ms = static_cast<unsigned int>(milliseconds);
186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  usleep(1000 * ms);
187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::Abort() {
191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Redirect to std abort to signal abnormal program termination.
192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  abort();
193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::DebugBreak() {
197756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick#if (defined(__arm__) || defined(__thumb__))
198756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick# if defined(CAN_USE_ARMV5_INSTRUCTIONS)
199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  asm("bkpt 0");
200756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick# endif
201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#else
202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  asm("int $3");
203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass PosixMemoryMappedFile : public OS::MemoryMappedFile {
208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  PosixMemoryMappedFile(FILE* file, void* memory, int size)
210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    : file_(file), memory_(memory), size_(size) { }
211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual ~PosixMemoryMappedFile();
212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual void* memory() { return memory_; }
2131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  virtual int size() { return size_; }
214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  FILE* file_;
216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void* memory_;
217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int size_;
218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2211e0659c275bb392c045087af4f6b0d7565cb3d77Steve BlockOS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
222e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  FILE* file = fopen(name, "r+");
2231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  if (file == NULL) return NULL;
2241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  fseek(file, 0, SEEK_END);
2261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  int size = ftell(file);
2271e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  void* memory =
2291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
2301e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  return new PosixMemoryMappedFile(file, memory, size);
2311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block}
2321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockOS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    void* initial) {
236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  FILE* file = fopen(name, "w+");
237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (file == NULL) return NULL;
238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int result = fwrite(initial, size, 1, file);
239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (result < 1) {
240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    fclose(file);
241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return NULL;
242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void* memory =
244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return new PosixMemoryMappedFile(file, memory, size);
246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockPosixMemoryMappedFile::~PosixMemoryMappedFile() {
250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (memory_) munmap(memory_, size_);
251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  fclose(file_);
252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic unsigned StringToLong(char* buffer) {
256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return static_cast<unsigned>(strtol(buffer, NULL, 16));  // NOLINT
257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::LogSharedLibraryAddresses() {
261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static const int MAP_LENGTH = 1024;
262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int fd = open("/proc/self/maps", O_RDONLY);
263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (fd < 0) return;
264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  while (true) {
265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    char addr_buffer[11];
266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    addr_buffer[0] = '0';
267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    addr_buffer[1] = 'x';
268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    addr_buffer[10] = 0;
269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int result = read(fd, addr_buffer + 2, 8);
270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (result < 8) break;
271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    unsigned start = StringToLong(addr_buffer);
272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    result = read(fd, addr_buffer + 2, 1);
273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (result < 1) break;
274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (addr_buffer[2] != '-') break;
275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    result = read(fd, addr_buffer + 2, 8);
276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (result < 8) break;
277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    unsigned end = StringToLong(addr_buffer);
278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    char buffer[MAP_LENGTH];
279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int bytes_read = -1;
280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    do {
281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      bytes_read++;
282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (bytes_read >= MAP_LENGTH - 1)
283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        break;
284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      result = read(fd, buffer + bytes_read, 1);
285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (result < 1) break;
286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } while (buffer[bytes_read] != '\n');
287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    buffer[bytes_read] = 0;
288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Ignore mappings that are not executable.
289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (buffer[3] != 'x') continue;
290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    char* start_of_path = index(buffer, '/');
291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // There may be no filename in this line.  Skip to next.
292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (start_of_path == NULL) continue;
293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    buffer[bytes_read] = 0;
29444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    LOG(i::Isolate::Current(), SharedLibraryEvent(start_of_path, start, end));
295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  close(fd);
297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
300f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochvoid OS::SignalCodeMovingGC() {
301f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch}
302f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
303f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockint OS::StackWalk(Vector<OS::StackFrame> frames) {
305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int frames_size = frames.length();
30625f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen  ScopedVector<void*> addresses(frames_size);
307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
30825f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen  int frames_count = backtrace(addresses.start(), frames_size);
309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
310f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke  char** symbols = backtrace_symbols(addresses.start(), frames_count);
311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (symbols == NULL) {
312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return kStackWalkError;
313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < frames_count; i++) {
316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frames[i].address = addresses[i];
317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Format a text representation of the frame based on the information
318a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // available.
319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    SNPrintF(MutableCStrVector(frames[i].text, kStackWalkMaxTextLen),
320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block             "%s",
321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block             symbols[i]);
322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Make sure line termination is in place.
323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frames[i].text[kStackWalkMaxTextLen - 1] = '\0';
324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  free(symbols);
327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return frames_count;
329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Constants used for mmap.
333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic const int kMmapFd = -1;
334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic const int kMmapFdOffset = 0;
335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
336592a9fc1d8ea420377a2e7efd0600e20b058be2bBen MurdochVirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockVirtualMemory::VirtualMemory(size_t size) {
339592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  address_ = ReserveRegion(size);
340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  size_ = size;
341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
344592a9fc1d8ea420377a2e7efd0600e20b058be2bBen MurdochVirtualMemory::VirtualMemory(size_t size, size_t alignment)
345592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch    : address_(NULL), size_(0) {
346592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
347592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  size_t request_size = RoundUp(size + alignment,
348592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch                                static_cast<intptr_t>(OS::AllocateAlignment()));
349592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  void* reservation = mmap(OS::GetRandomMmapAddr(),
350592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch                           request_size,
351592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch                           PROT_NONE,
352592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch                           MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
353592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch                           kMmapFd,
354592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch                           kMmapFdOffset);
355592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  if (reservation == MAP_FAILED) return;
356592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
357592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  Address base = static_cast<Address>(reservation);
358592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  Address aligned_base = RoundUp(base, alignment);
359592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  ASSERT_LE(base, aligned_base);
360592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
361592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  // Unmap extra memory reserved before and after the desired block.
362592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  if (aligned_base != base) {
363592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch    size_t prefix_size = static_cast<size_t>(aligned_base - base);
364592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch    OS::Free(base, prefix_size);
365592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch    request_size -= prefix_size;
366592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  }
367592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
368592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  size_t aligned_size = RoundUp(size, OS::AllocateAlignment());
369592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  ASSERT_LE(aligned_size, request_size);
370592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
371592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  if (aligned_size != request_size) {
372592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch    size_t suffix_size = request_size - aligned_size;
373592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch    OS::Free(aligned_base + aligned_size, suffix_size);
374592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch    request_size -= suffix_size;
375592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  }
376592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
377592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  ASSERT(aligned_size == request_size);
378592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
379592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  address_ = static_cast<void*>(aligned_base);
380592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  size_ = aligned_size;
381592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch}
382592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
383592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockVirtualMemory::~VirtualMemory() {
385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (IsReserved()) {
386592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch    bool result = ReleaseRegion(address(), size());
387592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch    ASSERT(result);
388592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch    USE(result);
389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool VirtualMemory::IsReserved() {
394592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  return address_ != NULL;
395a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
398592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdochvoid VirtualMemory::Reset() {
399592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  address_ = NULL;
400592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  size_ = 0;
401592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch}
402592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
403592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
404592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdochbool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
405592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  return CommitRegion(address, size, is_executable);
406592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch}
407592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
408592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
409592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdochbool VirtualMemory::Uncommit(void* address, size_t size) {
410592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  return UncommitRegion(address, size);
411592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch}
412592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
413592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
414592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdochbool VirtualMemory::Guard(void* address) {
415592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  OS::Guard(address, OS::CommitPageSize());
416592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  return true;
417592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch}
418592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
419592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
420592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdochvoid* VirtualMemory::ReserveRegion(size_t size) {
421592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  void* result = mmap(OS::GetRandomMmapAddr(),
422592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch                      size,
423592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch                      PROT_NONE,
424592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch                      MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
425592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch                      kMmapFd,
426592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch                      kMmapFdOffset);
427592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
428592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  if (result == MAP_FAILED) return NULL;
429592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
430592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  return result;
431592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch}
432592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
433592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
434592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdochbool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
435592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
436592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  if (MAP_FAILED == mmap(base,
437592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch                         size,
438592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch                         prot,
439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                         MAP_PRIVATE | MAP_ANON | MAP_FIXED,
440592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch                         kMmapFd,
441592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch                         kMmapFdOffset)) {
442a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return false;
443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
444a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
445592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  UpdateAllocatedSpaceLimits(base, size);
446a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return true;
447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
450592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdochbool VirtualMemory::UncommitRegion(void* base, size_t size) {
451592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  return mmap(base,
452592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch              size,
453592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch              PROT_NONE,
454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block              MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | MAP_FIXED,
455592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch              kMmapFd,
456592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch              kMmapFdOffset) != MAP_FAILED;
457592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch}
458592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
459592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
460592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdochbool VirtualMemory::ReleaseRegion(void* base, size_t size) {
461592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch  return munmap(base, size) == 0;
462a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
463a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
464a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4658b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdochclass Thread::PlatformData : public Malloced {
466a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
467a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_t thread_;  // Thread handle for pthread.
468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4713fb3ca8c7ca439d408449a395897395c0faae8d1Ben MurdochThread::Thread(const Options& options)
4728b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    : data_(new PlatformData),
47344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      stack_size_(options.stack_size) {
47444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  set_name(options.name);
4759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block}
4769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
4779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
4783fb3ca8c7ca439d408449a395897395c0faae8d1Ben MurdochThread::Thread(const char* name)
4798b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    : data_(new PlatformData),
48044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      stack_size_(0) {
4811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  set_name(name);
482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockThread::~Thread() {
4868b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  delete data_;
487a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
488a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
489a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
490a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void* ThreadEntry(void* arg) {
491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Thread* thread = reinterpret_cast<Thread*>(arg);
492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // This is also initialized by the first argument to pthread_create() but we
493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // don't know which thread will run first (the original thread or the new
494a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // one) so we initialize it here too.
495257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  thread->data()->thread_ = pthread_self();
496257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(thread->data()->thread_ != kNoThread);
497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  thread->Run();
498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return NULL;
499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
500a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
501a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5029fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid Thread::set_name(const char* name) {
5039fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  strncpy(name_, name, sizeof(name_));
5049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  name_[sizeof(name_) - 1] = '\0';
5059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block}
5069fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
5079fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
508a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Thread::Start() {
50944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  pthread_attr_t* attr_ptr = NULL;
51044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  pthread_attr_t attr;
51144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (stack_size_ > 0) {
51244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    pthread_attr_init(&attr);
51344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
51444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    attr_ptr = &attr;
51544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
516257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  pthread_create(&data_->thread_, attr_ptr, ThreadEntry, this);
517257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  ASSERT(data_->thread_ != kNoThread);
518a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
519a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Thread::Join() {
522257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  pthread_join(data_->thread_, NULL);
523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
524a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
525a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
526a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockThread::LocalStorageKey Thread::CreateThreadLocalKey() {
527a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_key_t key;
528a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int result = pthread_key_create(&key, NULL);
529a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  USE(result);
530a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(result == 0);
531a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return static_cast<LocalStorageKey>(key);
532a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
533a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
534a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
535a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Thread::DeleteThreadLocalKey(LocalStorageKey key) {
536a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
537a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int result = pthread_key_delete(pthread_key);
538a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  USE(result);
539a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(result == 0);
540a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
541a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
542a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
543a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid* Thread::GetThreadLocal(LocalStorageKey key) {
544a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
545a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return pthread_getspecific(pthread_key);
546a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
547a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
548a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
549a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Thread::SetThreadLocal(LocalStorageKey key, void* value) {
550a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
551a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_setspecific(pthread_key, value);
552a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
553a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
554a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
555a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Thread::YieldCPU() {
556a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  sched_yield();
557a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
558a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
559a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
560a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass FreeBSDMutex : public Mutex {
561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
562a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  FreeBSDMutex() {
563a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    pthread_mutexattr_t attrs;
564a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int result = pthread_mutexattr_init(&attrs);
565a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(result == 0);
566a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
567a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(result == 0);
568a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    result = pthread_mutex_init(&mutex_, &attrs);
569a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(result == 0);
570a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
571a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
572a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual ~FreeBSDMutex() { pthread_mutex_destroy(&mutex_); }
573a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
574a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual int Lock() {
575a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int result = pthread_mutex_lock(&mutex_);
576a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return result;
577a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
578a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
579a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual int Unlock() {
580a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int result = pthread_mutex_unlock(&mutex_);
581a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return result;
582a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
583a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
58444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  virtual bool TryLock() {
58544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    int result = pthread_mutex_trylock(&mutex_);
58644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Return false if the lock is busy and locking failed.
58744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (result == EBUSY) {
58844f0eee88ff00398ff7f715fab053374d808c90dSteve Block      return false;
58944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    }
59044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    ASSERT(result == 0);  // Verify no other errors.
59144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    return true;
59244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
59344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
594a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
595a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_mutex_t mutex_;   // Pthread mutex for POSIX platforms.
596a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
597a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
598a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
599a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockMutex* OS::CreateMutex() {
600a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return new FreeBSDMutex();
601a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
602a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
603a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
604a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass FreeBSDSemaphore : public Semaphore {
605a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
606a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  explicit FreeBSDSemaphore(int count) {  sem_init(&sem_, 0, count); }
607a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual ~FreeBSDSemaphore() { sem_destroy(&sem_); }
608a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
609a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual void Wait();
610a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual bool Wait(int timeout);
611a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual void Signal() { sem_post(&sem_); }
612a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
613a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  sem_t sem_;
614a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
615a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
616a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
617a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid FreeBSDSemaphore::Wait() {
618a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  while (true) {
619a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int result = sem_wait(&sem_);
620a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (result == 0) return;  // Successfully got semaphore.
621a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
622a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
623a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
624a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
625a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
626a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool FreeBSDSemaphore::Wait(int timeout) {
627a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const long kOneSecondMicros = 1000000;  // NOLINT
628a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
629a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Split timeout into second and nanosecond parts.
630a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  struct timeval delta;
631a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  delta.tv_usec = timeout % kOneSecondMicros;
632a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  delta.tv_sec = timeout / kOneSecondMicros;
633a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
634a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  struct timeval current_time;
635a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the current time.
636a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (gettimeofday(&current_time, NULL) == -1) {
637a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return false;
638a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
639a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
640a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Calculate time for end of timeout.
641a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  struct timeval end_time;
642a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  timeradd(&current_time, &delta, &end_time);
643a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
644a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  struct timespec ts;
645a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  TIMEVAL_TO_TIMESPEC(&end_time, &ts);
646a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  while (true) {
647a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int result = sem_timedwait(&sem_, &ts);
648a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (result == 0) return true;  // Successfully got semaphore.
649a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (result == -1 && errno == ETIMEDOUT) return false;  // Timeout.
650a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
651a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
652a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
653a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
654a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
655a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockSemaphore* OS::CreateSemaphore(int count) {
656a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return new FreeBSDSemaphore(count);
657a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
658a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
659a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
66044f0eee88ff00398ff7f715fab053374d808c90dSteve Blockstatic pthread_t GetThreadID() {
66144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  pthread_t thread_id = pthread_self();
66244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  return thread_id;
66344f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
66444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
66544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
66644f0eee88ff00398ff7f715fab053374d808c90dSteve Blockclass Sampler::PlatformData : public Malloced {
66744f0eee88ff00398ff7f715fab053374d808c90dSteve Block public:
66844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  PlatformData() : vm_tid_(GetThreadID()) {}
66944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
67044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  pthread_t vm_tid() const { return vm_tid_; }
67144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
67244f0eee88ff00398ff7f715fab053374d808c90dSteve Block private:
67344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  pthread_t vm_tid_;
67444f0eee88ff00398ff7f715fab053374d808c90dSteve Block};
67544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
676a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
677a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
678a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  USE(info);
679a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (signal != SIGPROF) return;
68044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Isolate* isolate = Isolate::UncheckedCurrent();
68144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
68244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // We require a fully initialized and entered isolate.
68344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    return;
68444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
6858b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  if (v8::Locker::IsActive() &&
6868b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      !isolate->thread_manager()->IsLockedByCurrentThread()) {
6878b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    return;
6888b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  }
6898b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch
69044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Sampler* sampler = isolate->logger()->sampler();
69144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (sampler == NULL || !sampler->IsActive()) return;
692a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
69344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  TickSample sample_obj;
69444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  TickSample* sample = CpuProfiler::TickSampleEvent(isolate);
69544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (sample == NULL) sample = &sample_obj;
6966ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
69744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Extracting the sample from the context is extremely machine dependent.
69844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
69944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  mcontext_t& mcontext = ucontext->uc_mcontext;
70044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->state = isolate->current_vm_state();
701a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#if V8_HOST_ARCH_IA32
70244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->pc = reinterpret_cast<Address>(mcontext.mc_eip);
70344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->sp = reinterpret_cast<Address>(mcontext.mc_esp);
70444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->fp = reinterpret_cast<Address>(mcontext.mc_ebp);
705a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#elif V8_HOST_ARCH_X64
70644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->pc = reinterpret_cast<Address>(mcontext.mc_rip);
70744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->sp = reinterpret_cast<Address>(mcontext.mc_rsp);
70844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->fp = reinterpret_cast<Address>(mcontext.mc_rbp);
709a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#elif V8_HOST_ARCH_ARM
71044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->pc = reinterpret_cast<Address>(mcontext.mc_r15);
71144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->sp = reinterpret_cast<Address>(mcontext.mc_r13);
71244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->fp = reinterpret_cast<Address>(mcontext.mc_r11);
713a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
71444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sampler->SampleStack(sample);
71544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sampler->Tick(sample);
716a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
717a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
718a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
71944f0eee88ff00398ff7f715fab053374d808c90dSteve Blockclass SignalSender : public Thread {
720a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
72144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  enum SleepInterval {
72244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    HALF_INTERVAL,
72344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    FULL_INTERVAL
72444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  };
72544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
72644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  explicit SignalSender(int interval)
7273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      : Thread("SignalSender"),
72844f0eee88ff00398ff7f715fab053374d808c90dSteve Block        interval_(interval) {}
72944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
73044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static void AddActiveSampler(Sampler* sampler) {
73144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    ScopedLock lock(mutex_);
73244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    SamplerRegistry::AddActiveSampler(sampler);
73344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (instance_ == NULL) {
73444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      // Install a signal handler.
73544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      struct sigaction sa;
73644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      sa.sa_sigaction = ProfilerSignalHandler;
73744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      sigemptyset(&sa.sa_mask);
73844f0eee88ff00398ff7f715fab053374d808c90dSteve Block      sa.sa_flags = SA_RESTART | SA_SIGINFO;
73944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      signal_handler_installed_ =
74044f0eee88ff00398ff7f715fab053374d808c90dSteve Block          (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
74144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
74244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      // Start a thread that sends SIGPROF signal to VM threads.
74344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      instance_ = new SignalSender(sampler->interval());
74444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      instance_->Start();
74544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    } else {
74644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ASSERT(instance_->interval_ == sampler->interval());
74744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    }
748a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
749a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
75044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static void RemoveActiveSampler(Sampler* sampler) {
75144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    ScopedLock lock(mutex_);
75244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    SamplerRegistry::RemoveActiveSampler(sampler);
75344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
7543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
75544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      delete instance_;
75644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      instance_ = NULL;
75744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
75844f0eee88ff00398ff7f715fab053374d808c90dSteve Block      // Restore the old signal handler.
75944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      if (signal_handler_installed_) {
76044f0eee88ff00398ff7f715fab053374d808c90dSteve Block        sigaction(SIGPROF, &old_signal_handler_, 0);
76144f0eee88ff00398ff7f715fab053374d808c90dSteve Block        signal_handler_installed_ = false;
76244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      }
76344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    }
76444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
76544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
76644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Implement Thread::Run().
76744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  virtual void Run() {
76844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    SamplerRegistry::State state;
76944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    while ((state = SamplerRegistry::GetState()) !=
77044f0eee88ff00398ff7f715fab053374d808c90dSteve Block           SamplerRegistry::HAS_NO_SAMPLERS) {
77144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      bool cpu_profiling_enabled =
77244f0eee88ff00398ff7f715fab053374d808c90dSteve Block          (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS);
77344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled();
77444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      // When CPU profiling is enabled both JavaScript and C++ code is
77544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      // profiled. We must not suspend.
77644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      if (!cpu_profiling_enabled) {
77744f0eee88ff00398ff7f715fab053374d808c90dSteve Block        if (rate_limiter_.SuspendIfNecessary()) continue;
77844f0eee88ff00398ff7f715fab053374d808c90dSteve Block      }
77944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      if (cpu_profiling_enabled && runtime_profiler_enabled) {
78044f0eee88ff00398ff7f715fab053374d808c90dSteve Block        if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) {
78144f0eee88ff00398ff7f715fab053374d808c90dSteve Block          return;
78244f0eee88ff00398ff7f715fab053374d808c90dSteve Block        }
78344f0eee88ff00398ff7f715fab053374d808c90dSteve Block        Sleep(HALF_INTERVAL);
78444f0eee88ff00398ff7f715fab053374d808c90dSteve Block        if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) {
78544f0eee88ff00398ff7f715fab053374d808c90dSteve Block          return;
78644f0eee88ff00398ff7f715fab053374d808c90dSteve Block        }
78744f0eee88ff00398ff7f715fab053374d808c90dSteve Block        Sleep(HALF_INTERVAL);
78844f0eee88ff00398ff7f715fab053374d808c90dSteve Block      } else {
78944f0eee88ff00398ff7f715fab053374d808c90dSteve Block        if (cpu_profiling_enabled) {
79044f0eee88ff00398ff7f715fab053374d808c90dSteve Block          if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile,
79144f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                                      this)) {
79244f0eee88ff00398ff7f715fab053374d808c90dSteve Block            return;
79344f0eee88ff00398ff7f715fab053374d808c90dSteve Block          }
79444f0eee88ff00398ff7f715fab053374d808c90dSteve Block        }
79544f0eee88ff00398ff7f715fab053374d808c90dSteve Block        if (runtime_profiler_enabled) {
79644f0eee88ff00398ff7f715fab053374d808c90dSteve Block          if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile,
79744f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                                      NULL)) {
79844f0eee88ff00398ff7f715fab053374d808c90dSteve Block            return;
79944f0eee88ff00398ff7f715fab053374d808c90dSteve Block          }
80044f0eee88ff00398ff7f715fab053374d808c90dSteve Block        }
80144f0eee88ff00398ff7f715fab053374d808c90dSteve Block        Sleep(FULL_INTERVAL);
80244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      }
80344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    }
80444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
80544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
80644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static void DoCpuProfile(Sampler* sampler, void* raw_sender) {
80744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (!sampler->IsProfiling()) return;
80844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender);
80944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    sender->SendProfilingSignal(sampler->platform_data()->vm_tid());
81044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
81144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
81244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static void DoRuntimeProfile(Sampler* sampler, void* ignored) {
81344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (!sampler->isolate()->IsInitialized()) return;
81444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    sampler->isolate()->runtime_profiler()->NotifyTick();
81544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
81644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
81744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  void SendProfilingSignal(pthread_t tid) {
81844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (!signal_handler_installed_) return;
81944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    pthread_kill(tid, SIGPROF);
82044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
82144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
82244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  void Sleep(SleepInterval full_or_half) {
82344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Convert ms to us and subtract 100 us to compensate delays
82444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // occuring during signal delivery.
82544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    useconds_t interval = interval_ * 1000 - 100;
82644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (full_or_half == HALF_INTERVAL) interval /= 2;
82744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    int result = usleep(interval);
82844f0eee88ff00398ff7f715fab053374d808c90dSteve Block#ifdef DEBUG
82944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (result != 0 && errno != EINTR) {
83044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      fprintf(stderr,
83144f0eee88ff00398ff7f715fab053374d808c90dSteve Block              "SignalSender usleep error; interval = %u, errno = %d\n",
83244f0eee88ff00398ff7f715fab053374d808c90dSteve Block              interval,
83344f0eee88ff00398ff7f715fab053374d808c90dSteve Block              errno);
83444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ASSERT(result == 0 || errno == EINTR);
83544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    }
83644f0eee88ff00398ff7f715fab053374d808c90dSteve Block#endif
83744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    USE(result);
83844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
83944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
84044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const int interval_;
84144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  RuntimeProfilerRateLimiter rate_limiter_;
84244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
84344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Protects the process wide state below.
84444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static Mutex* mutex_;
84544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static SignalSender* instance_;
84644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static bool signal_handler_installed_;
84744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static struct sigaction old_signal_handler_;
84844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
84944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  DISALLOW_COPY_AND_ASSIGN(SignalSender);
850a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
851a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
85244f0eee88ff00398ff7f715fab053374d808c90dSteve BlockMutex* SignalSender::mutex_ = OS::CreateMutex();
85344f0eee88ff00398ff7f715fab053374d808c90dSteve BlockSignalSender* SignalSender::instance_ = NULL;
85444f0eee88ff00398ff7f715fab053374d808c90dSteve Blockstruct sigaction SignalSender::old_signal_handler_;
85544f0eee88ff00398ff7f715fab053374d808c90dSteve Blockbool SignalSender::signal_handler_installed_ = false;
856a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
85744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
85844f0eee88ff00398ff7f715fab053374d808c90dSteve BlockSampler::Sampler(Isolate* isolate, int interval)
85944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    : isolate_(isolate),
86044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      interval_(interval),
861b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      profiling_(false),
8628a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      active_(false),
8638a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      samples_taken_(0) {
86444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  data_ = new PlatformData;
865a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
866a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
867a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
868a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockSampler::~Sampler() {
86944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ASSERT(!IsActive());
870a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  delete data_;
871a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
872a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
873a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
874a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Sampler::Start() {
87544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ASSERT(!IsActive());
87644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  SetActive(true);
87744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  SignalSender::AddActiveSampler(this);
878a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
879a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
880a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
881a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Sampler::Stop() {
88244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ASSERT(IsActive());
88344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  SignalSender::RemoveActiveSampler(this);
88444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  SetActive(false);
885a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
886a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
887a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
888a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} }  // namespace v8::internal
889