1d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// Copyright 2006-2009 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
28d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// Platform specific code for OpenBSD goes here. For the POSIX comaptible parts
29d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// 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>
36d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include <sys/types.h>
37d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include <stdlib.h>
38d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
39d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include <sys/types.h>  // mmap & munmap
40d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include <sys/mman.h>   // mmap & munmap
41d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include <sys/stat.h>   // open
42d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include <sys/fcntl.h>  // open
43d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include <unistd.h>     // getpagesize
44d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include <execinfo.h>   // backtrace, backtrace_symbols
45d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include <strings.h>    // index
46d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include <errno.h>
47d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include <stdarg.h>
48d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include <limits.h>
49d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
50d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#undef MAP_TYPE
51d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
52d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include "v8.h"
53d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
54d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include "platform.h"
55b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch#include "vm-state-inl.h"
56d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
57d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
58d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blocknamespace v8 {
59d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blocknamespace internal {
60d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
61d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// 0 is never a valid thread id on OpenBSD since tids and pids share a
62d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// name space and pid 0 is used to kill the group (see man 2 kill).
63d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockstatic const pthread_t kNoThread = (pthread_t) 0;
64d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
65d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
66d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockdouble ceiling(double x) {
67d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    // Correct as on OS X
68d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    if (-1.0 < x && x < 0.0) {
69d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        return -0.0;
70d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    } else {
71d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        return ceil(x);
72d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    }
73d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
74d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
75d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
76d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid OS::Setup() {
77d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Seed the random number generator.
78d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Convert the current time to a 64-bit integer first, before converting it
79d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // to an unsigned. Going directly can cause an overflow and the seed to be
80d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // set to all ones. The seed will be identical for different instances that
81d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // call this setup code within the same millisecond.
82d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
83d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  srandom(static_cast<unsigned int>(seed));
84d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
85d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
86d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
873bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdochvoid OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) {
883bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  __asm__ __volatile__("" : : : "memory");
893bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  *ptr = value;
903bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch}
913bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
923bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
93d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockuint64_t OS::CpuFeaturesImpliedByPlatform() {
94d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return 0;  // OpenBSD runs on anything.
95d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
96d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
97d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
98d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockint OS::ActivationFrameAlignment() {
99d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // 16 byte alignment on OpenBSD
100d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return 16;
101d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
102d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
103d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
104d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarkeconst char* OS::LocalTimezone(double time) {
105d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  if (isnan(time)) return "";
106d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  time_t tv = static_cast<time_t>(floor(time/msPerSecond));
107d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  struct tm* t = localtime(&tv);
108d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  if (NULL == t) return "";
109d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  return t->tm_zone;
110d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke}
111d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
112d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
113d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarkedouble OS::LocalTimeOffset() {
114d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  time_t tv = time(NULL);
115d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  struct tm* t = localtime(&tv);
116d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // tm_gmtoff includes any daylight savings offset, so subtract it.
117d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  return static_cast<double>(t->tm_gmtoff * msPerSecond -
118d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke                             (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
119d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke}
120d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
121d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
122d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// We keep the lowest and highest addresses mapped as a quick way of
123d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// determining that pointers are outside the heap (used mostly in assertions
124d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// and verification).  The estimate is conservative, ie, not all addresses in
125d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// 'allocated' space are actually allocated to our heap.  The range is
126d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// [lowest, highest), inclusive on the low and and exclusive on the high end.
127d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockstatic void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
128d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockstatic void* highest_ever_allocated = reinterpret_cast<void*>(0);
129d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
130d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
131d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockstatic void UpdateAllocatedSpaceLimits(void* address, int size) {
132d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  lowest_ever_allocated = Min(lowest_ever_allocated, address);
133d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  highest_ever_allocated =
134d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      Max(highest_ever_allocated,
135d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block          reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
136d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
137d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
138d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
139d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockbool OS::IsOutsideAllocatedSpace(void* address) {
140d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return address < lowest_ever_allocated || address >= highest_ever_allocated;
141d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
142d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
143d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
144d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blocksize_t OS::AllocateAlignment() {
145d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return getpagesize();
146d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
147d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
148d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
149d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid* OS::Allocate(const size_t requested,
150d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                   size_t* allocated,
151d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                   bool executable) {
152d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  const size_t msize = RoundUp(requested, getpagesize());
153d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
154d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
155d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
156d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (mbase == MAP_FAILED) {
15744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    LOG(ISOLATE, StringEvent("OS::Allocate", "mmap failed"));
158d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    return NULL;
159d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
160d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  *allocated = msize;
161d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  UpdateAllocatedSpaceLimits(mbase, msize);
162d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return mbase;
163d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
164d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
165d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
166d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid OS::Free(void* buf, const size_t length) {
167d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  int result = munmap(buf, length);
168d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  USE(result);
169d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  ASSERT(result == 0);
170d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
171d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
172d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
173d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#ifdef ENABLE_HEAP_PROTECTION
174d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
175d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid OS::Protect(void* address, size_t size) {
176d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  UNIMPLEMENTED();
177d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
178d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
179d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
180d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid OS::Unprotect(void* address, size_t size, bool is_executable) {
181d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  UNIMPLEMENTED();
182d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
183d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
184d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#endif
185d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
186d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
187d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid OS::Sleep(int milliseconds) {
188d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  unsigned int ms = static_cast<unsigned int>(milliseconds);
189d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  usleep(1000 * ms);
190d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
191d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
192d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
193d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid OS::Abort() {
194d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Redirect to std abort to signal abnormal program termination.
195d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  abort();
196d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
197d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
198d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
199d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid OS::DebugBreak() {
200756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick#if (defined(__arm__) || defined(__thumb__))
201756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick# if defined(CAN_USE_ARMV5_INSTRUCTIONS)
202d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  asm("bkpt 0");
203756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick# endif
204d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#else
205d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  asm("int $3");
206d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#endif
207d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
208d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
209d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
210d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockclass PosixMemoryMappedFile : public OS::MemoryMappedFile {
211d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block public:
212d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  PosixMemoryMappedFile(FILE* file, void* memory, int size)
213d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    : file_(file), memory_(memory), size_(size) { }
214d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  virtual ~PosixMemoryMappedFile();
215d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  virtual void* memory() { return memory_; }
2161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  virtual int size() { return size_; }
217d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block private:
218d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  FILE* file_;
219d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  void* memory_;
220d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  int size_;
221d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block};
222d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
223d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
2241e0659c275bb392c045087af4f6b0d7565cb3d77Steve BlockOS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
225e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  FILE* file = fopen(name, "r+");
2261e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  if (file == NULL) return NULL;
2271e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2281e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  fseek(file, 0, SEEK_END);
2291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  int size = ftell(file);
2301e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  void* memory =
2321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block      mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
2331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  return new PosixMemoryMappedFile(file, memory, size);
2341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block}
2351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
237d0582a6c46733687d045e4188a1bcd0123c758a1Steve BlockOS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
238d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    void* initial) {
239d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  FILE* file = fopen(name, "w+");
240d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (file == NULL) return NULL;
241d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  int result = fwrite(initial, size, 1, file);
242d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (result < 1) {
243d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    fclose(file);
244d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    return NULL;
245d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
246d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  void* memory =
247d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
248d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return new PosixMemoryMappedFile(file, memory, size);
249d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
250d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
251d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
252d0582a6c46733687d045e4188a1bcd0123c758a1Steve BlockPosixMemoryMappedFile::~PosixMemoryMappedFile() {
253d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (memory_) munmap(memory_, size_);
254d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  fclose(file_);
255d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
256d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
257d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
258d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#ifdef ENABLE_LOGGING_AND_PROFILING
259d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockstatic unsigned StringToLong(char* buffer) {
260d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return static_cast<unsigned>(strtol(buffer, NULL, 16));  // NOLINT
261d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
262d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#endif
263d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
264d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
265d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid OS::LogSharedLibraryAddresses() {
266d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#ifdef ENABLE_LOGGING_AND_PROFILING
267d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  static const int MAP_LENGTH = 1024;
268d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  int fd = open("/proc/self/maps", O_RDONLY);
269d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (fd < 0) return;
270d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  while (true) {
271d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    char addr_buffer[11];
272d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    addr_buffer[0] = '0';
273d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    addr_buffer[1] = 'x';
274d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    addr_buffer[10] = 0;
275d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    int result = read(fd, addr_buffer + 2, 8);
276d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    if (result < 8) break;
277d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    unsigned start = StringToLong(addr_buffer);
278d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    result = read(fd, addr_buffer + 2, 1);
279d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    if (result < 1) break;
280d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    if (addr_buffer[2] != '-') break;
281d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    result = read(fd, addr_buffer + 2, 8);
282d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    if (result < 8) break;
283d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    unsigned end = StringToLong(addr_buffer);
284d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    char buffer[MAP_LENGTH];
285d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    int bytes_read = -1;
286d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    do {
287d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      bytes_read++;
288d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      if (bytes_read >= MAP_LENGTH - 1)
289d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block        break;
290d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      result = read(fd, buffer + bytes_read, 1);
291d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      if (result < 1) break;
292d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    } while (buffer[bytes_read] != '\n');
293d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    buffer[bytes_read] = 0;
294d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    // Ignore mappings that are not executable.
295d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    if (buffer[3] != 'x') continue;
296d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    char* start_of_path = index(buffer, '/');
297d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    // There may be no filename in this line.  Skip to next.
298d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    if (start_of_path == NULL) continue;
299d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    buffer[bytes_read] = 0;
300d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    LOG(SharedLibraryEvent(start_of_path, start, end));
301d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
302d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  close(fd);
303d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#endif
304d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
305d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
306d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
307f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochvoid OS::SignalCodeMovingGC() {
308f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch}
309f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
310f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
311d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockint OS::StackWalk(Vector<OS::StackFrame> frames) {
312d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  UNIMPLEMENTED();
313d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return 1;
314d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
315d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
316d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
317d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block// Constants used for mmap.
318d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockstatic const int kMmapFd = -1;
319d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockstatic const int kMmapFdOffset = 0;
320d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
321d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
322d0582a6c46733687d045e4188a1bcd0123c758a1Steve BlockVirtualMemory::VirtualMemory(size_t size) {
323d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  address_ = mmap(NULL, size, PROT_NONE,
324d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                  MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
325d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                  kMmapFd, kMmapFdOffset);
326d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  size_ = size;
327d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
328d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
329d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
330d0582a6c46733687d045e4188a1bcd0123c758a1Steve BlockVirtualMemory::~VirtualMemory() {
331d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (IsReserved()) {
332d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    if (0 == munmap(address(), size())) address_ = MAP_FAILED;
333d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
334d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
335d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
336d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
337d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockbool VirtualMemory::IsReserved() {
338d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return address_ != MAP_FAILED;
339d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
340d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
341d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
342d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockbool VirtualMemory::Commit(void* address, size_t size, bool executable) {
343d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
344d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (MAP_FAILED == mmap(address, size, prot,
345d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                         MAP_PRIVATE | MAP_ANON | MAP_FIXED,
346d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block                         kMmapFd, kMmapFdOffset)) {
347d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    return false;
348d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
349d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
350d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  UpdateAllocatedSpaceLimits(address, size);
351d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return true;
352d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
353d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
354d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
355d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockbool VirtualMemory::Uncommit(void* address, size_t size) {
356d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return mmap(address, size, PROT_NONE,
357d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block              MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
358d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block              kMmapFd, kMmapFdOffset) != MAP_FAILED;
359d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
360d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
361d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
3628b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdochclass Thread::PlatformData : public Malloced {
363d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block public:
3648b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  PlatformData() : thread_(kNoThread) {}
365d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
366d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  pthread_t thread_;  // Thread handle for pthread.
367d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block};
368d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
369d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
37044f0eee88ff00398ff7f715fab053374d808c90dSteve BlockThread::Thread(Isolate* isolate, const Options& options)
3718b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    : data_(new PlatformData()),
37244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      isolate_(isolate),
37344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      stack_size_(options.stack_size) {
37444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  set_name(options.name);
3759fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block}
3769fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
3779fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
37844f0eee88ff00398ff7f715fab053374d808c90dSteve BlockThread::Thread(Isolate* isolate, const char* name)
3798b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    : data_(new PlatfromData()),
38044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      isolate_(isolate),
38144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      stack_size_(0) {
3829fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  set_name(name);
383d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
384d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
385d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
386d0582a6c46733687d045e4188a1bcd0123c758a1Steve BlockThread::~Thread() {
3878b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  delete data_;
388d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
389d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
390d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
391d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockstatic void* ThreadEntry(void* arg) {
392d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  Thread* thread = reinterpret_cast<Thread*>(arg);
393d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // This is also initialized by the first argument to pthread_create() but we
394d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // don't know which thread will run first (the original thread or the new
395d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // one) so we initialize it here too.
3968b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  thread->data()->thread_ = pthread_self();
3978b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  ASSERT(thread->data()->thread_ != kNoThread);
39844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Thread::SetThreadLocal(Isolate::isolate_key(), thread->isolate());
399d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  thread->Run();
400d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return NULL;
401d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
402d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
403d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
4049fac840a46e8b7e26894f4792ba26dde14c56b04Steve Blockvoid Thread::set_name(const char* name) {
4059fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  strncpy(name_, name, sizeof(name_));
4069fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block  name_[sizeof(name_) - 1] = '\0';
4079fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block}
4089fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
4099fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
410d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid Thread::Start() {
41144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  pthread_attr_t* attr_ptr = NULL;
41244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  pthread_attr_t attr;
41344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (stack_size_ > 0) {
41444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    pthread_attr_init(&attr);
41544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
41644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    attr_ptr = &attr;
41744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
4188b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  pthread_create(&data_->thread_, attr_ptr, ThreadEntry, this);
419d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  ASSERT(IsValid());
420d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
421d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
422d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
423d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid Thread::Join() {
4248b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  pthread_join(data_->thread_, NULL);
425d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
426d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
427d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
428d0582a6c46733687d045e4188a1bcd0123c758a1Steve BlockThread::LocalStorageKey Thread::CreateThreadLocalKey() {
429d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  pthread_key_t key;
430d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  int result = pthread_key_create(&key, NULL);
431d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  USE(result);
432d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  ASSERT(result == 0);
433d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return static_cast<LocalStorageKey>(key);
434d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
435d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
436d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
437d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid Thread::DeleteThreadLocalKey(LocalStorageKey key) {
438d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
439d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  int result = pthread_key_delete(pthread_key);
440d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  USE(result);
441d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  ASSERT(result == 0);
442d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
443d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
444d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
445d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid* Thread::GetThreadLocal(LocalStorageKey key) {
446d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
447d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return pthread_getspecific(pthread_key);
448d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
449d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
450d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
451d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid Thread::SetThreadLocal(LocalStorageKey key, void* value) {
452d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
453d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  pthread_setspecific(pthread_key, value);
454d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
455d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
456d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
457d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid Thread::YieldCPU() {
458d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  sched_yield();
459d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
460d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
461d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
462d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockclass OpenBSDMutex : public Mutex {
463d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block public:
464d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
465d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  OpenBSDMutex() {
466d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    pthread_mutexattr_t attrs;
467d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    int result = pthread_mutexattr_init(&attrs);
468d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    ASSERT(result == 0);
469d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
470d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    ASSERT(result == 0);
471d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    result = pthread_mutex_init(&mutex_, &attrs);
472d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    ASSERT(result == 0);
473d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
474d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
475d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  virtual ~OpenBSDMutex() { pthread_mutex_destroy(&mutex_); }
476d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
477d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  virtual int Lock() {
478d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    int result = pthread_mutex_lock(&mutex_);
479d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    return result;
480d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
481d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
482d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  virtual int Unlock() {
483d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    int result = pthread_mutex_unlock(&mutex_);
484d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    return result;
485d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
486d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
487d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block private:
488d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  pthread_mutex_t mutex_;   // Pthread mutex for POSIX platforms.
489d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block};
490d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
491d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
492d0582a6c46733687d045e4188a1bcd0123c758a1Steve BlockMutex* OS::CreateMutex() {
493d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return new OpenBSDMutex();
494d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
495d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
496d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
497d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockclass OpenBSDSemaphore : public Semaphore {
498d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block public:
499d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  explicit OpenBSDSemaphore(int count) {  sem_init(&sem_, 0, count); }
500d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  virtual ~OpenBSDSemaphore() { sem_destroy(&sem_); }
501d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
502d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  virtual void Wait();
503d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  virtual bool Wait(int timeout);
504d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  virtual void Signal() { sem_post(&sem_); }
505d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block private:
506d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  sem_t sem_;
507d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block};
508d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
509d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
510d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid OpenBSDSemaphore::Wait() {
511d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  while (true) {
512d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    int result = sem_wait(&sem_);
513d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    if (result == 0) return;  // Successfully got semaphore.
514d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
515d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
516d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
517d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
518d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
519d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockbool OpenBSDSemaphore::Wait(int timeout) {
520d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  const long kOneSecondMicros = 1000000;  // NOLINT
521d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
522d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Split timeout into second and nanosecond parts.
523d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  struct timeval delta;
524d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  delta.tv_usec = timeout % kOneSecondMicros;
525d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  delta.tv_sec = timeout / kOneSecondMicros;
526d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
527d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  struct timeval current_time;
528d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Get the current time.
529d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (gettimeofday(&current_time, NULL) == -1) {
530d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    return false;
531d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
532d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
533d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Calculate time for end of timeout.
534d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  struct timeval end_time;
535d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  timeradd(&current_time, &delta, &end_time);
536d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
537d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  struct timespec ts;
538d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  TIMEVAL_TO_TIMESPEC(&end_time, &ts);
539d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  while (true) {
540d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    int result = sem_trywait(&sem_);
541d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    if (result == 0) return true;  // Successfully got semaphore.
542d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    if (result == -1 && errno == ETIMEDOUT) return false;  // Timeout.
543d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
544d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
545d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
546d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
547d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
548d0582a6c46733687d045e4188a1bcd0123c758a1Steve BlockSemaphore* OS::CreateSemaphore(int count) {
549d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return new OpenBSDSemaphore(count);
550d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
551d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
552d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
553d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#ifdef ENABLE_LOGGING_AND_PROFILING
554d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
555d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockstatic Sampler* active_sampler_ = NULL;
556d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
557d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockstatic void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
558d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  USE(info);
559d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (signal != SIGPROF) return;
560d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (active_sampler_ == NULL) return;
561d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
562d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  TickSample sample;
563d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
564d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // We always sample the VM state.
5656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  sample.state = VMState::current_state();
566d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
567d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  active_sampler_->Tick(&sample);
568d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
569d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
570d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
571d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockclass Sampler::PlatformData : public Malloced {
572d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block public:
573d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  PlatformData() {
574d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    signal_handler_installed_ = false;
575d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
576d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
577d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  bool signal_handler_installed_;
578d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  struct sigaction old_signal_handler_;
579d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  struct itimerval old_timer_value_;
580d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block};
581d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
582d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
58344f0eee88ff00398ff7f715fab053374d808c90dSteve BlockSampler::Sampler(Isolate* isolate, int interval)
58444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    : isolate_(isolate),
58544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      interval_(interval),
586b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      profiling_(false),
5878a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      active_(false),
5888a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      samples_taken_(0) {
589d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  data_ = new PlatformData();
590d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
591d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
592d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
593d0582a6c46733687d045e4188a1bcd0123c758a1Steve BlockSampler::~Sampler() {
594d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  delete data_;
595d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
596d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
597d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
598d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid Sampler::Start() {
599d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // There can only be one active sampler at the time on POSIX
600d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // platforms.
601d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (active_sampler_ != NULL) return;
602d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
603d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Request profiling signals.
604d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  struct sigaction sa;
605d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  sa.sa_sigaction = ProfilerSignalHandler;
606d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  sigemptyset(&sa.sa_mask);
607d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  sa.sa_flags = SA_SIGINFO;
608d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return;
609d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  data_->signal_handler_installed_ = true;
610d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
611d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Set the itimer to generate a tick for each interval.
612d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  itimerval itimer;
613d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  itimer.it_interval.tv_sec = interval_ / 1000;
614d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  itimer.it_interval.tv_usec = (interval_ % 1000) * 1000;
615d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  itimer.it_value.tv_sec = itimer.it_interval.tv_sec;
616d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  itimer.it_value.tv_usec = itimer.it_interval.tv_usec;
617d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_);
618d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
619d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Set this sampler as the active sampler.
620d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  active_sampler_ = this;
621d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  active_ = true;
622d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
623d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
624d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
625d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockvoid Sampler::Stop() {
626d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Restore old signal handler
627d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if (data_->signal_handler_installed_) {
628d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL);
629d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    sigaction(SIGPROF, &data_->old_signal_handler_, 0);
630d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    data_->signal_handler_installed_ = false;
631d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  }
632d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
633d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // This sampler is no longer the active sampler.
634d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  active_sampler_ = NULL;
635d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  active_ = false;
636d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block}
637d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
638d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#endif  // ENABLE_LOGGING_AND_PROFILING
639d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
640d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block} }  // namespace v8::internal
641