platform-freebsd.cc revision d0582a6c46733687d045e4188a1bcd0123c758a1
1a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Copyright 2006-2008 the V8 project authors. All rights reserved.
2a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Redistribution and use in source and binary forms, with or without
3a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// modification, are permitted provided that the following conditions are
4a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// met:
5a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//
6a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//     * Redistributions of source code must retain the above copyright
7a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       notice, this list of conditions and the following disclaimer.
8a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//     * Redistributions in binary form must reproduce the above
9a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       copyright notice, this list of conditions and the following
10a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       disclaimer in the documentation and/or other materials provided
11a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       with the distribution.
12a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//     * Neither the name of Google Inc. nor the names of its
13a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       contributors may be used to endorse or promote products derived
14a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       from this software without specific prior written permission.
15a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//
16a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
28a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Platform specific code for FreeBSD goes here. For the POSIX comaptible parts
29a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// the implementation is in platform-posix.cc.
30a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
31a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <pthread.h>
32a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <semaphore.h>
33a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <signal.h>
34a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <sys/time.h>
35a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <sys/resource.h>
36a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <sys/types.h>
37a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <sys/ucontext.h>
38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <stdlib.h>
39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <sys/types.h>  // mmap & munmap
41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <sys/mman.h>   // mmap & munmap
42a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <sys/stat.h>   // open
43a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <sys/fcntl.h>  // open
44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <unistd.h>     // getpagesize
45a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <execinfo.h>   // backtrace, backtrace_symbols
46a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <strings.h>    // index
47a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <errno.h>
48a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <stdarg.h>
49a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <limits.h>
50a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
51a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#undef MAP_TYPE
52a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
53a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "v8.h"
54a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
55a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "platform.h"
56a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
57a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
58a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace v8 {
59a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace internal {
60a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 0 is never a valid thread id on FreeBSD since tids and pids share a
62a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// name space and pid 0 is used to kill the group (see man 2 kill).
63a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic const pthread_t kNoThread = (pthread_t) 0;
64a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
65a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdouble ceiling(double x) {
67a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Correct as on OS X
68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (-1.0 < x && x < 0.0) {
69a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        return -0.0;
70a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
71a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        return ceil(x);
72a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
75a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
76a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::Setup() {
77a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Seed the random number generator.
78a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Convert the current time to a 64-bit integer first, before converting it
79a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // to an unsigned. Going directly can cause an overflow and the seed to be
80a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // set to all ones. The seed will be identical for different instances that
81a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // call this setup code within the same millisecond.
82a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
83a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  srandom(static_cast<unsigned int>(seed));
84a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
85a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
86a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
87d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockuint64_t OS::CpuFeaturesImpliedByPlatform() {
88d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  return 0;  // FreeBSD runs on anything.
89a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
90a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
91a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
92a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockint OS::ActivationFrameAlignment() {
93a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // 16 byte alignment on FreeBSD
94a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return 16;
95a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
96a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
97a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
98a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// We keep the lowest and highest addresses mapped as a quick way of
99a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// determining that pointers are outside the heap (used mostly in assertions
100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// and verification).  The estimate is conservative, ie, not all addresses in
101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 'allocated' space are actually allocated to our heap.  The range is
102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// [lowest, highest), inclusive on the low and and exclusive on the high end.
103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void* highest_ever_allocated = reinterpret_cast<void*>(0);
105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void UpdateAllocatedSpaceLimits(void* address, int size) {
108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  lowest_ever_allocated = Min(lowest_ever_allocated, address);
109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  highest_ever_allocated =
110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Max(highest_ever_allocated,
111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool OS::IsOutsideAllocatedSpace(void* address) {
116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return address < lowest_ever_allocated || address >= highest_ever_allocated;
117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocksize_t OS::AllocateAlignment() {
121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return getpagesize();
122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid* OS::Allocate(const size_t requested,
126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                   size_t* allocated,
127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                   bool executable) {
128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const size_t msize = RoundUp(requested, getpagesize());
129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (mbase == MAP_FAILED) {
133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    LOG(StringEvent("OS::Allocate", "mmap failed"));
134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return NULL;
135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  *allocated = msize;
137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  UpdateAllocatedSpaceLimits(mbase, msize);
138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return mbase;
139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::Free(void* buf, const size_t length) {
143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // TODO(1240712): munmap has a return value which is ignored here.
144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int result = munmap(buf, length);
145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  USE(result);
146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(result == 0);
147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_HEAP_PROTECTION
151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::Protect(void* address, size_t size) {
153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  UNIMPLEMENTED();
154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::Unprotect(void* address, size_t size, bool is_executable) {
158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  UNIMPLEMENTED();
159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::Sleep(int milliseconds) {
165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  unsigned int ms = static_cast<unsigned int>(milliseconds);
166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  usleep(1000 * ms);
167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::Abort() {
171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Redirect to std abort to signal abnormal program termination.
172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  abort();
173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::DebugBreak() {
177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#if defined(__arm__) || defined(__thumb__)
178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  asm("bkpt 0");
179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#else
180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  asm("int $3");
181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass PosixMemoryMappedFile : public OS::MemoryMappedFile {
186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  PosixMemoryMappedFile(FILE* file, void* memory, int size)
188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    : file_(file), memory_(memory), size_(size) { }
189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual ~PosixMemoryMappedFile();
190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual void* memory() { return memory_; }
191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  FILE* file_;
193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void* memory_;
194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int size_;
195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockOS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    void* initial) {
200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  FILE* file = fopen(name, "w+");
201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (file == NULL) return NULL;
202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int result = fwrite(initial, size, 1, file);
203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (result < 1) {
204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    fclose(file);
205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return NULL;
206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void* memory =
208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return new PosixMemoryMappedFile(file, memory, size);
210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockPosixMemoryMappedFile::~PosixMemoryMappedFile() {
214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (memory_) munmap(memory_, size_);
215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  fclose(file_);
216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_LOGGING_AND_PROFILING
220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic unsigned StringToLong(char* buffer) {
221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return static_cast<unsigned>(strtol(buffer, NULL, 16));  // NOLINT
222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid OS::LogSharedLibraryAddresses() {
227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_LOGGING_AND_PROFILING
228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static const int MAP_LENGTH = 1024;
229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int fd = open("/proc/self/maps", O_RDONLY);
230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (fd < 0) return;
231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  while (true) {
232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    char addr_buffer[11];
233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    addr_buffer[0] = '0';
234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    addr_buffer[1] = 'x';
235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    addr_buffer[10] = 0;
236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int result = read(fd, addr_buffer + 2, 8);
237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (result < 8) break;
238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    unsigned start = StringToLong(addr_buffer);
239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    result = read(fd, addr_buffer + 2, 1);
240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (result < 1) break;
241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (addr_buffer[2] != '-') break;
242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    result = read(fd, addr_buffer + 2, 8);
243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (result < 8) break;
244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    unsigned end = StringToLong(addr_buffer);
245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    char buffer[MAP_LENGTH];
246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int bytes_read = -1;
247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    do {
248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      bytes_read++;
249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (bytes_read >= MAP_LENGTH - 1)
250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        break;
251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      result = read(fd, buffer + bytes_read, 1);
252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (result < 1) break;
253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } while (buffer[bytes_read] != '\n');
254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    buffer[bytes_read] = 0;
255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Ignore mappings that are not executable.
256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (buffer[3] != 'x') continue;
257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    char* start_of_path = index(buffer, '/');
258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // There may be no filename in this line.  Skip to next.
259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (start_of_path == NULL) continue;
260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    buffer[bytes_read] = 0;
261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    LOG(SharedLibraryEvent(start_of_path, start, end));
262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  close(fd);
264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockint OS::StackWalk(Vector<OS::StackFrame> frames) {
269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int frames_size = frames.length();
270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void** addresses = NewArray<void*>(frames_size);
271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int frames_count = backtrace(addresses, frames_size);
273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  char** symbols;
275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  symbols = backtrace_symbols(addresses, frames_count);
276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (symbols == NULL) {
277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    DeleteArray(addresses);
278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return kStackWalkError;
279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < frames_count; i++) {
282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frames[i].address = addresses[i];
283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Format a text representation of the frame based on the information
284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // available.
285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    SNPrintF(MutableCStrVector(frames[i].text, kStackWalkMaxTextLen),
286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block             "%s",
287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block             symbols[i]);
288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Make sure line termination is in place.
289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    frames[i].text[kStackWalkMaxTextLen - 1] = '\0';
290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  DeleteArray(addresses);
293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  free(symbols);
294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return frames_count;
296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Constants used for mmap.
300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic const int kMmapFd = -1;
301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic const int kMmapFdOffset = 0;
302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockVirtualMemory::VirtualMemory(size_t size) {
305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  address_ = mmap(NULL, size, PROT_NONE,
306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                  MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                  kMmapFd, kMmapFdOffset);
308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  size_ = size;
309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockVirtualMemory::~VirtualMemory() {
313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (IsReserved()) {
314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (0 == munmap(address(), size())) address_ = MAP_FAILED;
315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
318a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool VirtualMemory::IsReserved() {
320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return address_ != MAP_FAILED;
321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool VirtualMemory::Commit(void* address, size_t size, bool executable) {
325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (MAP_FAILED == mmap(address, size, prot,
327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                         MAP_PRIVATE | MAP_ANON | MAP_FIXED,
328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                         kMmapFd, kMmapFdOffset)) {
329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return false;
330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  UpdateAllocatedSpaceLimits(address, size);
333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return true;
334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool VirtualMemory::Uncommit(void* address, size_t size) {
338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return mmap(address, size, PROT_NONE,
339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block              MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | MAP_FIXED,
340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block              kMmapFd, kMmapFdOffset) != MAP_FAILED;
341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass ThreadHandle::PlatformData : public Malloced {
345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
346a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  explicit PlatformData(ThreadHandle::Kind kind) {
347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Initialize(kind);
348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void Initialize(ThreadHandle::Kind kind) {
351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    switch (kind) {
352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      case ThreadHandle::SELF: thread_ = pthread_self(); break;
353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      case ThreadHandle::INVALID: thread_ = kNoThread; break;
354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_t thread_;  // Thread handle for pthread.
357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockThreadHandle::ThreadHandle(Kind kind) {
361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  data_ = new PlatformData(kind);
362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid ThreadHandle::Initialize(ThreadHandle::Kind kind) {
366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  data_->Initialize(kind);
367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockThreadHandle::~ThreadHandle() {
371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  delete data_;
372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool ThreadHandle::IsSelf() const {
376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return pthread_equal(data_->thread_, pthread_self());
377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
379a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool ThreadHandle::IsValid() const {
381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return data_->thread_ != kNoThread;
382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockThread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockThread::~Thread() {
390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void* ThreadEntry(void* arg) {
394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Thread* thread = reinterpret_cast<Thread*>(arg);
395a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // This is also initialized by the first argument to pthread_create() but we
396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // don't know which thread will run first (the original thread or the new
397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // one) so we initialize it here too.
398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  thread->thread_handle_data()->thread_ = pthread_self();
399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(thread->IsValid());
400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  thread->Run();
401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return NULL;
402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Thread::Start() {
406a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(IsValid());
408a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
409a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
410a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
411a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Thread::Join() {
412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_join(thread_handle_data()->thread_, NULL);
413a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
414a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
415a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
416a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockThread::LocalStorageKey Thread::CreateThreadLocalKey() {
417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_key_t key;
418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int result = pthread_key_create(&key, NULL);
419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  USE(result);
420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(result == 0);
421a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return static_cast<LocalStorageKey>(key);
422a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Thread::DeleteThreadLocalKey(LocalStorageKey key) {
426a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
427a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int result = pthread_key_delete(pthread_key);
428a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  USE(result);
429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(result == 0);
430a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
431a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
432a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid* Thread::GetThreadLocal(LocalStorageKey key) {
434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return pthread_getspecific(pthread_key);
436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
438a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Thread::SetThreadLocal(LocalStorageKey key, void* value) {
440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_setspecific(pthread_key, value);
442a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
444a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
445a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Thread::YieldCPU() {
446a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  sched_yield();
447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass FreeBSDMutex : public Mutex {
451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  FreeBSDMutex() {
454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    pthread_mutexattr_t attrs;
455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int result = pthread_mutexattr_init(&attrs);
456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(result == 0);
457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(result == 0);
459a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    result = pthread_mutex_init(&mutex_, &attrs);
460a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(result == 0);
461a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
462a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
463a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual ~FreeBSDMutex() { pthread_mutex_destroy(&mutex_); }
464a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
465a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual int Lock() {
466a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int result = pthread_mutex_lock(&mutex_);
467a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return result;
468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual int Unlock() {
471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int result = pthread_mutex_unlock(&mutex_);
472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return result;
473a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
474a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pthread_mutex_t mutex_;   // Pthread mutex for POSIX platforms.
477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
478a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
479a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
480a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockMutex* OS::CreateMutex() {
481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return new FreeBSDMutex();
482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass FreeBSDSemaphore : public Semaphore {
486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
487a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  explicit FreeBSDSemaphore(int count) {  sem_init(&sem_, 0, count); }
488a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual ~FreeBSDSemaphore() { sem_destroy(&sem_); }
489a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
490a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual void Wait();
491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual bool Wait(int timeout);
492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual void Signal() { sem_post(&sem_); }
493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
494a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  sem_t sem_;
495a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
496a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid FreeBSDSemaphore::Wait() {
499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  while (true) {
500a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int result = sem_wait(&sem_);
501a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (result == 0) return;  // Successfully got semaphore.
502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
503a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
504a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
505a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
506a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
507a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool FreeBSDSemaphore::Wait(int timeout) {
508a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const long kOneSecondMicros = 1000000;  // NOLINT
509a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
510a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Split timeout into second and nanosecond parts.
511a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  struct timeval delta;
512a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  delta.tv_usec = timeout % kOneSecondMicros;
513a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  delta.tv_sec = timeout / kOneSecondMicros;
514a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
515a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  struct timeval current_time;
516a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the current time.
517a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (gettimeofday(&current_time, NULL) == -1) {
518a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return false;
519a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Calculate time for end of timeout.
522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  struct timeval end_time;
523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  timeradd(&current_time, &delta, &end_time);
524a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
525a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  struct timespec ts;
526a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  TIMEVAL_TO_TIMESPEC(&end_time, &ts);
527a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  while (true) {
528a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int result = sem_timedwait(&sem_, &ts);
529a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (result == 0) return true;  // Successfully got semaphore.
530a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (result == -1 && errno == ETIMEDOUT) return false;  // Timeout.
531a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
532a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
533a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
534a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
535a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
536a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockSemaphore* OS::CreateSemaphore(int count) {
537a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return new FreeBSDSemaphore(count);
538a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
539a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
540a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
541a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_LOGGING_AND_PROFILING
542a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
543a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic Sampler* active_sampler_ = NULL;
544a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
545a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
546a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  USE(info);
547a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (signal != SIGPROF) return;
548a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (active_sampler_ == NULL) return;
549a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
550a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  TickSample sample;
551a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
552a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If profiling, we extract the current pc and sp.
553a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (active_sampler_->IsProfiling()) {
554a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Extracting the sample from the context is extremely machine dependent.
555a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
556a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    mcontext_t& mcontext = ucontext->uc_mcontext;
557a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#if V8_HOST_ARCH_IA32
558a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    sample.pc = mcontext.mc_eip;
559a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    sample.sp = mcontext.mc_esp;
560a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    sample.fp = mcontext.mc_ebp;
561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#elif V8_HOST_ARCH_X64
562a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    sample.pc = mcontext.mc_rip;
563a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    sample.sp = mcontext.mc_rsp;
564a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    sample.fp = mcontext.mc_rbp;
565a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#elif V8_HOST_ARCH_ARM
566a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    sample.pc = mcontext.mc_r15;
567a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    sample.sp = mcontext.mc_r13;
568a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    sample.fp = mcontext.mc_r11;
569a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
570a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    active_sampler_->SampleStack(&sample);
571a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
572a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
573a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // We always sample the VM state.
574a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  sample.state = Logger::state();
575a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
576a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  active_sampler_->Tick(&sample);
577a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
578a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
579a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
580a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass Sampler::PlatformData : public Malloced {
581a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
582a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  PlatformData() {
583a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    signal_handler_installed_ = false;
584a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
585a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
586a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  bool signal_handler_installed_;
587a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  struct sigaction old_signal_handler_;
588a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  struct itimerval old_timer_value_;
589a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
590a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
591a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
592a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockSampler::Sampler(int interval, bool profiling)
593a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    : interval_(interval), profiling_(profiling), active_(false) {
594a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  data_ = new PlatformData();
595a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
596a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
597a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
598a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockSampler::~Sampler() {
599a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  delete data_;
600a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
601a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
602a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
603a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Sampler::Start() {
604a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // There can only be one active sampler at the time on POSIX
605a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // platforms.
606a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (active_sampler_ != NULL) return;
607a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
608a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Request profiling signals.
609a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  struct sigaction sa;
610a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  sa.sa_sigaction = ProfilerSignalHandler;
611a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  sigemptyset(&sa.sa_mask);
612a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  sa.sa_flags = SA_SIGINFO;
613a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return;
614a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  data_->signal_handler_installed_ = true;
615a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
616a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Set the itimer to generate a tick for each interval.
617a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  itimerval itimer;
618a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  itimer.it_interval.tv_sec = interval_ / 1000;
619a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  itimer.it_interval.tv_usec = (interval_ % 1000) * 1000;
620a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  itimer.it_value.tv_sec = itimer.it_interval.tv_sec;
621a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  itimer.it_value.tv_usec = itimer.it_interval.tv_usec;
622a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_);
623a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
624a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Set this sampler as the active sampler.
625a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  active_sampler_ = this;
626a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  active_ = true;
627a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
628a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
629a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
630a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid Sampler::Stop() {
631a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Restore old signal handler
632a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (data_->signal_handler_installed_) {
633a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL);
634a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    sigaction(SIGPROF, &data_->old_signal_handler_, 0);
635a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    data_->signal_handler_installed_ = false;
636a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
637a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
638a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // This sampler is no longer the active sampler.
639a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  active_sampler_ = NULL;
640a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  active_ = false;
641a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
642a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
643a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif  // ENABLE_LOGGING_AND_PROFILING
644a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
645a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} }  // namespace v8::internal
646