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"
55a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
56a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "platform.h"
57b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch#include "vm-state-inl.h"
58a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
59a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
60a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace v8 {
61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace internal {
62a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
63a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 0 is never a valid thread id on FreeBSD since tids and pids share a
64a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// name space and pid 0 is used to kill the group (see man 2 kill).
65a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic const pthread_t kNoThread = (pthread_t) 0;
66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
67a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdouble ceiling(double x) {
69a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Correct as on OS X
70a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (-1.0 < x && x < 0.0) {
71a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        return -0.0;
72a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        return ceil(x);
74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
75a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
76a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
77a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7844f0eee88ff00398ff7f715fab053374d808c90dSteve Blockstatic Mutex* limit_mutex = NULL;
7944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
8044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
81a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::Setup() {
82a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Seed the random number generator.
83a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Convert the current time to a 64-bit integer first, before converting it
84a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // to an unsigned. Going directly can cause an overflow and the seed to be
85a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // set to all ones. The seed will be identical for different instances that
86a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // call this setup code within the same millisecond.
87a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
88a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  srandom(static_cast<unsigned int>(seed));
8944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  limit_mutex = CreateMutex();
90a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
91a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
92a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
937f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochvoid OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) {
947f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __asm__ __volatile__("" : : : "memory");
957f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  *ptr = value;
967f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch}
977f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
987f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
99d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockuint64_t OS::CpuFeaturesImpliedByPlatform() {
100d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return 0;  // FreeBSD runs on anything.
101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockint OS::ActivationFrameAlignment() {
105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // 16 byte alignment on FreeBSD
106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return 16;
107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
110d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarkeconst char* OS::LocalTimezone(double time) {
111d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  if (isnan(time)) return "";
112d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  time_t tv = static_cast<time_t>(floor(time/msPerSecond));
113d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  struct tm* t = localtime(&tv);
114d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  if (NULL == t) return "";
115d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  return t->tm_zone;
116d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke}
117d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
118d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
119d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarkedouble OS::LocalTimeOffset() {
120d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  time_t tv = time(NULL);
121d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  struct tm* t = localtime(&tv);
122d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // tm_gmtoff includes any daylight savings offset, so subtract it.
123d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  return static_cast<double>(t->tm_gmtoff * msPerSecond -
124d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                             (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
125d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke}
126d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
127d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// We keep the lowest and highest addresses mapped as a quick way of
129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// determining that pointers are outside the heap (used mostly in assertions
130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// and verification).  The estimate is conservative, ie, not all addresses in
131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 'allocated' space are actually allocated to our heap.  The range is
132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// [lowest, highest), inclusive on the low and and exclusive on the high end.
133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void* highest_ever_allocated = reinterpret_cast<void*>(0);
135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void UpdateAllocatedSpaceLimits(void* address, int size) {
13844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ASSERT(limit_mutex != NULL);
13944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ScopedLock lock(limit_mutex);
14044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  lowest_ever_allocated = Min(lowest_ever_allocated, address);
142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  highest_ever_allocated =
143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Max(highest_ever_allocated,
144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool OS::IsOutsideAllocatedSpace(void* address) {
149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return address < lowest_ever_allocated || address >= highest_ever_allocated;
150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocksize_t OS::AllocateAlignment() {
154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return getpagesize();
155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid* OS::Allocate(const size_t requested,
159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                   size_t* allocated,
160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                   bool executable) {
161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const size_t msize = RoundUp(requested, getpagesize());
162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (mbase == MAP_FAILED) {
16644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    LOG(ISOLATE, StringEvent("OS::Allocate", "mmap failed"));
167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return NULL;
168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  *allocated = msize;
170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  UpdateAllocatedSpaceLimits(mbase, msize);
171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return mbase;
172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::Free(void* buf, const size_t length) {
176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // TODO(1240712): munmap has a return value which is ignored here.
177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int result = munmap(buf, length);
178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  USE(result);
179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(result == 0);
180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_HEAP_PROTECTION
184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::Protect(void* address, size_t size) {
186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  UNIMPLEMENTED();
187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::Unprotect(void* address, size_t size, bool is_executable) {
191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  UNIMPLEMENTED();
192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::Sleep(int milliseconds) {
198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  unsigned int ms = static_cast<unsigned int>(milliseconds);
199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  usleep(1000 * ms);
200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::Abort() {
204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Redirect to std abort to signal abnormal program termination.
205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  abort();
206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::DebugBreak() {
210756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick#if (defined(__arm__) || defined(__thumb__))
211756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick# if defined(CAN_USE_ARMV5_INSTRUCTIONS)
212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  asm("bkpt 0");
213756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick# endif
214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#else
215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  asm("int $3");
216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass PosixMemoryMappedFile : public OS::MemoryMappedFile {
221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  PosixMemoryMappedFile(FILE* file, void* memory, int size)
223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    : file_(file), memory_(memory), size_(size) { }
224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual ~PosixMemoryMappedFile();
225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual void* memory() { return memory_; }
2261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  virtual int size() { return size_; }
227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  FILE* file_;
229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void* memory_;
230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int size_;
231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2341e0659c275bb392c045087af4f6b0d7565cb3d77Steve BlockOS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
235e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  FILE* file = fopen(name, "r+");
2361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  if (file == NULL) return NULL;
2371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  fseek(file, 0, SEEK_END);
2391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  int size = ftell(file);
2401e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  void* memory =
2421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
2431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  return new PosixMemoryMappedFile(file, memory, size);
2441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block}
2451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockOS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    void* initial) {
249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  FILE* file = fopen(name, "w+");
250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (file == NULL) return NULL;
251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int result = fwrite(initial, size, 1, file);
252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (result < 1) {
253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    fclose(file);
254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return NULL;
255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void* memory =
257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return new PosixMemoryMappedFile(file, memory, size);
259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockPosixMemoryMappedFile::~PosixMemoryMappedFile() {
263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (memory_) munmap(memory_, size_);
264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  fclose(file_);
265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_LOGGING_AND_PROFILING
269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic unsigned StringToLong(char* buffer) {
270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return static_cast<unsigned>(strtol(buffer, NULL, 16));  // NOLINT
271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::LogSharedLibraryAddresses() {
276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_LOGGING_AND_PROFILING
277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static const int MAP_LENGTH = 1024;
278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int fd = open("/proc/self/maps", O_RDONLY);
279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (fd < 0) return;
280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  while (true) {
281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    char addr_buffer[11];
282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    addr_buffer[0] = '0';
283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    addr_buffer[1] = 'x';
284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    addr_buffer[10] = 0;
285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int result = read(fd, addr_buffer + 2, 8);
286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (result < 8) break;
287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    unsigned start = StringToLong(addr_buffer);
288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    result = read(fd, addr_buffer + 2, 1);
289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (result < 1) break;
290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (addr_buffer[2] != '-') break;
291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    result = read(fd, addr_buffer + 2, 8);
292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (result < 8) break;
293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    unsigned end = StringToLong(addr_buffer);
294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    char buffer[MAP_LENGTH];
295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int bytes_read = -1;
296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    do {
297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      bytes_read++;
298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (bytes_read >= MAP_LENGTH - 1)
299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        break;
300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      result = read(fd, buffer + bytes_read, 1);
301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (result < 1) break;
302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } while (buffer[bytes_read] != '\n');
303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    buffer[bytes_read] = 0;
304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Ignore mappings that are not executable.
305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (buffer[3] != 'x') continue;
306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    char* start_of_path = index(buffer, '/');
307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // There may be no filename in this line.  Skip to next.
308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (start_of_path == NULL) continue;
309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    buffer[bytes_read] = 0;
31044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    LOG(i::Isolate::Current(), SharedLibraryEvent(start_of_path, start, end));
311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  close(fd);
313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
317f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochvoid OS::SignalCodeMovingGC() {
318f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch}
319f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
320f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockint OS::StackWalk(Vector<OS::StackFrame> frames) {
322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int frames_size = frames.length();
32325f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen  ScopedVector<void*> addresses(frames_size);
324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
32525f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen  int frames_count = backtrace(addresses.start(), frames_size);
326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
327f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke  char** symbols = backtrace_symbols(addresses.start(), frames_count);
328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (symbols == NULL) {
329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return kStackWalkError;
330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < frames_count; i++) {
333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frames[i].address = addresses[i];
334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Format a text representation of the frame based on the information
335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // available.
336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    SNPrintF(MutableCStrVector(frames[i].text, kStackWalkMaxTextLen),
337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block             "%s",
338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block             symbols[i]);
339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Make sure line termination is in place.
340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frames[i].text[kStackWalkMaxTextLen - 1] = '\0';
341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  free(symbols);
344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return frames_count;
346a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Constants used for mmap.
350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic const int kMmapFd = -1;
351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic const int kMmapFdOffset = 0;
352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockVirtualMemory::VirtualMemory(size_t size) {
355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  address_ = mmap(NULL, size, PROT_NONE,
356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                  MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                  kMmapFd, kMmapFdOffset);
358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  size_ = size;
359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockVirtualMemory::~VirtualMemory() {
363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (IsReserved()) {
364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (0 == munmap(address(), size())) address_ = MAP_FAILED;
365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool VirtualMemory::IsReserved() {
370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return address_ != MAP_FAILED;
371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool VirtualMemory::Commit(void* address, size_t size, bool executable) {
375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (MAP_FAILED == mmap(address, size, prot,
377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                         MAP_PRIVATE | MAP_ANON | MAP_FIXED,
378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                         kMmapFd, kMmapFdOffset)) {
379a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return false;
380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  UpdateAllocatedSpaceLimits(address, size);
383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return true;
384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool VirtualMemory::Uncommit(void* address, size_t size) {
388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return mmap(address, size, PROT_NONE,
389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block              MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | MAP_FIXED,
390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block              kMmapFd, kMmapFdOffset) != MAP_FAILED;
391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3948b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdochclass Thread::PlatformData : public Malloced {
395a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_t thread_;  // Thread handle for pthread.
397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockThreadHandle::ThreadHandle(Kind kind) {
401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  data_ = new PlatformData(kind);
402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid ThreadHandle::Initialize(ThreadHandle::Kind kind) {
406a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  data_->Initialize(kind);
407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
408a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
409a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
410a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockThreadHandle::~ThreadHandle() {
411a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  delete data_;
412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
413a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
414a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
415a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool ThreadHandle::IsSelf() const {
416a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return pthread_equal(data_->thread_, pthread_self());
417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool ThreadHandle::IsValid() const {
421a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return data_->thread_ != kNoThread;
422a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
42544f0eee88ff00398ff7f715fab053374d808c90dSteve BlockThread::Thread(Isolate* isolate, const Options& options)
4268b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    : data_(new PlatformData),
42744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      isolate_(isolate),
42844f0eee88ff00398ff7f715fab053374d808c90dSteve Block      stack_size_(options.stack_size) {
42944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  set_name(options.name);
4309fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block}
4319fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
4329fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
43344f0eee88ff00398ff7f715fab053374d808c90dSteve BlockThread::Thread(Isolate* isolate, const char* name)
4348b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    : data_(new PlatformData),
43544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      isolate_(isolate),
43644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      stack_size_(0) {
4371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  set_name(name);
438a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockThread::~Thread() {
4428b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  delete data_;
443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
444a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
445a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
446a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void* ThreadEntry(void* arg) {
447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Thread* thread = reinterpret_cast<Thread*>(arg);
448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // This is also initialized by the first argument to pthread_create() but we
449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // don't know which thread will run first (the original thread or the new
450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // one) so we initialize it here too.
4518b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  thread_->data_->thread_ = pthread_self();
452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(thread->IsValid());
45344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Thread::SetThreadLocal(Isolate::isolate_key(), thread->isolate());
454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  thread->Run();
455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return NULL;
456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid Thread::set_name(const char* name) {
4609fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  strncpy(name_, name, sizeof(name_));
4619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  name_[sizeof(name_) - 1] = '\0';
4629fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block}
4639fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
4649fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
465a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Thread::Start() {
46644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  pthread_attr_t* attr_ptr = NULL;
46744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  pthread_attr_t attr;
46844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (stack_size_ > 0) {
46944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    pthread_attr_init(&attr);
47044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
47144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    attr_ptr = &attr;
47244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
47344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  pthread_create(&thread_handle_data()->thread_, attr_ptr, ThreadEntry, this);
474a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(IsValid());
475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
478a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Thread::Join() {
479a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_join(thread_handle_data()->thread_, NULL);
480a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockThread::LocalStorageKey Thread::CreateThreadLocalKey() {
484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_key_t key;
485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int result = pthread_key_create(&key, NULL);
486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  USE(result);
487a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(result == 0);
488a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return static_cast<LocalStorageKey>(key);
489a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
490a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Thread::DeleteThreadLocalKey(LocalStorageKey key) {
493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
494a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int result = pthread_key_delete(pthread_key);
495a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  USE(result);
496a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(result == 0);
497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
500a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid* Thread::GetThreadLocal(LocalStorageKey key) {
501a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return pthread_getspecific(pthread_key);
503a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
504a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
505a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
506a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Thread::SetThreadLocal(LocalStorageKey key, void* value) {
507a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
508a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_setspecific(pthread_key, value);
509a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
510a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
511a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
512a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Thread::YieldCPU() {
513a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  sched_yield();
514a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
515a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
516a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
517a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass FreeBSDMutex : public Mutex {
518a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
519a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  FreeBSDMutex() {
521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    pthread_mutexattr_t attrs;
522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int result = pthread_mutexattr_init(&attrs);
523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(result == 0);
524a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
525a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(result == 0);
526a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    result = pthread_mutex_init(&mutex_, &attrs);
527a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(result == 0);
528a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
529a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
530a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual ~FreeBSDMutex() { pthread_mutex_destroy(&mutex_); }
531a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
532a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual int Lock() {
533a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int result = pthread_mutex_lock(&mutex_);
534a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return result;
535a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
536a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
537a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual int Unlock() {
538a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int result = pthread_mutex_unlock(&mutex_);
539a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return result;
540a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
541a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
54244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  virtual bool TryLock() {
54344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    int result = pthread_mutex_trylock(&mutex_);
54444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Return false if the lock is busy and locking failed.
54544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (result == EBUSY) {
54644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      return false;
54744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    }
54844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    ASSERT(result == 0);  // Verify no other errors.
54944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    return true;
55044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
55144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
552a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
553a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_mutex_t mutex_;   // Pthread mutex for POSIX platforms.
554a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
555a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
556a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
557a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockMutex* OS::CreateMutex() {
558a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return new FreeBSDMutex();
559a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
560a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
562a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass FreeBSDSemaphore : public Semaphore {
563a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
564a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  explicit FreeBSDSemaphore(int count) {  sem_init(&sem_, 0, count); }
565a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual ~FreeBSDSemaphore() { sem_destroy(&sem_); }
566a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
567a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual void Wait();
568a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual bool Wait(int timeout);
569a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual void Signal() { sem_post(&sem_); }
570a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
571a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  sem_t sem_;
572a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
573a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
574a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
575a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid FreeBSDSemaphore::Wait() {
576a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  while (true) {
577a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int result = sem_wait(&sem_);
578a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (result == 0) return;  // Successfully got semaphore.
579a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
580a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
581a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
582a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
583a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
584a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool FreeBSDSemaphore::Wait(int timeout) {
585a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const long kOneSecondMicros = 1000000;  // NOLINT
586a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
587a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Split timeout into second and nanosecond parts.
588a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  struct timeval delta;
589a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  delta.tv_usec = timeout % kOneSecondMicros;
590a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  delta.tv_sec = timeout / kOneSecondMicros;
591a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
592a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  struct timeval current_time;
593a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the current time.
594a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (gettimeofday(&current_time, NULL) == -1) {
595a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return false;
596a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
597a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
598a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Calculate time for end of timeout.
599a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  struct timeval end_time;
600a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  timeradd(&current_time, &delta, &end_time);
601a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
602a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  struct timespec ts;
603a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  TIMEVAL_TO_TIMESPEC(&end_time, &ts);
604a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  while (true) {
605a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int result = sem_timedwait(&sem_, &ts);
606a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (result == 0) return true;  // Successfully got semaphore.
607a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (result == -1 && errno == ETIMEDOUT) return false;  // Timeout.
608a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
609a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
610a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
611a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
612a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
613a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockSemaphore* OS::CreateSemaphore(int count) {
614a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return new FreeBSDSemaphore(count);
615a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
616a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
617a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
618a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_LOGGING_AND_PROFILING
619a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
62044f0eee88ff00398ff7f715fab053374d808c90dSteve Blockstatic pthread_t GetThreadID() {
62144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  pthread_t thread_id = pthread_self();
62244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  return thread_id;
62344f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
62444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
62544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
62644f0eee88ff00398ff7f715fab053374d808c90dSteve Blockclass Sampler::PlatformData : public Malloced {
62744f0eee88ff00398ff7f715fab053374d808c90dSteve Block public:
62844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  PlatformData() : vm_tid_(GetThreadID()) {}
62944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
63044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  pthread_t vm_tid() const { return vm_tid_; }
63144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
63244f0eee88ff00398ff7f715fab053374d808c90dSteve Block private:
63344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  pthread_t vm_tid_;
63444f0eee88ff00398ff7f715fab053374d808c90dSteve Block};
63544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
636a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
637a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
638a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  USE(info);
639a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (signal != SIGPROF) return;
64044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Isolate* isolate = Isolate::UncheckedCurrent();
64144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
64244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // We require a fully initialized and entered isolate.
64344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    return;
64444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
6458b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  if (v8::Locker::IsActive() &&
6468b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      !isolate->thread_manager()->IsLockedByCurrentThread()) {
6478b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    return;
6488b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  }
6498b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch
65044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Sampler* sampler = isolate->logger()->sampler();
65144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (sampler == NULL || !sampler->IsActive()) return;
652a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
65344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  TickSample sample_obj;
65444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  TickSample* sample = CpuProfiler::TickSampleEvent(isolate);
65544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (sample == NULL) sample = &sample_obj;
6566ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
65744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Extracting the sample from the context is extremely machine dependent.
65844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
65944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  mcontext_t& mcontext = ucontext->uc_mcontext;
66044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->state = isolate->current_vm_state();
661a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#if V8_HOST_ARCH_IA32
66244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->pc = reinterpret_cast<Address>(mcontext.mc_eip);
66344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->sp = reinterpret_cast<Address>(mcontext.mc_esp);
66444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->fp = reinterpret_cast<Address>(mcontext.mc_ebp);
665a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#elif V8_HOST_ARCH_X64
66644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->pc = reinterpret_cast<Address>(mcontext.mc_rip);
66744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->sp = reinterpret_cast<Address>(mcontext.mc_rsp);
66844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->fp = reinterpret_cast<Address>(mcontext.mc_rbp);
669a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#elif V8_HOST_ARCH_ARM
67044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->pc = reinterpret_cast<Address>(mcontext.mc_r15);
67144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->sp = reinterpret_cast<Address>(mcontext.mc_r13);
67244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sample->fp = reinterpret_cast<Address>(mcontext.mc_r11);
673a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
67444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sampler->SampleStack(sample);
67544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  sampler->Tick(sample);
676a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
677a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
678a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
67944f0eee88ff00398ff7f715fab053374d808c90dSteve Blockclass SignalSender : public Thread {
680a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
68144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  enum SleepInterval {
68244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    HALF_INTERVAL,
68344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    FULL_INTERVAL
68444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  };
68544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
68644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  explicit SignalSender(int interval)
68744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      : Thread(NULL, "SignalSender"),
68844f0eee88ff00398ff7f715fab053374d808c90dSteve Block        interval_(interval) {}
68944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
69044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static void AddActiveSampler(Sampler* sampler) {
69144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    ScopedLock lock(mutex_);
69244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    SamplerRegistry::AddActiveSampler(sampler);
69344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (instance_ == NULL) {
69444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      // Install a signal handler.
69544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      struct sigaction sa;
69644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      sa.sa_sigaction = ProfilerSignalHandler;
69744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      sigemptyset(&sa.sa_mask);
69844f0eee88ff00398ff7f715fab053374d808c90dSteve Block      sa.sa_flags = SA_RESTART | SA_SIGINFO;
69944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      signal_handler_installed_ =
70044f0eee88ff00398ff7f715fab053374d808c90dSteve Block          (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
70144f0eee88ff00398ff7f715fab053374d808c90dSteve Block
70244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      // Start a thread that sends SIGPROF signal to VM threads.
70344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      instance_ = new SignalSender(sampler->interval());
70444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      instance_->Start();
70544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    } else {
70644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ASSERT(instance_->interval_ == sampler->interval());
70744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    }
708a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
709a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
71044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static void RemoveActiveSampler(Sampler* sampler) {
71144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    ScopedLock lock(mutex_);
71244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    SamplerRegistry::RemoveActiveSampler(sampler);
71344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
71444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      RuntimeProfiler::WakeUpRuntimeProfilerThreadBeforeShutdown();
71544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      instance_->Join();
71644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      delete instance_;
71744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      instance_ = NULL;
71844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
71944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      // Restore the old signal handler.
72044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      if (signal_handler_installed_) {
72144f0eee88ff00398ff7f715fab053374d808c90dSteve Block        sigaction(SIGPROF, &old_signal_handler_, 0);
72244f0eee88ff00398ff7f715fab053374d808c90dSteve Block        signal_handler_installed_ = false;
72344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      }
72444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    }
72544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
72644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
72744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Implement Thread::Run().
72844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  virtual void Run() {
72944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    SamplerRegistry::State state;
73044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    while ((state = SamplerRegistry::GetState()) !=
73144f0eee88ff00398ff7f715fab053374d808c90dSteve Block           SamplerRegistry::HAS_NO_SAMPLERS) {
73244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      bool cpu_profiling_enabled =
73344f0eee88ff00398ff7f715fab053374d808c90dSteve Block          (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS);
73444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled();
73544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      // When CPU profiling is enabled both JavaScript and C++ code is
73644f0eee88ff00398ff7f715fab053374d808c90dSteve Block      // profiled. We must not suspend.
73744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      if (!cpu_profiling_enabled) {
73844f0eee88ff00398ff7f715fab053374d808c90dSteve Block        if (rate_limiter_.SuspendIfNecessary()) continue;
73944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      }
74044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      if (cpu_profiling_enabled && runtime_profiler_enabled) {
74144f0eee88ff00398ff7f715fab053374d808c90dSteve Block        if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) {
74244f0eee88ff00398ff7f715fab053374d808c90dSteve Block          return;
74344f0eee88ff00398ff7f715fab053374d808c90dSteve Block        }
74444f0eee88ff00398ff7f715fab053374d808c90dSteve Block        Sleep(HALF_INTERVAL);
74544f0eee88ff00398ff7f715fab053374d808c90dSteve Block        if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) {
74644f0eee88ff00398ff7f715fab053374d808c90dSteve Block          return;
74744f0eee88ff00398ff7f715fab053374d808c90dSteve Block        }
74844f0eee88ff00398ff7f715fab053374d808c90dSteve Block        Sleep(HALF_INTERVAL);
74944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      } else {
75044f0eee88ff00398ff7f715fab053374d808c90dSteve Block        if (cpu_profiling_enabled) {
75144f0eee88ff00398ff7f715fab053374d808c90dSteve Block          if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile,
75244f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                                      this)) {
75344f0eee88ff00398ff7f715fab053374d808c90dSteve Block            return;
75444f0eee88ff00398ff7f715fab053374d808c90dSteve Block          }
75544f0eee88ff00398ff7f715fab053374d808c90dSteve Block        }
75644f0eee88ff00398ff7f715fab053374d808c90dSteve Block        if (runtime_profiler_enabled) {
75744f0eee88ff00398ff7f715fab053374d808c90dSteve Block          if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile,
75844f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                                      NULL)) {
75944f0eee88ff00398ff7f715fab053374d808c90dSteve Block            return;
76044f0eee88ff00398ff7f715fab053374d808c90dSteve Block          }
76144f0eee88ff00398ff7f715fab053374d808c90dSteve Block        }
76244f0eee88ff00398ff7f715fab053374d808c90dSteve Block        Sleep(FULL_INTERVAL);
76344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      }
76444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    }
76544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
76644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
76744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static void DoCpuProfile(Sampler* sampler, void* raw_sender) {
76844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (!sampler->IsProfiling()) return;
76944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender);
77044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    sender->SendProfilingSignal(sampler->platform_data()->vm_tid());
77144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
77244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
77344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static void DoRuntimeProfile(Sampler* sampler, void* ignored) {
77444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (!sampler->isolate()->IsInitialized()) return;
77544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    sampler->isolate()->runtime_profiler()->NotifyTick();
77644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
77744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
77844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  void SendProfilingSignal(pthread_t tid) {
77944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (!signal_handler_installed_) return;
78044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    pthread_kill(tid, SIGPROF);
78144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
78244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
78344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  void Sleep(SleepInterval full_or_half) {
78444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // Convert ms to us and subtract 100 us to compensate delays
78544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    // occuring during signal delivery.
78644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    useconds_t interval = interval_ * 1000 - 100;
78744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (full_or_half == HALF_INTERVAL) interval /= 2;
78844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    int result = usleep(interval);
78944f0eee88ff00398ff7f715fab053374d808c90dSteve Block#ifdef DEBUG
79044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (result != 0 && errno != EINTR) {
79144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      fprintf(stderr,
79244f0eee88ff00398ff7f715fab053374d808c90dSteve Block              "SignalSender usleep error; interval = %u, errno = %d\n",
79344f0eee88ff00398ff7f715fab053374d808c90dSteve Block              interval,
79444f0eee88ff00398ff7f715fab053374d808c90dSteve Block              errno);
79544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ASSERT(result == 0 || errno == EINTR);
79644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    }
79744f0eee88ff00398ff7f715fab053374d808c90dSteve Block#endif
79844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    USE(result);
79944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
80044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
80144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const int interval_;
80244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  RuntimeProfilerRateLimiter rate_limiter_;
80344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
80444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  // Protects the process wide state below.
80544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static Mutex* mutex_;
80644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static SignalSender* instance_;
80744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static bool signal_handler_installed_;
80844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static struct sigaction old_signal_handler_;
80944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
81044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  DISALLOW_COPY_AND_ASSIGN(SignalSender);
811a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
812a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
81344f0eee88ff00398ff7f715fab053374d808c90dSteve BlockMutex* SignalSender::mutex_ = OS::CreateMutex();
81444f0eee88ff00398ff7f715fab053374d808c90dSteve BlockSignalSender* SignalSender::instance_ = NULL;
81544f0eee88ff00398ff7f715fab053374d808c90dSteve Blockstruct sigaction SignalSender::old_signal_handler_;
81644f0eee88ff00398ff7f715fab053374d808c90dSteve Blockbool SignalSender::signal_handler_installed_ = false;
817a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
81844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
81944f0eee88ff00398ff7f715fab053374d808c90dSteve BlockSampler::Sampler(Isolate* isolate, int interval)
82044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    : isolate_(isolate),
82144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      interval_(interval),
822b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      profiling_(false),
8238a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      active_(false),
8248a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      samples_taken_(0) {
82544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  data_ = new PlatformData;
826a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
827a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
828a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
829a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockSampler::~Sampler() {
83044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ASSERT(!IsActive());
831a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  delete data_;
832a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
833a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
834a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
835a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Sampler::Start() {
83644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ASSERT(!IsActive());
83744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  SetActive(true);
83844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  SignalSender::AddActiveSampler(this);
839a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
840a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
841a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
842a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Sampler::Stop() {
84344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ASSERT(IsActive());
84444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  SignalSender::RemoveActiveSampler(this);
84544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  SetActive(false);
846a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
847a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
848a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif  // ENABLE_LOGGING_AND_PROFILING
849a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
850a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} }  // namespace v8::internal
851