13ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// Copyright 2012 the V8 project authors. All rights reserved.
2e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch// Redistribution and use in source and binary forms, with or without
3e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch// modification, are permitted provided that the following conditions are
4e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch// met:
5e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch//
6e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch//     * Redistributions of source code must retain the above copyright
7e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch//       notice, this list of conditions and the following disclaimer.
8e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch//     * Redistributions in binary form must reproduce the above
9e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch//       copyright notice, this list of conditions and the following
10e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch//       disclaimer in the documentation and/or other materials provided
11e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch//       with the distribution.
12e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch//     * Neither the name of Google Inc. nor the names of its
13e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch//       contributors may be used to endorse or promote products derived
14e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch//       from this software without specific prior written permission.
15e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch//
16e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
28e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch// Platform specific code for Cygwin goes here. For the POSIX comaptible parts
29e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch// the implementation is in platform-posix.cc.
30e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
31e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch#include <errno.h>
32e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch#include <pthread.h>
33e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch#include <semaphore.h>
34e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch#include <stdarg.h>
35e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch#include <strings.h>    // index
36e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch#include <sys/time.h>
37e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch#include <sys/mman.h>   // mmap & munmap
38e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch#include <unistd.h>     // sysconf
39e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
40e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch#undef MAP_TYPE
41e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
42e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch#include "v8.h"
43e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#include "platform-posix.h"
45e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch#include "platform.h"
46e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch#include "v8threads.h"
47e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch#include "vm-state-inl.h"
48e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch#include "win32-headers.h"
49e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
50e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochnamespace v8 {
51e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochnamespace internal {
52e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
53e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch// 0 is never a valid thread id
54e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochstatic const pthread_t kNoThread = (pthread_t) 0;
55e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
56e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
57e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochdouble ceiling(double x) {
58e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  return ceil(x);
59e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
60e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
61e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
628b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdochstatic Mutex* limit_mutex = NULL;
638b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch
648b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch
653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid OS::SetUp() {
66e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Seed the random number generator.
67e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Convert the current time to a 64-bit integer first, before converting it
68e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // to an unsigned. Going directly can cause an overflow and the seed to be
69e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // set to all ones. The seed will be identical for different instances that
70e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // call this setup code within the same millisecond.
71e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
72e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  srandom(static_cast<unsigned int>(seed));
738b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  limit_mutex = CreateMutex();
74e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
75e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
76e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid OS::PostSetUp() {
783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Math functions depend on CPU features therefore they are initialized after
793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // CPU.
803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  MathSetup();
813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
83e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochuint64_t OS::CpuFeaturesImpliedByPlatform() {
84e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  return 0;  // Nothing special about Cygwin.
85e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
86e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
87e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
88e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochint OS::ActivationFrameAlignment() {
89e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // With gcc 4.4 the tree vectorization optimizer can generate code
90e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // that requires 16 byte alignment such as movdqa on x86.
91e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  return 16;
92e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
93e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
94e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
95e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) {
96e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __asm__ __volatile__("" : : : "memory");
97e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // An x86 store acts as a release barrier.
98e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  *ptr = value;
99e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
100e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
101e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochconst char* OS::LocalTimezone(double time) {
102e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  if (isnan(time)) return "";
103e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  time_t tv = static_cast<time_t>(floor(time/msPerSecond));
104e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  struct tm* t = localtime(&tv);
105e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  if (NULL == t) return "";
106e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  return tzname[0];  // The location of the timezone string on Cygwin.
107e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
108e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
109e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
110e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochdouble OS::LocalTimeOffset() {
111e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // On Cygwin, struct tm does not contain a tm_gmtoff field.
112e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  time_t utc = time(NULL);
113e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  ASSERT(utc != -1);
114e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  struct tm* loc = localtime(&utc);
115e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  ASSERT(loc != NULL);
116e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // time - localtime includes any daylight savings offset, so subtract it.
117e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  return static_cast<double>((mktime(loc) - utc) * msPerSecond -
118e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                             (loc->tm_isdst > 0 ? 3600 * msPerSecond : 0));
119e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
120e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
121e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
122e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch// We keep the lowest and highest addresses mapped as a quick way of
123e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch// determining that pointers are outside the heap (used mostly in assertions
1243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// and verification).  The estimate is conservative, i.e., not all addresses in
125e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch// 'allocated' space are actually allocated to our heap.  The range is
126e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch// [lowest, highest), inclusive on the low and and exclusive on the high end.
127e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochstatic void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
128e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochstatic void* highest_ever_allocated = reinterpret_cast<void*>(0);
129e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
130e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
131e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochstatic void UpdateAllocatedSpaceLimits(void* address, int size) {
1328b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  ASSERT(limit_mutex != NULL);
1338b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  ScopedLock lock(limit_mutex);
1348b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch
135e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  lowest_ever_allocated = Min(lowest_ever_allocated, address);
136e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  highest_ever_allocated =
137e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      Max(highest_ever_allocated,
138e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch          reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
139e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
140e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
141e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
142e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochbool OS::IsOutsideAllocatedSpace(void* address) {
143e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  return address < lowest_ever_allocated || address >= highest_ever_allocated;
144e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
145e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
146e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
147e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochsize_t OS::AllocateAlignment() {
148e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  return sysconf(_SC_PAGESIZE);
149e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
150e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
151e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
152e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid* OS::Allocate(const size_t requested,
153e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                   size_t* allocated,
154e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                   bool is_executable) {
155e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  const size_t msize = RoundUp(requested, sysconf(_SC_PAGESIZE));
156e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
157e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
158e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  if (mbase == MAP_FAILED) {
15944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    LOG(ISOLATE, StringEvent("OS::Allocate", "mmap failed"));
160e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    return NULL;
161e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  }
162e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  *allocated = msize;
163e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  UpdateAllocatedSpaceLimits(mbase, msize);
164e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  return mbase;
165e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
166e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
167e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
168e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid OS::Free(void* address, const size_t size) {
169e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // TODO(1240712): munmap has a return value which is ignored here.
170e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  int result = munmap(address, size);
171e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  USE(result);
172e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  ASSERT(result == 0);
173e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
174e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
175e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
17669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdochvoid OS::ProtectCode(void* address, const size_t size) {
17769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  DWORD old_protect;
17869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  VirtualProtect(address, size, PAGE_EXECUTE_READ, &old_protect);
17969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch}
18069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
18169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
18269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdochvoid OS::Guard(void* address, const size_t size) {
18369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  DWORD oldprotect;
18469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  VirtualProtect(address, size, PAGE_READONLY | PAGE_GUARD, &oldprotect);
18569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch}
18669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
18769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
188e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid OS::Sleep(int milliseconds) {
189e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  unsigned int ms = static_cast<unsigned int>(milliseconds);
190e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  usleep(1000 * ms);
191e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
192e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
193e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
194e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid OS::Abort() {
195e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Redirect to std abort to signal abnormal program termination.
196e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  abort();
197e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
198e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
199e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
200e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid OS::DebugBreak() {
201e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  asm("int $3");
202e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
203e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
204e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
205e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochclass PosixMemoryMappedFile : public OS::MemoryMappedFile {
206e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch public:
207e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  PosixMemoryMappedFile(FILE* file, void* memory, int size)
208e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    : file_(file), memory_(memory), size_(size) { }
209e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  virtual ~PosixMemoryMappedFile();
210e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  virtual void* memory() { return memory_; }
211e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  virtual int size() { return size_; }
212e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch private:
213e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  FILE* file_;
214e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  void* memory_;
215e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  int size_;
216e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch};
217e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
218e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
219e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen MurdochOS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
220e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  FILE* file = fopen(name, "r+");
221e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  if (file == NULL) return NULL;
222e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
223e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  fseek(file, 0, SEEK_END);
224e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  int size = ftell(file);
225e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
226e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  void* memory =
227e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
228e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  return new PosixMemoryMappedFile(file, memory, size);
229e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
230e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
231e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
232e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen MurdochOS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
233e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    void* initial) {
234e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  FILE* file = fopen(name, "w+");
235e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  if (file == NULL) return NULL;
236e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  int result = fwrite(initial, size, 1, file);
237e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  if (result < 1) {
238e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    fclose(file);
239e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    return NULL;
240e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  }
241e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  void* memory =
242e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
243e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  return new PosixMemoryMappedFile(file, memory, size);
244e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
245e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
246e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
247e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen MurdochPosixMemoryMappedFile::~PosixMemoryMappedFile() {
248e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  if (memory_) munmap(memory_, size_);
249e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  fclose(file_);
250e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
251e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
252e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
253e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid OS::LogSharedLibraryAddresses() {
254e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // This function assumes that the layout of the file is as follows:
255e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // hex_start_addr-hex_end_addr rwxp <unused data> [binary_file_name]
256e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // If we encounter an unexpected situation we abort scanning further entries.
257e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  FILE* fp = fopen("/proc/self/maps", "r");
258e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  if (fp == NULL) return;
259e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
260e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Allocate enough room to be able to store a full file name.
261e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  const int kLibNameLen = FILENAME_MAX + 1;
262e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen));
263e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
2648b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  i::Isolate* isolate = ISOLATE;
265e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // This loop will terminate once the scanning hits an EOF.
266e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  while (true) {
267e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    uintptr_t start, end;
268e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    char attr_r, attr_w, attr_x, attr_p;
269e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    // Parse the addresses and permission bits at the beginning of the line.
270e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    if (fscanf(fp, "%" V8PRIxPTR "-%" V8PRIxPTR, &start, &end) != 2) break;
271e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    if (fscanf(fp, " %c%c%c%c", &attr_r, &attr_w, &attr_x, &attr_p) != 4) break;
272e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
273e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    int c;
274e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    if (attr_r == 'r' && attr_w != 'w' && attr_x == 'x') {
275e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      // Found a read-only executable entry. Skip characters until we reach
276e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      // the beginning of the filename or the end of the line.
277e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      do {
278e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch        c = getc(fp);
279e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      } while ((c != EOF) && (c != '\n') && (c != '/'));
280e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      if (c == EOF) break;  // EOF: Was unexpected, just exit.
281e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
282e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      // Process the filename if found.
283e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      if (c == '/') {
284e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch        ungetc(c, fp);  // Push the '/' back into the stream to be read below.
285e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
286e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch        // Read to the end of the line. Exit if the read fails.
287e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch        if (fgets(lib_name, kLibNameLen, fp) == NULL) break;
288e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
289e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch        // Drop the newline character read by fgets. We do not need to check
290e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch        // for a zero-length string because we know that we at least read the
291e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch        // '/' character.
292e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch        lib_name[strlen(lib_name) - 1] = '\0';
293e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      } else {
294e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch        // No library name found, just record the raw address range.
295e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch        snprintf(lib_name, kLibNameLen,
296e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                 "%08" V8PRIxPTR "-%08" V8PRIxPTR, start, end);
297e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      }
2988b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      LOG(isolate, SharedLibraryEvent(lib_name, start, end));
299e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    } else {
3003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // Entry not describing executable data. Skip to end of line to set up
301e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      // reading the next entry.
302e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      do {
303e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch        c = getc(fp);
304e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      } while ((c != EOF) && (c != '\n'));
305e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      if (c == EOF) break;
306e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    }
307e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  }
308e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  free(lib_name);
309e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  fclose(fp);
310e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
311e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
312e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
313e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid OS::SignalCodeMovingGC() {
314e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Nothing to do on Cygwin.
315e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
316e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
317e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
318e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochint OS::StackWalk(Vector<OS::StackFrame> frames) {
319e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Not supported on Cygwin.
320e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  return 0;
321e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
322e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
323e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
3248b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch// The VirtualMemory implementation is taken from platform-win32.cc.
3258b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch// The mmap-based virtual memory implementation as it is used on most posix
3268b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch// platforms does not work well because Cygwin does not support MAP_FIXED.
3278b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch// This causes VirtualMemory::Commit to not always commit the memory region
3288b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch// specified.
3298b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch
3308b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdochbool VirtualMemory::IsReserved() {
3318b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  return address_ != NULL;
3328b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch}
333e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
334e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
335e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen MurdochVirtualMemory::VirtualMemory(size_t size) {
3368b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  address_ = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS);
337e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  size_ = size;
338e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
339e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
340e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
341e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen MurdochVirtualMemory::~VirtualMemory() {
342e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  if (IsReserved()) {
3438b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    if (0 == VirtualFree(address(), 0, MEM_RELEASE)) address_ = NULL;
344e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  }
345e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
346e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
347e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
348e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochbool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
3498b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
3508b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  if (NULL == VirtualAlloc(address, size, MEM_COMMIT, prot)) {
351e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    return false;
352e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  }
353e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
3548b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  UpdateAllocatedSpaceLimits(address, static_cast<int>(size));
355e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  return true;
356e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
357e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
358e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
359e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochbool VirtualMemory::Uncommit(void* address, size_t size) {
3608b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  ASSERT(IsReserved());
3618b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  return VirtualFree(address, size, MEM_DECOMMIT) != false;
362e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
363e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
364e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
3653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochbool VirtualMemory::Guard(void* address) {
3663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (NULL == VirtualAlloc(address,
3673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           OS::CommitPageSize(),
3683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           MEM_COMMIT,
3693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                           PAGE_READONLY | PAGE_GUARD)) {
3703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    return false;
3713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
3723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return true;
3733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
3743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3768b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdochclass Thread::PlatformData : public Malloced {
377e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch public:
3788b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  PlatformData() : thread_(kNoThread) {}
379e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  pthread_t thread_;  // Thread handle for pthread.
380e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch};
381e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
382e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
383e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
384e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
3853fb3ca8c7ca439d408449a395897395c0faae8d1Ben MurdochThread::Thread(const Options& options)
3863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    : data_(new PlatformData()),
3873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      stack_size_(options.stack_size()) {
3883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  set_name(options.name());
389e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
390e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
391e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
392e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen MurdochThread::~Thread() {
3938b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  delete data_;
394e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
395e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
396e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
397e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochstatic void* ThreadEntry(void* arg) {
398e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  Thread* thread = reinterpret_cast<Thread*>(arg);
399e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // This is also initialized by the first argument to pthread_create() but we
400e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // don't know which thread will run first (the original thread or the new
401e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // one) so we initialize it here too.
4028b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  thread->data()->thread_ = pthread_self();
4038b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  ASSERT(thread->data()->thread_ != kNoThread);
404e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  thread->Run();
405e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  return NULL;
406e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
407e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
408e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
409e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid Thread::set_name(const char* name) {
410e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  strncpy(name_, name, sizeof(name_));
411e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  name_[sizeof(name_) - 1] = '\0';
412e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
413e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
414e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
415e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid Thread::Start() {
4168b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  pthread_attr_t* attr_ptr = NULL;
4178b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  pthread_attr_t attr;
4188b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  if (stack_size_ > 0) {
4198b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    pthread_attr_init(&attr);
4208b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
4218b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    attr_ptr = &attr;
4228b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  }
4238b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  pthread_create(&data_->thread_, attr_ptr, ThreadEntry, this);
4248b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  ASSERT(data_->thread_ != kNoThread);
425e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
426e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
427e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
428e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid Thread::Join() {
4298b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  pthread_join(data_->thread_, NULL);
430e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
431e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
432e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
433e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochstatic inline Thread::LocalStorageKey PthreadKeyToLocalKey(
434e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    pthread_key_t pthread_key) {
435e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // We need to cast pthread_key_t to Thread::LocalStorageKey in two steps
436e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // because pthread_key_t is a pointer type on Cygwin. This will probably not
437e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // work on 64-bit platforms, but Cygwin doesn't support 64-bit anyway.
438e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t));
439e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  intptr_t ptr_key = reinterpret_cast<intptr_t>(pthread_key);
440e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  return static_cast<Thread::LocalStorageKey>(ptr_key);
441e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
442e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
443e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
444e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochstatic inline pthread_key_t LocalKeyToPthreadKey(
445e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    Thread::LocalStorageKey local_key) {
446e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t));
447e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  intptr_t ptr_key = static_cast<intptr_t>(local_key);
448e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  return reinterpret_cast<pthread_key_t>(ptr_key);
449e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
450e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
451e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
452e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen MurdochThread::LocalStorageKey Thread::CreateThreadLocalKey() {
453e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  pthread_key_t key;
454e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  int result = pthread_key_create(&key, NULL);
455e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  USE(result);
456e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  ASSERT(result == 0);
457e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  return PthreadKeyToLocalKey(key);
458e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
459e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
460e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
461e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid Thread::DeleteThreadLocalKey(LocalStorageKey key) {
462e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
463e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  int result = pthread_key_delete(pthread_key);
464e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  USE(result);
465e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  ASSERT(result == 0);
466e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
467e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
468e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
469e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid* Thread::GetThreadLocal(LocalStorageKey key) {
470e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
471e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  return pthread_getspecific(pthread_key);
472e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
473e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
474e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
475e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid Thread::SetThreadLocal(LocalStorageKey key, void* value) {
476e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
477e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  pthread_setspecific(pthread_key, value);
478e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
479e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
480e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
481e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid Thread::YieldCPU() {
482e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  sched_yield();
483e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
484e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
485e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
486e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochclass CygwinMutex : public Mutex {
487e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch public:
488e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  CygwinMutex() {
489e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    pthread_mutexattr_t attrs;
490e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    memset(&attrs, 0, sizeof(attrs));
491e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
492e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    int result = pthread_mutexattr_init(&attrs);
493e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    ASSERT(result == 0);
494e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
495e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    ASSERT(result == 0);
496e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    result = pthread_mutex_init(&mutex_, &attrs);
497e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    ASSERT(result == 0);
498e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  }
499e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
500e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  virtual ~CygwinMutex() { pthread_mutex_destroy(&mutex_); }
501e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
502e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  virtual int Lock() {
503e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    int result = pthread_mutex_lock(&mutex_);
504e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    return result;
505e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  }
506e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
507e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  virtual int Unlock() {
508e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    int result = pthread_mutex_unlock(&mutex_);
509e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    return result;
510e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  }
511e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
512e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  virtual bool TryLock() {
513e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    int result = pthread_mutex_trylock(&mutex_);
514e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    // Return false if the lock is busy and locking failed.
515e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    if (result == EBUSY) {
516e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      return false;
517e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    }
518e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    ASSERT(result == 0);  // Verify no other errors.
519e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    return true;
520e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  }
521e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
522e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch private:
523e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  pthread_mutex_t mutex_;   // Pthread mutex for POSIX platforms.
524e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch};
525e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
526e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
527e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen MurdochMutex* OS::CreateMutex() {
528e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  return new CygwinMutex();
529e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
530e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
531e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
532e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochclass CygwinSemaphore : public Semaphore {
533e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch public:
534e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  explicit CygwinSemaphore(int count) {  sem_init(&sem_, 0, count); }
535e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  virtual ~CygwinSemaphore() { sem_destroy(&sem_); }
536e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
537e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  virtual void Wait();
538e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  virtual bool Wait(int timeout);
539e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  virtual void Signal() { sem_post(&sem_); }
540e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch private:
541e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  sem_t sem_;
542e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch};
543e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
544e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
545e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid CygwinSemaphore::Wait() {
546e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  while (true) {
547e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    int result = sem_wait(&sem_);
548e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    if (result == 0) return;  // Successfully got semaphore.
549e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
550e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  }
551e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
552e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
553e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
554e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch#ifndef TIMEVAL_TO_TIMESPEC
555e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch#define TIMEVAL_TO_TIMESPEC(tv, ts) do {                            \
556e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    (ts)->tv_sec = (tv)->tv_sec;                                    \
557e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    (ts)->tv_nsec = (tv)->tv_usec * 1000;                           \
558e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch} while (false)
559e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch#endif
560e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
561e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
562e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochbool CygwinSemaphore::Wait(int timeout) {
563e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  const long kOneSecondMicros = 1000000;  // NOLINT
564e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
565e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Split timeout into second and nanosecond parts.
566e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  struct timeval delta;
567e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  delta.tv_usec = timeout % kOneSecondMicros;
568e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  delta.tv_sec = timeout / kOneSecondMicros;
569e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
570e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  struct timeval current_time;
571e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Get the current time.
572e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  if (gettimeofday(&current_time, NULL) == -1) {
573e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    return false;
574e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  }
575e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
576e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Calculate time for end of timeout.
577e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  struct timeval end_time;
578e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  timeradd(&current_time, &delta, &end_time);
579e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
580e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  struct timespec ts;
581e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  TIMEVAL_TO_TIMESPEC(&end_time, &ts);
582e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Wait for semaphore signalled or timeout.
583e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  while (true) {
584e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    int result = sem_timedwait(&sem_, &ts);
585e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    if (result == 0) return true;  // Successfully got semaphore.
586e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    if (result == -1 && errno == ETIMEDOUT) return false;  // Timeout.
587e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
588e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  }
589e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
590e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
591e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
592e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen MurdochSemaphore* OS::CreateSemaphore(int count) {
593e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  return new CygwinSemaphore(count);
594e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
595e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
596e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
597e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch// ----------------------------------------------------------------------------
598e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch// Cygwin profiler support.
599e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch//
600e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch// On Cygwin we use the same sampler implementation as on win32.
601e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
602e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochclass Sampler::PlatformData : public Malloced {
603e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch public:
6048b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Get a handle to the calling thread. This is the thread that we are
6058b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // going to profile. We need to make a copy of the handle because we are
6068b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // going to use it in the sampler thread. Using GetThreadHandle() will
6078b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // not work in this case. We're using OpenThread because DuplicateHandle
6088b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // for some reason doesn't work in Chrome's sandbox.
6098b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  PlatformData() : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
6108b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                               THREAD_SUSPEND_RESUME |
6118b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                               THREAD_QUERY_INFORMATION,
6128b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                               false,
6138b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch                                               GetCurrentThreadId())) {}
6148b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch
6158b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  ~PlatformData() {
6168b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    if (profiled_thread_ != NULL) {
6178b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      CloseHandle(profiled_thread_);
6188b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      profiled_thread_ = NULL;
6198b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    }
620e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  }
621e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
6228b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  HANDLE profiled_thread() { return profiled_thread_; }
6238b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch
6248b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch private:
625e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  HANDLE profiled_thread_;
6268b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch};
6278b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch
6288b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch
6298b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdochclass SamplerThread : public Thread {
6308b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch public:
6313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  static const int kSamplerThreadStackSize = 64 * KB;
6323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
6338b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  explicit SamplerThread(int interval)
6343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
6358b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch        interval_(interval) {}
6368b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch
6378b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void AddActiveSampler(Sampler* sampler) {
6383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ScopedLock lock(mutex_.Pointer());
6398b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    SamplerRegistry::AddActiveSampler(sampler);
6408b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    if (instance_ == NULL) {
6418b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      instance_ = new SamplerThread(sampler->interval());
6428b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      instance_->Start();
6438b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    } else {
6448b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      ASSERT(instance_->interval_ == sampler->interval());
6458b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    }
6468b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  }
647e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
6488b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void RemoveActiveSampler(Sampler* sampler) {
6493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ScopedLock lock(mutex_.Pointer());
6508b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    SamplerRegistry::RemoveActiveSampler(sampler);
6518b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
6523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
6538b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      delete instance_;
6548b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      instance_ = NULL;
655e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    }
656e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  }
657e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
6588b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Implement Thread::Run().
6598b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  virtual void Run() {
6608b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    SamplerRegistry::State state;
6618b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    while ((state = SamplerRegistry::GetState()) !=
6628b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch           SamplerRegistry::HAS_NO_SAMPLERS) {
6638b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      bool cpu_profiling_enabled =
6648b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch          (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS);
6658b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled();
6668b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      // When CPU profiling is enabled both JavaScript and C++ code is
6678b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      // profiled. We must not suspend.
6688b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      if (!cpu_profiling_enabled) {
6698b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch        if (rate_limiter_.SuspendIfNecessary()) continue;
6708b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      }
6718b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      if (cpu_profiling_enabled) {
6728b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch        if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) {
6738b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch          return;
6748b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch        }
6758b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      }
6768b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      if (runtime_profiler_enabled) {
6778b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch        if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) {
6788b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch          return;
6798b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch        }
6808b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      }
6818b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      OS::Sleep(interval_);
6828b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    }
6838b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  }
6848b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch
6858b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void DoCpuProfile(Sampler* sampler, void* raw_sampler_thread) {
6868b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    if (!sampler->isolate()->IsInitialized()) return;
6878b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    if (!sampler->IsProfiling()) return;
6888b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    SamplerThread* sampler_thread =
6898b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch        reinterpret_cast<SamplerThread*>(raw_sampler_thread);
6908b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    sampler_thread->SampleContext(sampler);
6918b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  }
6928b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch
6938b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static void DoRuntimeProfile(Sampler* sampler, void* ignored) {
6948b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    if (!sampler->isolate()->IsInitialized()) return;
6958b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    sampler->isolate()->runtime_profiler()->NotifyTick();
6968b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  }
6978b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch
6988b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  void SampleContext(Sampler* sampler) {
6998b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    HANDLE profiled_thread = sampler->platform_data()->profiled_thread();
7008b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    if (profiled_thread == NULL) return;
7018b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch
7028b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    // Context used for sampling the register state of the profiled thread.
7038b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    CONTEXT context;
7048b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    memset(&context, 0, sizeof(context));
705e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
7068b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    TickSample sample_obj;
7078b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    TickSample* sample = CpuProfiler::TickSampleEvent(sampler->isolate());
7088b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    if (sample == NULL) sample = &sample_obj;
709e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
7108b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
7118b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    if (SuspendThread(profiled_thread) == kSuspendFailed) return;
7128b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    sample->state = sampler->isolate()->current_vm_state();
713e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
7148b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    context.ContextFlags = CONTEXT_FULL;
7158b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    if (GetThreadContext(profiled_thread, &context) != 0) {
716e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch#if V8_HOST_ARCH_X64
7178b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      sample->pc = reinterpret_cast<Address>(context.Rip);
7188b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      sample->sp = reinterpret_cast<Address>(context.Rsp);
7198b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      sample->fp = reinterpret_cast<Address>(context.Rbp);
720e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch#else
7218b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      sample->pc = reinterpret_cast<Address>(context.Eip);
7228b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      sample->sp = reinterpret_cast<Address>(context.Esp);
7238b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      sample->fp = reinterpret_cast<Address>(context.Ebp);
724e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch#endif
7258b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      sampler->SampleStack(sample);
7268b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      sampler->Tick(sample);
727e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    }
7288b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    ResumeThread(profiled_thread);
729e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  }
7308b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch
7318b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  const int interval_;
7328b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  RuntimeProfilerRateLimiter rate_limiter_;
7338b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch
7348b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  // Protects the process wide state below.
7353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  static LazyMutex mutex_;
7368b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static SamplerThread* instance_;
7378b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch
7383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch private:
7398b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  DISALLOW_COPY_AND_ASSIGN(SamplerThread);
740e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch};
741e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
742e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
7433ef787dbeca8a5fb1086949cda830dccee07bfbdBen MurdochLazyMutex SamplerThread::mutex_ = LAZY_MUTEX_INITIALIZER;
7448b112d2025046f85ef7f6be087c6129c872ebad2Ben MurdochSamplerThread* SamplerThread::instance_ = NULL;
745e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
746e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
7478b112d2025046f85ef7f6be087c6129c872ebad2Ben MurdochSampler::Sampler(Isolate* isolate, int interval)
7488b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    : isolate_(isolate),
7498b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      interval_(interval),
750e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      profiling_(false),
751e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      active_(false),
752e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      samples_taken_(0) {
7538b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  data_ = new PlatformData;
754e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
755e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
756e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
757e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen MurdochSampler::~Sampler() {
7588b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  ASSERT(!IsActive());
759e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  delete data_;
760e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
761e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
762e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
763e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid Sampler::Start() {
764e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  ASSERT(!IsActive());
765e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  SetActive(true);
7668b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  SamplerThread::AddActiveSampler(this);
767e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
768e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
769e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
770e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid Sampler::Stop() {
7718b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  ASSERT(IsActive());
7728b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  SamplerThread::RemoveActiveSampler(this);
773e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  SetActive(false);
774e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch}
775e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
776e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
777e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch} }  // namespace v8::internal
778