13ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// Copyright 2012 the V8 project authors. All rights reserved.
2d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// Redistribution and use in source and binary forms, with or without
3d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// modification, are permitted provided that the following conditions are
4d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// met:
5d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block//
6d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block//     * Redistributions of source code must retain the above copyright
7d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block//       notice, this list of conditions and the following disclaimer.
8d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block//     * Redistributions in binary form must reproduce the above
9d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block//       copyright notice, this list of conditions and the following
10d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block//       disclaimer in the documentation and/or other materials provided
11d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block//       with the distribution.
12d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block//     * Neither the name of Google Inc. nor the names of its
13d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block//       contributors may be used to endorse or promote products derived
14d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block//       from this software without specific prior written permission.
15d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block//
16d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// Platform specific code for OpenBSD and NetBSD goes here. For the POSIX
293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// comaptible parts the implementation is in platform-posix.cc.
30d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
31d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include <pthread.h>
32d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include <semaphore.h>
33d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include <signal.h>
34d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include <sys/time.h>
35d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include <sys/resource.h>
363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#include <sys/syscall.h>
37d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include <sys/types.h>
38d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include <stdlib.h>
39d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
40d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include <sys/types.h>  // mmap & munmap
41d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include <sys/mman.h>   // mmap & munmap
42d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include <sys/stat.h>   // open
433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#include <fcntl.h>      // open
443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#include <unistd.h>     // sysconf
45d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include <execinfo.h>   // backtrace, backtrace_symbols
46d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include <strings.h>    // index
47d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include <errno.h>
48d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include <stdarg.h>
49d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
50d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#undef MAP_TYPE
51d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
52d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include "v8.h"
53d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#include "platform-posix.h"
55d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include "platform.h"
563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#include "v8threads.h"
57b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch#include "vm-state-inl.h"
58d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
59d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
60d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blocknamespace v8 {
61d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blocknamespace internal {
62d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// 0 is never a valid thread id on Linux and OpenBSD since tids and pids share a
643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// name space and pid 0 is reserved (see man 2 kill).
65d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockstatic const pthread_t kNoThread = (pthread_t) 0;
66d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
67d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
68d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockdouble ceiling(double x) {
693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return ceil(x);
70d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
71d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
72d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochstatic Mutex* limit_mutex = NULL;
743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochstatic void* GetRandomMmapAddr() {
773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Isolate* isolate = Isolate::UncheckedCurrent();
783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Note that the current isolate isn't set up in a call path via
793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // CpuFeatures::Probe. We don't care about randomization in this case because
803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // the code page is immediately freed.
813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (isolate != NULL) {
823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#ifdef V8_TARGET_ARCH_X64
833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    uint64_t rnd1 = V8::RandomPrivate(isolate);
843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    uint64_t rnd2 = V8::RandomPrivate(isolate);
853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    uint64_t raw_addr = (rnd1 << 32) ^ rnd2;
863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Currently available CPUs have 48 bits of virtual addressing.  Truncate
873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // the hint address to 46 bits to give the kernel a fighting chance of
883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // fulfilling our placement request.
893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    raw_addr &= V8_UINT64_C(0x3ffffffff000);
903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#else
913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    uint32_t raw_addr = V8::RandomPrivate(isolate);
923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // The range 0x20000000 - 0x60000000 is relatively unpopulated across a
933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // variety of ASLR modes (PAE kernel, NX compat mode, etc).
943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    raw_addr &= 0x3ffff000;
953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    raw_addr += 0x20000000;
963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#endif
973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    return reinterpret_cast<void*>(raw_addr);
983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return NULL;
1003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
1013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid OS::SetUp() {
1043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Seed the random number generator. We preserve microsecond resolution.
1053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  uint64_t seed = Ticks() ^ (getpid() << 16);
10685b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch  srandom(static_cast<unsigned int>(seed));
10785b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch  limit_mutex = CreateMutex();
108d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
109d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
110d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
1113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid OS::PostSetUp() {
1123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Math functions depend on CPU features therefore they are initialized after
1133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // CPU.
1143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  MathSetup();
1153bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch}
1163bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
1173bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
118d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockuint64_t OS::CpuFeaturesImpliedByPlatform() {
1193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return 0;
120d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
121d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
122d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
123d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockint OS::ActivationFrameAlignment() {
1243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // With gcc 4.4 the tree vectorization optimizer can generate code
1253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // that requires 16 byte alignment such as movdqa on x86.
126d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return 16;
127d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
128d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
129d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
1303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) {
1313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  __asm__ __volatile__("" : : : "memory");
1323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // An x86 store acts as a release barrier.
1333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  *ptr = value;
1343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
1353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
137d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarkeconst char* OS::LocalTimezone(double time) {
138d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  if (isnan(time)) return "";
139d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  time_t tv = static_cast<time_t>(floor(time/msPerSecond));
140d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  struct tm* t = localtime(&tv);
141d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  if (NULL == t) return "";
142d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  return t->tm_zone;
143d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke}
144d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
145d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
146d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarkedouble OS::LocalTimeOffset() {
147d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  time_t tv = time(NULL);
148d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  struct tm* t = localtime(&tv);
149d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // tm_gmtoff includes any daylight savings offset, so subtract it.
150d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  return static_cast<double>(t->tm_gmtoff * msPerSecond -
151d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                             (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
152d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke}
153d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
154d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
155d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// We keep the lowest and highest addresses mapped as a quick way of
156d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// determining that pointers are outside the heap (used mostly in assertions
1573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// and verification).  The estimate is conservative, i.e., not all addresses in
158d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// 'allocated' space are actually allocated to our heap.  The range is
159d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// [lowest, highest), inclusive on the low and and exclusive on the high end.
160d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockstatic void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
161d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockstatic void* highest_ever_allocated = reinterpret_cast<void*>(0);
162d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
163d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
164d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockstatic void UpdateAllocatedSpaceLimits(void* address, int size) {
1653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  ASSERT(limit_mutex != NULL);
1663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  ScopedLock lock(limit_mutex);
1673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
168d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  lowest_ever_allocated = Min(lowest_ever_allocated, address);
169d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  highest_ever_allocated =
170d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      Max(highest_ever_allocated,
171d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block          reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
172d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
173d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
174d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
175d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockbool OS::IsOutsideAllocatedSpace(void* address) {
176d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return address < lowest_ever_allocated || address >= highest_ever_allocated;
177d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
178d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
179d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
180d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blocksize_t OS::AllocateAlignment() {
1813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return sysconf(_SC_PAGESIZE);
182d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
183d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
184d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
185d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid* OS::Allocate(const size_t requested,
186d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                   size_t* allocated,
1873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                   bool is_executable) {
1883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const size_t msize = RoundUp(requested, AllocateAlignment());
1893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
1903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  void* addr = GetRandomMmapAddr();
1913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  void* mbase = mmap(addr, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
192d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (mbase == MAP_FAILED) {
1933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    LOG(i::Isolate::Current(),
1943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        StringEvent("OS::Allocate", "mmap failed"));
195d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    return NULL;
196d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
197d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  *allocated = msize;
198d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  UpdateAllocatedSpaceLimits(mbase, msize);
199d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return mbase;
200d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
201d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
202d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
2033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid OS::Free(void* address, const size_t size) {
2043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // TODO(1240712): munmap has a return value which is ignored here.
2053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  int result = munmap(address, size);
206d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  USE(result);
207d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  ASSERT(result == 0);
208d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
209d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
210d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
211d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid OS::Sleep(int milliseconds) {
212d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  unsigned int ms = static_cast<unsigned int>(milliseconds);
213d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  usleep(1000 * ms);
214d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
215d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
216d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
217d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid OS::Abort() {
218d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Redirect to std abort to signal abnormal program termination.
219d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  abort();
220d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
221d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
222d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
223d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid OS::DebugBreak() {
224d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  asm("int $3");
225d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
226d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
227d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
228d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockclass PosixMemoryMappedFile : public OS::MemoryMappedFile {
229d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block public:
230d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  PosixMemoryMappedFile(FILE* file, void* memory, int size)
231d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    : file_(file), memory_(memory), size_(size) { }
232d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  virtual ~PosixMemoryMappedFile();
233d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  virtual void* memory() { return memory_; }
2341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  virtual int size() { return size_; }
235d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block private:
236d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  FILE* file_;
237d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  void* memory_;
238d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  int size_;
239d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block};
240d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
241d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
2421e0659c275bb392c045087af4f6b0d7565cb3d77Steve BlockOS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
243e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  FILE* file = fopen(name, "r+");
2441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  if (file == NULL) return NULL;
2451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  fseek(file, 0, SEEK_END);
2471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  int size = ftell(file);
2481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  void* memory =
2501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
2511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  return new PosixMemoryMappedFile(file, memory, size);
2521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block}
2531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
255d0582a6c46733687d045e4188a1bcd0123c758a1Steve BlockOS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
256d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    void* initial) {
257d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  FILE* file = fopen(name, "w+");
258d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (file == NULL) return NULL;
259d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  int result = fwrite(initial, size, 1, file);
260d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (result < 1) {
261d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    fclose(file);
262d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    return NULL;
263d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
264d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  void* memory =
265d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
266d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return new PosixMemoryMappedFile(file, memory, size);
267d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
268d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
269d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
270d0582a6c46733687d045e4188a1bcd0123c758a1Steve BlockPosixMemoryMappedFile::~PosixMemoryMappedFile() {
2713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (memory_) OS::Free(memory_, size_);
272d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  fclose(file_);
273d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
274d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
275d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
276d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid OS::LogSharedLibraryAddresses() {
2773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // This function assumes that the layout of the file is as follows:
2783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // hex_start_addr-hex_end_addr rwxp <unused data> [binary_file_name]
2793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // If we encounter an unexpected situation we abort scanning further entries.
2803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  FILE* fp = fopen("/proc/self/maps", "r");
2813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (fp == NULL) return;
2823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Allocate enough room to be able to store a full file name.
2843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const int kLibNameLen = FILENAME_MAX + 1;
2853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen));
2863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  i::Isolate* isolate = ISOLATE;
2883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // This loop will terminate once the scanning hits an EOF.
289d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  while (true) {
2903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    uintptr_t start, end;
2913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    char attr_r, attr_w, attr_x, attr_p;
2923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Parse the addresses and permission bits at the beginning of the line.
2933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    if (fscanf(fp, "%" V8PRIxPTR "-%" V8PRIxPTR, &start, &end) != 2) break;
2943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    if (fscanf(fp, " %c%c%c%c", &attr_r, &attr_w, &attr_x, &attr_p) != 4) break;
2953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    int c;
2973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    if (attr_r == 'r' && attr_w != 'w' && attr_x == 'x') {
2983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Found a read-only executable entry. Skip characters until we reach
2993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // the beginning of the filename or the end of the line.
3003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      do {
3013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        c = getc(fp);
3023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      } while ((c != EOF) && (c != '\n') && (c != '/'));
3033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      if (c == EOF) break;  // EOF: Was unexpected, just exit.
3043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Process the filename if found.
3063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      if (c == '/') {
3073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        ungetc(c, fp);  // Push the '/' back into the stream to be read below.
3083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        // Read to the end of the line. Exit if the read fails.
3103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        if (fgets(lib_name, kLibNameLen, fp) == NULL) break;
3113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        // Drop the newline character read by fgets. We do not need to check
3133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        // for a zero-length string because we know that we at least read the
3143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        // '/' character.
3153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        lib_name[strlen(lib_name) - 1] = '\0';
3163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      } else {
3173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        // No library name found, just record the raw address range.
3183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        snprintf(lib_name, kLibNameLen,
3193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                 "%08" V8PRIxPTR "-%08" V8PRIxPTR, start, end);
3203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      }
3213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      LOG(isolate, SharedLibraryEvent(lib_name, start, end));
3223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    } else {
3233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Entry not describing executable data. Skip to end of line to set up
3243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // reading the next entry.
3253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      do {
3263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        c = getc(fp);
3273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      } while ((c != EOF) && (c != '\n'));
3283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      if (c == EOF) break;
3293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
330d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
3313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  free(lib_name);
3323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  fclose(fp);
333d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
334d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
335d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
3363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochstatic const char kGCFakeMmap[] = "/tmp/__v8_gc__";
3373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
339f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochvoid OS::SignalCodeMovingGC() {
3403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Support for ll_prof.py.
3413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  //
3423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // The Linux profiler built into the kernel logs all mmap's with
3433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // PROT_EXEC so that analysis tools can properly attribute ticks. We
3443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // do a mmap with a name known by ll_prof.py and immediately munmap
3453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // it. This injects a GC marker into the stream of events generated
3463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // by the kernel and allows us to synchronize V8 code log and the
3473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // kernel log.
3483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  int size = sysconf(_SC_PAGESIZE);
3493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  FILE* f = fopen(kGCFakeMmap, "w+");
3503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  void* addr = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_PRIVATE,
3513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                    fileno(f), 0);
3523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT(addr != MAP_FAILED);
3533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  OS::Free(addr, size);
3543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  fclose(f);
355f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch}
356f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
357f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
358d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockint OS::StackWalk(Vector<OS::StackFrame> frames) {
3593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // backtrace is a glibc extension.
3603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  int frames_size = frames.length();
3613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  ScopedVector<void*> addresses(frames_size);
3623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
3633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  int frames_count = backtrace(addresses.start(), frames_size);
3643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
3653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  char** symbols = backtrace_symbols(addresses.start(), frames_count);
3663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (symbols == NULL) {
3673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    return kStackWalkError;
3683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
3693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
3703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  for (int i = 0; i < frames_count; i++) {
3713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    frames[i].address = addresses[i];
3723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    // Format a text representation of the frame based on the information
3733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    // available.
3743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    SNPrintF(MutableCStrVector(frames[i].text, kStackWalkMaxTextLen),
3753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch             "%s",
3763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch             symbols[i]);
3773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    // Make sure line termination is in place.
3783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    frames[i].text[kStackWalkMaxTextLen - 1] = '\0';
3793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
3803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
3813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  free(symbols);
3823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
3833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  return frames_count;
384d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
385d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
386d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
387d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// Constants used for mmap.
388d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockstatic const int kMmapFd = -1;
389d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockstatic const int kMmapFdOffset = 0;
390d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
3913ef787dbeca8a5fb1086949cda830dccee07bfbdBen MurdochVirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
392d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
393d0582a6c46733687d045e4188a1bcd0123c758a1Steve BlockVirtualMemory::VirtualMemory(size_t size) {
3943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  address_ = ReserveRegion(size);
395d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  size_ = size;
396d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
397d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
398d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
3993ef787dbeca8a5fb1086949cda830dccee07bfbdBen MurdochVirtualMemory::VirtualMemory(size_t size, size_t alignment)
4003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    : address_(NULL), size_(0) {
4013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
4023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  size_t request_size = RoundUp(size + alignment,
4033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                static_cast<intptr_t>(OS::AllocateAlignment()));
4043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  void* reservation = mmap(GetRandomMmapAddr(),
4053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           request_size,
4063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           PROT_NONE,
4073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
4083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           kMmapFd,
4093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           kMmapFdOffset);
4103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (reservation == MAP_FAILED) return;
4113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Address base = static_cast<Address>(reservation);
4133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  Address aligned_base = RoundUp(base, alignment);
4143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT_LE(base, aligned_base);
4153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Unmap extra memory reserved before and after the desired block.
4173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (aligned_base != base) {
4183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    size_t prefix_size = static_cast<size_t>(aligned_base - base);
4193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    OS::Free(base, prefix_size);
4203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    request_size -= prefix_size;
4213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
4223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  size_t aligned_size = RoundUp(size, OS::AllocateAlignment());
4243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT_LE(aligned_size, request_size);
4253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (aligned_size != request_size) {
4273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    size_t suffix_size = request_size - aligned_size;
4283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    OS::Free(aligned_base + aligned_size, suffix_size);
4293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    request_size -= suffix_size;
4303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
4313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ASSERT(aligned_size == request_size);
4333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  address_ = static_cast<void*>(aligned_base);
4353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  size_ = aligned_size;
4363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
4373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
439d0582a6c46733687d045e4188a1bcd0123c758a1Steve BlockVirtualMemory::~VirtualMemory() {
440d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (IsReserved()) {
4413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    bool result = ReleaseRegion(address(), size());
4423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ASSERT(result);
4433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    USE(result);
444d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
445d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
446d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
447d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
448d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockbool VirtualMemory::IsReserved() {
4493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return address_ != NULL;
4503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
4513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid VirtualMemory::Reset() {
4543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  address_ = NULL;
4553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  size_ = 0;
4563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
4573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
4603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return CommitRegion(address, size, is_executable);
4613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
4623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool VirtualMemory::Uncommit(void* address, size_t size) {
4653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return UncommitRegion(address, size);
4663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
4673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool VirtualMemory::Guard(void* address) {
4703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  OS::Guard(address, OS::CommitPageSize());
4713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return true;
4723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
4733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid* VirtualMemory::ReserveRegion(size_t size) {
4763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  void* result = mmap(GetRandomMmapAddr(),
4773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      size,
4783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      PROT_NONE,
4793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
4803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      kMmapFd,
4813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      kMmapFdOffset);
4823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (result == MAP_FAILED) return NULL;
4843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
4853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return result;
486592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch}
487592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
488592a9fc1d8ea420377a2e7efd0600e20b058be2bBen Murdoch
4893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
4903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
4913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (MAP_FAILED == mmap(base,
4923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                         size,
4933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                         prot,
494d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                         MAP_PRIVATE | MAP_ANON | MAP_FIXED,
4953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                         kMmapFd,
4963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                         kMmapFdOffset)) {
497d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    return false;
498d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
499d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
5003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  UpdateAllocatedSpaceLimits(base, size);
501d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return true;
502d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
503d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
504d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
5053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool VirtualMemory::UncommitRegion(void* base, size_t size) {
5063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return mmap(base,
5073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch              size,
5083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch              PROT_NONE,
5093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | MAP_FIXED,
5103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch              kMmapFd,
5113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch              kMmapFdOffset) != MAP_FAILED;
5123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
5133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
5143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
5153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool VirtualMemory::ReleaseRegion(void* base, size_t size) {
5163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return munmap(base, size) == 0;
517d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
518d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
519d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
5208b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdochclass Thread::PlatformData : public Malloced {
521d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block public:
5223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  PlatformData() : thread_(kNoThread) {}
5233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
524d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  pthread_t thread_;  // Thread handle for pthread.
525d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block};
526d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
5273fb3ca8c7ca439d408449a395897395c0faae8d1Ben MurdochThread::Thread(const Options& options)
5283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    : data_(new PlatformData()),
5293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      stack_size_(options.stack_size()) {
5303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  set_name(options.name());
531d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
532d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
533d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
534d0582a6c46733687d045e4188a1bcd0123c758a1Steve BlockThread::~Thread() {
5358b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  delete data_;
536d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
537d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
538d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
539d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockstatic void* ThreadEntry(void* arg) {
540d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  Thread* thread = reinterpret_cast<Thread*>(arg);
541d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // This is also initialized by the first argument to pthread_create() but we
542d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // don't know which thread will run first (the original thread or the new
543d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // one) so we initialize it here too.
5443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#ifdef PR_SET_NAME
5453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  prctl(PR_SET_NAME,
5463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        reinterpret_cast<unsigned long>(thread->name()),  // NOLINT
5473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        0, 0, 0);
5483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#endif
5498b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  thread->data()->thread_ = pthread_self();
5508b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  ASSERT(thread->data()->thread_ != kNoThread);
551d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  thread->Run();
552d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return NULL;
553d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
554d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
555d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
5569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid Thread::set_name(const char* name) {
5579fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  strncpy(name_, name, sizeof(name_));
5589fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  name_[sizeof(name_) - 1] = '\0';
5599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block}
5609fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
5619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
562d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid Thread::Start() {
56344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  pthread_attr_t* attr_ptr = NULL;
56444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  pthread_attr_t attr;
56544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (stack_size_ > 0) {
56644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    pthread_attr_init(&attr);
56744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
56844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    attr_ptr = &attr;
56944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
5708b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  pthread_create(&data_->thread_, attr_ptr, ThreadEntry, this);
5713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  ASSERT(data_->thread_ != kNoThread);
572d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
573d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
574d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
575d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid Thread::Join() {
5768b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  pthread_join(data_->thread_, NULL);
577d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
578d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
579d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
580d0582a6c46733687d045e4188a1bcd0123c758a1Steve BlockThread::LocalStorageKey Thread::CreateThreadLocalKey() {
581d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  pthread_key_t key;
582d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  int result = pthread_key_create(&key, NULL);
583d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  USE(result);
584d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  ASSERT(result == 0);
585d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return static_cast<LocalStorageKey>(key);
586d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
587d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
588d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
589d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid Thread::DeleteThreadLocalKey(LocalStorageKey key) {
590d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
591d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  int result = pthread_key_delete(pthread_key);
592d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  USE(result);
593d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  ASSERT(result == 0);
594d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
595d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
596d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
597d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid* Thread::GetThreadLocal(LocalStorageKey key) {
598d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
599d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return pthread_getspecific(pthread_key);
600d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
601d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
602d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
603d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid Thread::SetThreadLocal(LocalStorageKey key, void* value) {
604d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
605d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  pthread_setspecific(pthread_key, value);
606d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
607d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
608d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
609d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid Thread::YieldCPU() {
610d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  sched_yield();
611d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
612d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
613d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
614d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockclass OpenBSDMutex : public Mutex {
615d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block public:
616d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  OpenBSDMutex() {
617d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    pthread_mutexattr_t attrs;
618d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    int result = pthread_mutexattr_init(&attrs);
619d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    ASSERT(result == 0);
620d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
621d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    ASSERT(result == 0);
622d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    result = pthread_mutex_init(&mutex_, &attrs);
623d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    ASSERT(result == 0);
6243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    USE(result);
625d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
626d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
627d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  virtual ~OpenBSDMutex() { pthread_mutex_destroy(&mutex_); }
628d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
629d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  virtual int Lock() {
630d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    int result = pthread_mutex_lock(&mutex_);
631d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    return result;
632d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
633d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
634d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  virtual int Unlock() {
635d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    int result = pthread_mutex_unlock(&mutex_);
636d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    return result;
637d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
638d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
6393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  virtual bool TryLock() {
6403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    int result = pthread_mutex_trylock(&mutex_);
6413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    // Return false if the lock is busy and locking failed.
6423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    if (result == EBUSY) {
6433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      return false;
6443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    }
6453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    ASSERT(result == 0);  // Verify no other errors.
6463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    return true;
6473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
6483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
649d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block private:
650d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  pthread_mutex_t mutex_;   // Pthread mutex for POSIX platforms.
651d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block};
652d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
653d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
654d0582a6c46733687d045e4188a1bcd0123c758a1Steve BlockMutex* OS::CreateMutex() {
655d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return new OpenBSDMutex();
656d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
657d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
658d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
659d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockclass OpenBSDSemaphore : public Semaphore {
660d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block public:
661d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  explicit OpenBSDSemaphore(int count) {  sem_init(&sem_, 0, count); }
662d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  virtual ~OpenBSDSemaphore() { sem_destroy(&sem_); }
663d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
664d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  virtual void Wait();
665d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  virtual bool Wait(int timeout);
666d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  virtual void Signal() { sem_post(&sem_); }
667d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block private:
668d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  sem_t sem_;
669d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block};
670d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
671d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
672d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid OpenBSDSemaphore::Wait() {
673d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  while (true) {
674d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    int result = sem_wait(&sem_);
675d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    if (result == 0) return;  // Successfully got semaphore.
676d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
677d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
678d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
679d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
680d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
6813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#ifndef TIMEVAL_TO_TIMESPEC
6823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#define TIMEVAL_TO_TIMESPEC(tv, ts) do {                            \
6833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    (ts)->tv_sec = (tv)->tv_sec;                                    \
6843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    (ts)->tv_nsec = (tv)->tv_usec * 1000;                           \
6853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} while (false)
6863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#endif
6873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
6883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
689d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockbool OpenBSDSemaphore::Wait(int timeout) {
690d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  const long kOneSecondMicros = 1000000;  // NOLINT
691d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
692d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Split timeout into second and nanosecond parts.
693d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  struct timeval delta;
694d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  delta.tv_usec = timeout % kOneSecondMicros;
695d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  delta.tv_sec = timeout / kOneSecondMicros;
696d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
697d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  struct timeval current_time;
698d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Get the current time.
699d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (gettimeofday(&current_time, NULL) == -1) {
700d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    return false;
701d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
702d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
703d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Calculate time for end of timeout.
704d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  struct timeval end_time;
705d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  timeradd(&current_time, &delta, &end_time);
706d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
707d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  struct timespec ts;
708d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  TIMEVAL_TO_TIMESPEC(&end_time, &ts);
7093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
7103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  int to = ts.tv_sec;
7113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
712d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  while (true) {
713d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    int result = sem_trywait(&sem_);
714d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    if (result == 0) return true;  // Successfully got semaphore.
7153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    if (!to) return false;  // Timeout.
716d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
7173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    usleep(ts.tv_nsec / 1000);
7183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    to--;
719d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
720d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
721d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
722d0582a6c46733687d045e4188a1bcd0123c758a1Steve BlockSemaphore* OS::CreateSemaphore(int count) {
723d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return new OpenBSDSemaphore(count);
724d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
725d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
726d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
7273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochstatic pthread_t GetThreadID() {
7283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return pthread_self();
7293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch}
7303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
731d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockstatic void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
732d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  USE(info);
733d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (signal != SIGPROF) return;
7343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Isolate* isolate = Isolate::UncheckedCurrent();
7353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
7363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    // We require a fully initialized and entered isolate.
7373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    return;
7383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
7393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (v8::Locker::IsActive() &&
7403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      !isolate->thread_manager()->IsLockedByCurrentThread()) {
7413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    return;
7423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
743d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
7443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  Sampler* sampler = isolate->logger()->sampler();
7453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (sampler == NULL || !sampler->IsActive()) return;
7463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
7473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  TickSample sample_obj;
7483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  TickSample* sample = CpuProfiler::TickSampleEvent(isolate);
7493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  if (sample == NULL) sample = &sample_obj;
7503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
7513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Extracting the sample from the context is extremely machine dependent.
75285b71799222b55eb5dd74ea26efe0c64ab655c8cBen Murdoch  sample->state = isolate->current_vm_state();
7533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
7543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#ifdef __NetBSD__
7553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  mcontext_t& mcontext = ucontext->uc_mcontext;
7563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#if V8_HOST_ARCH_IA32
7573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  sample->pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_EIP]);
7583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  sample->sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_ESP]);
7593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  sample->fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_EBP]);
7603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#elif V8_HOST_ARCH_X64
7613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  sample->pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_RIP]);
7623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  sample->sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RSP]);
7633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  sample->fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RBP]);
7643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#endif  // V8_HOST_ARCH
7653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#else  // OpenBSD
7663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch#if V8_HOST_ARCH_IA32
7673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  sample->pc = reinterpret_cast<Address>(ucontext->sc_eip);
7683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  sample->sp = reinterpret_cast<Address>(ucontext->sc_esp);
7693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  sample->fp = reinterpret_cast<Address>(ucontext->sc_ebp);
7703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch#elif V8_HOST_ARCH_X64
7713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  sample->pc = reinterpret_cast<Address>(ucontext->sc_rip);
7723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  sample->sp = reinterpret_cast<Address>(ucontext->sc_rsp);
7733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  sample->fp = reinterpret_cast<Address>(ucontext->sc_rbp);
7743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#endif  // V8_HOST_ARCH
7753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#endif  // __NetBSD__
7763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  sampler->SampleStack(sample);
7773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  sampler->Tick(sample);
778d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
779d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
780d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
7813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochclass Sampler::PlatformData : public Malloced {
7823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch public:
7833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  PlatformData() : vm_tid_(GetThreadID()) {}
7843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
7853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  pthread_t vm_tid() const { return vm_tid_; }
7863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
7873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch private:
7883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  pthread_t vm_tid_;
7893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch};
7903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
7913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
7923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochclass SignalSender : public Thread {
793d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block public:
7943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  enum SleepInterval {
7953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    HALF_INTERVAL,
7963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    FULL_INTERVAL
7973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  };
7983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
7993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  static const int kSignalSenderStackSize = 64 * KB;
8003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
8013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  explicit SignalSender(int interval)
8023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      : Thread(Thread::Options("SignalSender", kSignalSenderStackSize)),
8033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        vm_tgid_(getpid()),
8043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        interval_(interval) {}
8053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
8063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  static void InstallSignalHandler() {
8073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    struct sigaction sa;
8083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    sa.sa_sigaction = ProfilerSignalHandler;
8093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    sigemptyset(&sa.sa_mask);
8103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    sa.sa_flags = SA_RESTART | SA_SIGINFO;
8113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    signal_handler_installed_ =
8123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
8133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
8143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
8153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  static void RestoreSignalHandler() {
8163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    if (signal_handler_installed_) {
8173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      sigaction(SIGPROF, &old_signal_handler_, 0);
8183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      signal_handler_installed_ = false;
8193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
8203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
8213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
8223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  static void AddActiveSampler(Sampler* sampler) {
8233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ScopedLock lock(mutex_.Pointer());
8243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    SamplerRegistry::AddActiveSampler(sampler);
8253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    if (instance_ == NULL) {
8263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Start a thread that will send SIGPROF signal to VM threads,
8273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // when CPU profiling will be enabled.
8283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      instance_ = new SignalSender(sampler->interval());
8293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      instance_->Start();
8303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    } else {
8313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      ASSERT(instance_->interval_ == sampler->interval());
8323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    }
8333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
8343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
8353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  static void RemoveActiveSampler(Sampler* sampler) {
8363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ScopedLock lock(mutex_.Pointer());
8373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    SamplerRegistry::RemoveActiveSampler(sampler);
8383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
8393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
8403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      delete instance_;
8413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      instance_ = NULL;
8423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      RestoreSignalHandler();
8433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    }
8443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
8453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
8463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Implement Thread::Run().
8473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  virtual void Run() {
8483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    SamplerRegistry::State state;
8493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    while ((state = SamplerRegistry::GetState()) !=
8503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch           SamplerRegistry::HAS_NO_SAMPLERS) {
8513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      bool cpu_profiling_enabled =
8523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch          (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS);
8533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled();
8543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      if (cpu_profiling_enabled && !signal_handler_installed_) {
8553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        InstallSignalHandler();
8563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      } else if (!cpu_profiling_enabled && signal_handler_installed_) {
8573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        RestoreSignalHandler();
8583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      }
8593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      // When CPU profiling is enabled both JavaScript and C++ code is
8603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      // profiled. We must not suspend.
8613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      if (!cpu_profiling_enabled) {
8623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        if (rate_limiter_.SuspendIfNecessary()) continue;
8633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      }
8643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      if (cpu_profiling_enabled && runtime_profiler_enabled) {
8653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) {
8663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch          return;
8673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        }
8683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        Sleep(HALF_INTERVAL);
8693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) {
8703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch          return;
8713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        }
8723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        Sleep(HALF_INTERVAL);
8733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      } else {
8743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        if (cpu_profiling_enabled) {
8753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch          if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile,
8763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                                                      this)) {
8773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            return;
8783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch          }
8793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        }
8803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        if (runtime_profiler_enabled) {
8813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch          if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile,
8823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                                                      NULL)) {
8833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch            return;
8843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch          }
8853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        }
8863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        Sleep(FULL_INTERVAL);
8873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      }
8883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    }
8893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
8903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
8913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  static void DoCpuProfile(Sampler* sampler, void* raw_sender) {
8923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    if (!sampler->IsProfiling()) return;
8933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender);
8943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    sender->SendProfilingSignal(sampler->platform_data()->vm_tid());
8953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
8963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
8973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  static void DoRuntimeProfile(Sampler* sampler, void* ignored) {
8983fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    if (!sampler->isolate()->IsInitialized()) return;
8993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    sampler->isolate()->runtime_profiler()->NotifyTick();
9003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
9013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
9023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  void SendProfilingSignal(pthread_t tid) {
9033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    if (!signal_handler_installed_) return;
9043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    pthread_kill(tid, SIGPROF);
9053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  }
9063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
9073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  void Sleep(SleepInterval full_or_half) {
9083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    // Convert ms to us and subtract 100 us to compensate delays
9093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    // occuring during signal delivery.
9103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    useconds_t interval = interval_ * 1000 - 100;
9113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    if (full_or_half == HALF_INTERVAL) interval /= 2;
9123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    int result = usleep(interval);
9133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch#ifdef DEBUG
9143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    if (result != 0 && errno != EINTR) {
9153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      fprintf(stderr,
9163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              "SignalSender usleep error; interval = %u, errno = %d\n",
9173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              interval,
9183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch              errno);
9193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      ASSERT(result == 0 || errno == EINTR);
9203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    }
9213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch#endif
9223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    USE(result);
923d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
924d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
9253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  const int vm_tgid_;
9263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  const int interval_;
9273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  RuntimeProfilerRateLimiter rate_limiter_;
9283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
9293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Protects the process wide state below.
9303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  static LazyMutex mutex_;
9313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  static SignalSender* instance_;
9323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  static bool signal_handler_installed_;
9333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  static struct sigaction old_signal_handler_;
9343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
9353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch private:
9363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  DISALLOW_COPY_AND_ASSIGN(SignalSender);
937d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block};
938d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
9393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
9403ef787dbeca8a5fb1086949cda830dccee07bfbdBen MurdochLazyMutex SignalSender::mutex_ = LAZY_MUTEX_INITIALIZER;
9413fb3ca8c7ca439d408449a395897395c0faae8d1Ben MurdochSignalSender* SignalSender::instance_ = NULL;
9423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochstruct sigaction SignalSender::old_signal_handler_;
9433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdochbool SignalSender::signal_handler_installed_ = false;
9443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
945d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
94644f0eee88ff00398ff7f715fab053374d808c90dSteve BlockSampler::Sampler(Isolate* isolate, int interval)
94744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    : isolate_(isolate),
94844f0eee88ff00398ff7f715fab053374d808c90dSteve Block      interval_(interval),
949b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      profiling_(false),
9508a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      active_(false),
9518a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      samples_taken_(0) {
9523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  data_ = new PlatformData;
953d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
954d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
955d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
956d0582a6c46733687d045e4188a1bcd0123c758a1Steve BlockSampler::~Sampler() {
9573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  ASSERT(!IsActive());
958d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  delete data_;
959d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
960d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
961d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
962d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid Sampler::Start() {
9633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  ASSERT(!IsActive());
9643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  SetActive(true);
9653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  SignalSender::AddActiveSampler(this);
966d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
967d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
968d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
969d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid Sampler::Stop() {
9703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  ASSERT(IsActive());
9713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  SignalSender::RemoveActiveSampler(this);
9723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  SetActive(false);
973d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
974d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
975d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
976d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block} }  // namespace v8::internal
977