blob: 9028fd0238a9d5b1cae6672c7cb10cf77c05046a [file] [log] [blame]
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000028// Platform specific code for Linux goes here. For the POSIX comaptible parts
29// the implementation is in platform-posix.cc.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000030
31#include <pthread.h>
32#include <semaphore.h>
33#include <signal.h>
lrn@chromium.org5d00b602011-01-05 09:51:43 +000034#include <sys/prctl.h>
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000035#include <sys/time.h>
36#include <sys/resource.h>
lrn@chromium.org303ada72010-10-27 09:33:13 +000037#include <sys/syscall.h>
ager@chromium.org381abbb2009-02-25 13:23:22 +000038#include <sys/types.h>
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000039#include <stdlib.h>
40
41// Ubuntu Dapper requires memory pages to be marked as
42// executable. Otherwise, OS raises an exception when executing code
43// in that page.
44#include <sys/types.h> // mmap & munmap
ager@chromium.org236ad962008-09-25 09:45:57 +000045#include <sys/mman.h> // mmap & munmap
46#include <sys/stat.h> // open
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000047#include <fcntl.h> // open
48#include <unistd.h> // sysconf
fschneider@chromium.org7d10be52012-04-10 12:30:14 +000049#if defined(__GLIBC__) && !defined(__UCLIBC__)
ager@chromium.org236ad962008-09-25 09:45:57 +000050#include <execinfo.h> // backtrace, backtrace_symbols
fschneider@chromium.org7d10be52012-04-10 12:30:14 +000051#endif // defined(__GLIBC__) && !defined(__UCLIBC__)
ager@chromium.org236ad962008-09-25 09:45:57 +000052#include <strings.h> // index
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000053#include <errno.h>
54#include <stdarg.h>
55
56#undef MAP_TYPE
57
58#include "v8.h"
59
danno@chromium.org8c0a43f2012-04-03 08:37:53 +000060#include "platform-posix.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061#include "platform.h"
ager@chromium.orga1645e22009-09-09 19:27:10 +000062#include "v8threads.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000063#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
65
kasperl@chromium.org71affb52009-05-26 05:44:31 +000066namespace v8 {
67namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068
69// 0 is never a valid thread id on Linux since tids and pids share a
70// name space and pid 0 is reserved (see man 2 kill).
71static const pthread_t kNoThread = (pthread_t) 0;
72
73
74double ceiling(double x) {
75 return ceil(x);
76}
77
78
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000079static Mutex* limit_mutex = NULL;
80
81
danno@chromium.org8c0a43f2012-04-03 08:37:53 +000082void OS::PostSetUp() {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +000083 POSIXPostSetUp();
danno@chromium.org8c0a43f2012-04-03 08:37:53 +000084}
85
86
ager@chromium.orgc4c92722009-11-18 14:12:51 +000087uint64_t OS::CpuFeaturesImpliedByPlatform() {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000088 return 0; // Linux runs on anything.
ager@chromium.orgc4c92722009-11-18 14:12:51 +000089}
90
91
ager@chromium.orgc4c92722009-11-18 14:12:51 +000092#ifdef __arm__
lrn@chromium.orgfa943b72010-11-03 08:14:36 +000093static bool CPUInfoContainsString(const char * search_string) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000094 const char* file_name = "/proc/cpuinfo";
ager@chromium.orgc4c92722009-11-18 14:12:51 +000095 // This is written as a straight shot one pass parser
96 // and not using STL string and ifstream because,
97 // on Linux, it's reading from a (non-mmap-able)
98 // character special device.
ager@chromium.orgc4c92722009-11-18 14:12:51 +000099 FILE* f = NULL;
100 const char* what = search_string;
101
102 if (NULL == (f = fopen(file_name, "r")))
103 return false;
104
105 int k;
106 while (EOF != (k = fgetc(f))) {
107 if (k == *what) {
108 ++what;
109 while ((*what != '\0') && (*what == fgetc(f))) {
110 ++what;
111 }
112 if (*what == '\0') {
113 fclose(f);
114 return true;
115 } else {
116 what = search_string;
117 }
118 }
119 }
120 fclose(f);
121
122 // Did not find string in the proc file.
123 return false;
124}
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000125
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000126
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000127bool OS::ArmCpuHasFeature(CpuFeature feature) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000128 const char* search_string = NULL;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000129 // Simple detection of VFP at runtime for Linux.
130 // It is based on /proc/cpuinfo, which reveals hardware configuration
131 // to user-space applications. According to ARM (mid 2009), no similar
132 // facility is universally available on the ARM architectures,
133 // so it's up to individual OSes to provide such.
134 switch (feature) {
135 case VFP3:
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000136 search_string = "vfpv3";
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000137 break;
138 case ARMv7:
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000139 search_string = "ARMv7";
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000140 break;
141 default:
142 UNREACHABLE();
143 }
144
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000145 if (CPUInfoContainsString(search_string)) {
146 return true;
147 }
148
149 if (feature == VFP3) {
150 // Some old kernels will report vfp not vfpv3. Here we make a last attempt
151 // to detect vfpv3 by checking for vfp *and* neon, since neon is only
152 // available on architectures with vfpv3.
153 // Checking neon on its own is not enough as it is possible to have neon
154 // without vfp.
155 if (CPUInfoContainsString("vfp") && CPUInfoContainsString("neon")) {
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000156 return true;
157 }
158 }
159
160 return false;
161}
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000162
163
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000164bool OS::ArmUsingHardFloat() {
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000165 // GCC versions 4.6 and above define __ARM_PCS or __ARM_PCS_VFP to specify
166 // the Floating Point ABI used (PCS stands for Procedure Call Standard).
167 // We use these as well as a couple of other defines to statically determine
168 // what FP ABI used.
169 // GCC versions 4.4 and below don't support hard-fp.
170 // GCC versions 4.5 may support hard-fp without defining __ARM_PCS or
171 // __ARM_PCS_VFP.
172
173#define GCC_VERSION (__GNUC__ * 10000 \
174 + __GNUC_MINOR__ * 100 \
175 + __GNUC_PATCHLEVEL__)
176#if GCC_VERSION >= 40600
177#if defined(__ARM_PCS_VFP)
178 return true;
179#else
180 return false;
181#endif
182
183#elif GCC_VERSION < 40500
184 return false;
185
186#else
187#if defined(__ARM_PCS_VFP)
188 return true;
189#elif defined(__ARM_PCS) || defined(__SOFTFP) || !defined(__VFP_FP__)
190 return false;
191#else
192#error "Your version of GCC does not report the FP ABI compiled for." \
193 "Please report it on this issue" \
194 "http://code.google.com/p/v8/issues/detail?id=2140"
195
196#endif
197#endif
198#undef GCC_VERSION
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000199}
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000200
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000201#endif // def __arm__
202
203
lrn@chromium.org7516f052011-03-30 08:52:27 +0000204#ifdef __mips__
205bool OS::MipsCpuHasFeature(CpuFeature feature) {
206 const char* search_string = NULL;
207 const char* file_name = "/proc/cpuinfo";
208 // Simple detection of FPU at runtime for Linux.
209 // It is based on /proc/cpuinfo, which reveals hardware configuration
210 // to user-space applications. According to MIPS (early 2010), no similar
211 // facility is universally available on the MIPS architectures,
212 // so it's up to individual OSes to provide such.
213 //
214 // This is written as a straight shot one pass parser
215 // and not using STL string and ifstream because,
216 // on Linux, it's reading from a (non-mmap-able)
217 // character special device.
218
219 switch (feature) {
220 case FPU:
221 search_string = "FPU";
222 break;
223 default:
224 UNREACHABLE();
225 }
226
227 FILE* f = NULL;
228 const char* what = search_string;
229
230 if (NULL == (f = fopen(file_name, "r")))
231 return false;
232
233 int k;
234 while (EOF != (k = fgetc(f))) {
235 if (k == *what) {
236 ++what;
237 while ((*what != '\0') && (*what == fgetc(f))) {
238 ++what;
239 }
240 if (*what == '\0') {
241 fclose(f);
242 return true;
243 } else {
244 what = search_string;
245 }
246 }
247 }
248 fclose(f);
249
250 // Did not find string in the proc file.
251 return false;
252}
253#endif // def __mips__
254
255
ager@chromium.org236ad962008-09-25 09:45:57 +0000256int OS::ActivationFrameAlignment() {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000257#ifdef V8_TARGET_ARCH_ARM
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000258 // On EABI ARM targets this is required for fp correctness in the
259 // runtime system.
ager@chromium.org3a6061e2009-03-12 14:24:36 +0000260 return 8;
ager@chromium.org5c838252010-02-19 08:53:10 +0000261#elif V8_TARGET_ARCH_MIPS
262 return 8;
263#endif
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000264 // With gcc 4.4 the tree vectorization optimizer can generate code
ager@chromium.orge2902be2009-06-08 12:21:35 +0000265 // that requires 16 byte alignment such as movdqa on x86.
266 return 16;
ager@chromium.org236ad962008-09-25 09:45:57 +0000267}
268
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000269
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000270void OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000271#if (defined(V8_TARGET_ARCH_ARM) && defined(__arm__)) || \
272 (defined(V8_TARGET_ARCH_MIPS) && defined(__mips__))
273 // Only use on ARM or MIPS hardware.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000274 MemoryBarrier();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000275#else
276 __asm__ __volatile__("" : : : "memory");
277 // An x86 store acts as a release barrier.
278#endif
279 *ptr = value;
280}
281
282
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000283const char* OS::LocalTimezone(double time) {
284 if (isnan(time)) return "";
285 time_t tv = static_cast<time_t>(floor(time/msPerSecond));
286 struct tm* t = localtime(&tv);
287 if (NULL == t) return "";
288 return t->tm_zone;
289}
290
291
292double OS::LocalTimeOffset() {
293 time_t tv = time(NULL);
294 struct tm* t = localtime(&tv);
295 // tm_gmtoff includes any daylight savings offset, so subtract it.
296 return static_cast<double>(t->tm_gmtoff * msPerSecond -
297 (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
298}
299
300
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000301// We keep the lowest and highest addresses mapped as a quick way of
302// determining that pointers are outside the heap (used mostly in assertions
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000303// and verification). The estimate is conservative, i.e., not all addresses in
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000304// 'allocated' space are actually allocated to our heap. The range is
305// [lowest, highest), inclusive on the low and and exclusive on the high end.
306static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
307static void* highest_ever_allocated = reinterpret_cast<void*>(0);
308
309
310static void UpdateAllocatedSpaceLimits(void* address, int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000311 ASSERT(limit_mutex != NULL);
312 ScopedLock lock(limit_mutex);
313
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000314 lowest_ever_allocated = Min(lowest_ever_allocated, address);
315 highest_ever_allocated =
316 Max(highest_ever_allocated,
317 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
318}
319
320
321bool OS::IsOutsideAllocatedSpace(void* address) {
322 return address < lowest_ever_allocated || address >= highest_ever_allocated;
323}
324
325
326size_t OS::AllocateAlignment() {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000327 return sysconf(_SC_PAGESIZE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000328}
329
330
kasper.lund7276f142008-07-30 08:49:36 +0000331void* OS::Allocate(const size_t requested,
332 size_t* allocated,
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000333 bool is_executable) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000334 const size_t msize = RoundUp(requested, AllocateAlignment());
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000335 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000336 void* addr = OS::GetRandomMmapAddr();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000337 void* mbase = mmap(addr, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000338 if (mbase == MAP_FAILED) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000339 LOG(i::Isolate::Current(),
340 StringEvent("OS::Allocate", "mmap failed"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000341 return NULL;
342 }
343 *allocated = msize;
344 UpdateAllocatedSpaceLimits(mbase, msize);
345 return mbase;
346}
347
348
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000349void OS::Free(void* address, const size_t size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000350 // TODO(1240712): munmap has a return value which is ignored here.
ager@chromium.orga1645e22009-09-09 19:27:10 +0000351 int result = munmap(address, size);
352 USE(result);
353 ASSERT(result == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000354}
355
356
357void OS::Sleep(int milliseconds) {
358 unsigned int ms = static_cast<unsigned int>(milliseconds);
359 usleep(1000 * ms);
360}
361
362
363void OS::Abort() {
364 // Redirect to std abort to signal abnormal program termination.
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000365 if (FLAG_break_on_abort) {
366 DebugBreak();
367 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000368 abort();
369}
370
371
kasper.lund7276f142008-07-30 08:49:36 +0000372void OS::DebugBreak() {
ager@chromium.org5ec48922009-05-05 07:25:34 +0000373// TODO(lrn): Introduce processor define for runtime system (!= V8_ARCH_x,
374// which is the architecture of generated code).
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000375#if (defined(__arm__) || defined(__thumb__))
376# if defined(CAN_USE_ARMV5_INSTRUCTIONS)
kasper.lund7276f142008-07-30 08:49:36 +0000377 asm("bkpt 0");
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000378# endif
ager@chromium.org5c838252010-02-19 08:53:10 +0000379#elif defined(__mips__)
380 asm("break");
kasper.lund7276f142008-07-30 08:49:36 +0000381#else
382 asm("int $3");
383#endif
384}
385
386
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000387class PosixMemoryMappedFile : public OS::MemoryMappedFile {
388 public:
389 PosixMemoryMappedFile(FILE* file, void* memory, int size)
390 : file_(file), memory_(memory), size_(size) { }
391 virtual ~PosixMemoryMappedFile();
392 virtual void* memory() { return memory_; }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000393 virtual int size() { return size_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000394 private:
395 FILE* file_;
396 void* memory_;
397 int size_;
398};
399
400
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000401OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000402 FILE* file = fopen(name, "r+");
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000403 if (file == NULL) return NULL;
404
405 fseek(file, 0, SEEK_END);
406 int size = ftell(file);
407
408 void* memory =
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000409 mmap(OS::GetRandomMmapAddr(),
410 size,
411 PROT_READ | PROT_WRITE,
412 MAP_SHARED,
413 fileno(file),
414 0);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000415 return new PosixMemoryMappedFile(file, memory, size);
416}
417
418
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000419OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
420 void* initial) {
421 FILE* file = fopen(name, "w+");
422 if (file == NULL) return NULL;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000423 int result = fwrite(initial, size, 1, file);
424 if (result < 1) {
425 fclose(file);
426 return NULL;
427 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000428 void* memory =
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000429 mmap(OS::GetRandomMmapAddr(),
430 size,
431 PROT_READ | PROT_WRITE,
432 MAP_SHARED,
433 fileno(file),
434 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000435 return new PosixMemoryMappedFile(file, memory, size);
436}
437
438
439PosixMemoryMappedFile::~PosixMemoryMappedFile() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000440 if (memory_) OS::Free(memory_, size_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000441 fclose(file_);
442}
443
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000444
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000445void OS::LogSharedLibraryAddresses() {
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000446 // This function assumes that the layout of the file is as follows:
447 // hex_start_addr-hex_end_addr rwxp <unused data> [binary_file_name]
448 // If we encounter an unexpected situation we abort scanning further entries.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000449 FILE* fp = fopen("/proc/self/maps", "r");
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000450 if (fp == NULL) return;
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000451
452 // Allocate enough room to be able to store a full file name.
453 const int kLibNameLen = FILENAME_MAX + 1;
454 char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen));
455
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000456 i::Isolate* isolate = ISOLATE;
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000457 // This loop will terminate once the scanning hits an EOF.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000458 while (true) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000459 uintptr_t start, end;
460 char attr_r, attr_w, attr_x, attr_p;
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000461 // Parse the addresses and permission bits at the beginning of the line.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000462 if (fscanf(fp, "%" V8PRIxPTR "-%" V8PRIxPTR, &start, &end) != 2) break;
463 if (fscanf(fp, " %c%c%c%c", &attr_r, &attr_w, &attr_x, &attr_p) != 4) break;
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000464
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000465 int c;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000466 if (attr_r == 'r' && attr_w != 'w' && attr_x == 'x') {
467 // Found a read-only executable entry. Skip characters until we reach
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000468 // the beginning of the filename or the end of the line.
469 do {
470 c = getc(fp);
471 } while ((c != EOF) && (c != '\n') && (c != '/'));
472 if (c == EOF) break; // EOF: Was unexpected, just exit.
473
474 // Process the filename if found.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000475 if (c == '/') {
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000476 ungetc(c, fp); // Push the '/' back into the stream to be read below.
477
478 // Read to the end of the line. Exit if the read fails.
479 if (fgets(lib_name, kLibNameLen, fp) == NULL) break;
480
481 // Drop the newline character read by fgets. We do not need to check
482 // for a zero-length string because we know that we at least read the
483 // '/' character.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000484 lib_name[strlen(lib_name) - 1] = '\0';
485 } else {
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000486 // No library name found, just record the raw address range.
487 snprintf(lib_name, kLibNameLen,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000488 "%08" V8PRIxPTR "-%08" V8PRIxPTR, start, end);
489 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000490 LOG(isolate, SharedLibraryEvent(lib_name, start, end));
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000491 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000492 // Entry not describing executable data. Skip to end of line to set up
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000493 // reading the next entry.
494 do {
495 c = getc(fp);
496 } while ((c != EOF) && (c != '\n'));
497 if (c == EOF) break;
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000498 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000499 }
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000500 free(lib_name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000501 fclose(fp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000502}
503
504
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000505static const char kGCFakeMmap[] = "/tmp/__v8_gc__";
506
507
508void OS::SignalCodeMovingGC() {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000509 // Support for ll_prof.py.
510 //
511 // The Linux profiler built into the kernel logs all mmap's with
512 // PROT_EXEC so that analysis tools can properly attribute ticks. We
513 // do a mmap with a name known by ll_prof.py and immediately munmap
514 // it. This injects a GC marker into the stream of events generated
515 // by the kernel and allows us to synchronize V8 code log and the
516 // kernel log.
517 int size = sysconf(_SC_PAGESIZE);
518 FILE* f = fopen(kGCFakeMmap, "w+");
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000519 void* addr = mmap(OS::GetRandomMmapAddr(),
520 size,
521 PROT_READ | PROT_EXEC,
522 MAP_PRIVATE,
523 fileno(f),
524 0);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000525 ASSERT(addr != MAP_FAILED);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000526 OS::Free(addr, size);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000527 fclose(f);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000528}
529
530
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000531int OS::StackWalk(Vector<OS::StackFrame> frames) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000532 // backtrace is a glibc extension.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000533#if defined(__GLIBC__) && !defined(__UCLIBC__)
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000534 int frames_size = frames.length();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000535 ScopedVector<void*> addresses(frames_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000536
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000537 int frames_count = backtrace(addresses.start(), frames_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000538
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000539 char** symbols = backtrace_symbols(addresses.start(), frames_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000540 if (symbols == NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000541 return kStackWalkError;
542 }
543
544 for (int i = 0; i < frames_count; i++) {
545 frames[i].address = addresses[i];
546 // Format a text representation of the frame based on the information
547 // available.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000548 SNPrintF(MutableCStrVector(frames[i].text, kStackWalkMaxTextLen),
549 "%s",
550 symbols[i]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000551 // Make sure line termination is in place.
552 frames[i].text[kStackWalkMaxTextLen - 1] = '\0';
553 }
554
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000555 free(symbols);
556
557 return frames_count;
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000558#else // defined(__GLIBC__) && !defined(__UCLIBC__)
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000559 return 0;
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000560#endif // defined(__GLIBC__) && !defined(__UCLIBC__)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000561}
562
563
564// Constants used for mmap.
565static const int kMmapFd = -1;
566static const int kMmapFdOffset = 0;
567
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000568VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000569
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000570VirtualMemory::VirtualMemory(size_t size) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000571 address_ = ReserveRegion(size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000572 size_ = size;
573}
574
575
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000576VirtualMemory::VirtualMemory(size_t size, size_t alignment)
577 : address_(NULL), size_(0) {
578 ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
579 size_t request_size = RoundUp(size + alignment,
580 static_cast<intptr_t>(OS::AllocateAlignment()));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000581 void* reservation = mmap(OS::GetRandomMmapAddr(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000582 request_size,
583 PROT_NONE,
584 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
585 kMmapFd,
586 kMmapFdOffset);
587 if (reservation == MAP_FAILED) return;
588
589 Address base = static_cast<Address>(reservation);
590 Address aligned_base = RoundUp(base, alignment);
591 ASSERT_LE(base, aligned_base);
592
593 // Unmap extra memory reserved before and after the desired block.
594 if (aligned_base != base) {
595 size_t prefix_size = static_cast<size_t>(aligned_base - base);
596 OS::Free(base, prefix_size);
597 request_size -= prefix_size;
598 }
599
600 size_t aligned_size = RoundUp(size, OS::AllocateAlignment());
601 ASSERT_LE(aligned_size, request_size);
602
603 if (aligned_size != request_size) {
604 size_t suffix_size = request_size - aligned_size;
605 OS::Free(aligned_base + aligned_size, suffix_size);
606 request_size -= suffix_size;
607 }
608
609 ASSERT(aligned_size == request_size);
610
611 address_ = static_cast<void*>(aligned_base);
612 size_ = aligned_size;
613}
614
615
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000616VirtualMemory::~VirtualMemory() {
617 if (IsReserved()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000618 bool result = ReleaseRegion(address(), size());
619 ASSERT(result);
620 USE(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000621 }
622}
623
624
625bool VirtualMemory::IsReserved() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000626 return address_ != NULL;
627}
628
629
630void VirtualMemory::Reset() {
631 address_ = NULL;
632 size_ = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000633}
634
635
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000636bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000637 return CommitRegion(address, size, is_executable);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000638}
639
640
641bool VirtualMemory::Uncommit(void* address, size_t size) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000642 return UncommitRegion(address, size);
643}
644
645
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000646bool VirtualMemory::Guard(void* address) {
647 OS::Guard(address, OS::CommitPageSize());
648 return true;
649}
650
651
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000652void* VirtualMemory::ReserveRegion(size_t size) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000653 void* result = mmap(OS::GetRandomMmapAddr(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000654 size,
655 PROT_NONE,
656 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
657 kMmapFd,
658 kMmapFdOffset);
659
660 if (result == MAP_FAILED) return NULL;
661
662 return result;
663}
664
665
666bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
667 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
668 if (MAP_FAILED == mmap(base,
669 size,
670 prot,
671 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
672 kMmapFd,
673 kMmapFdOffset)) {
674 return false;
675 }
676
677 UpdateAllocatedSpaceLimits(base, size);
678 return true;
679}
680
681
682bool VirtualMemory::UncommitRegion(void* base, size_t size) {
683 return mmap(base,
684 size,
685 PROT_NONE,
ager@chromium.orga1645e22009-09-09 19:27:10 +0000686 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_FIXED,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000687 kMmapFd,
688 kMmapFdOffset) != MAP_FAILED;
689}
690
691
692bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
693 return munmap(base, size) == 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000694}
695
696
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000697class Thread::PlatformData : public Malloced {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000698 public:
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000699 PlatformData() : thread_(kNoThread) {}
ager@chromium.org41826e72009-03-30 13:30:57 +0000700
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000701 pthread_t thread_; // Thread handle for pthread.
702};
703
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000704Thread::Thread(const Options& options)
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000705 : data_(new PlatformData()),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000706 stack_size_(options.stack_size()) {
707 set_name(options.name());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000708}
709
710
711Thread::~Thread() {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000712 delete data_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000713}
714
715
716static void* ThreadEntry(void* arg) {
717 Thread* thread = reinterpret_cast<Thread*>(arg);
718 // This is also initialized by the first argument to pthread_create() but we
719 // don't know which thread will run first (the original thread or the new
720 // one) so we initialize it here too.
danno@chromium.orgb6451162011-08-17 14:33:23 +0000721#ifdef PR_SET_NAME
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000722 prctl(PR_SET_NAME,
723 reinterpret_cast<unsigned long>(thread->name()), // NOLINT
724 0, 0, 0);
danno@chromium.orgb6451162011-08-17 14:33:23 +0000725#endif
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000726 thread->data()->thread_ = pthread_self();
727 ASSERT(thread->data()->thread_ != kNoThread);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000728 thread->Run();
729 return NULL;
730}
731
732
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000733void Thread::set_name(const char* name) {
734 strncpy(name_, name, sizeof(name_));
735 name_[sizeof(name_) - 1] = '\0';
736}
737
738
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000739void Thread::Start() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000740 pthread_attr_t* attr_ptr = NULL;
741 pthread_attr_t attr;
742 if (stack_size_ > 0) {
743 pthread_attr_init(&attr);
744 pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
745 attr_ptr = &attr;
746 }
danno@chromium.orgc612e022011-11-10 11:38:15 +0000747 int result = pthread_create(&data_->thread_, attr_ptr, ThreadEntry, this);
748 CHECK_EQ(0, result);
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000749 ASSERT(data_->thread_ != kNoThread);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000750}
751
752
753void Thread::Join() {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000754 pthread_join(data_->thread_, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000755}
756
757
758Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
759 pthread_key_t key;
760 int result = pthread_key_create(&key, NULL);
761 USE(result);
762 ASSERT(result == 0);
763 return static_cast<LocalStorageKey>(key);
764}
765
766
767void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
768 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
769 int result = pthread_key_delete(pthread_key);
770 USE(result);
771 ASSERT(result == 0);
772}
773
774
775void* Thread::GetThreadLocal(LocalStorageKey key) {
776 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
777 return pthread_getspecific(pthread_key);
778}
779
780
781void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
782 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
783 pthread_setspecific(pthread_key, value);
784}
785
786
787void Thread::YieldCPU() {
788 sched_yield();
789}
790
791
792class LinuxMutex : public Mutex {
793 public:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000794 LinuxMutex() {
795 pthread_mutexattr_t attrs;
796 int result = pthread_mutexattr_init(&attrs);
797 ASSERT(result == 0);
798 result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
799 ASSERT(result == 0);
800 result = pthread_mutex_init(&mutex_, &attrs);
801 ASSERT(result == 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000802 USE(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000803 }
804
805 virtual ~LinuxMutex() { pthread_mutex_destroy(&mutex_); }
806
807 virtual int Lock() {
808 int result = pthread_mutex_lock(&mutex_);
809 return result;
810 }
811
812 virtual int Unlock() {
813 int result = pthread_mutex_unlock(&mutex_);
814 return result;
815 }
816
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000817 virtual bool TryLock() {
818 int result = pthread_mutex_trylock(&mutex_);
819 // Return false if the lock is busy and locking failed.
820 if (result == EBUSY) {
821 return false;
822 }
823 ASSERT(result == 0); // Verify no other errors.
824 return true;
825 }
826
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000827 private:
828 pthread_mutex_t mutex_; // Pthread mutex for POSIX platforms.
829};
830
831
832Mutex* OS::CreateMutex() {
833 return new LinuxMutex();
834}
835
836
837class LinuxSemaphore : public Semaphore {
838 public:
839 explicit LinuxSemaphore(int count) { sem_init(&sem_, 0, count); }
840 virtual ~LinuxSemaphore() { sem_destroy(&sem_); }
841
kasper.lund7276f142008-07-30 08:49:36 +0000842 virtual void Wait();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000843 virtual bool Wait(int timeout);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000844 virtual void Signal() { sem_post(&sem_); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000845 private:
846 sem_t sem_;
847};
848
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000849
kasper.lund7276f142008-07-30 08:49:36 +0000850void LinuxSemaphore::Wait() {
851 while (true) {
852 int result = sem_wait(&sem_);
853 if (result == 0) return; // Successfully got semaphore.
854 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
855 }
856}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000857
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000858
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000859#ifndef TIMEVAL_TO_TIMESPEC
860#define TIMEVAL_TO_TIMESPEC(tv, ts) do { \
861 (ts)->tv_sec = (tv)->tv_sec; \
862 (ts)->tv_nsec = (tv)->tv_usec * 1000; \
863} while (false)
864#endif
865
866
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000867bool LinuxSemaphore::Wait(int timeout) {
868 const long kOneSecondMicros = 1000000; // NOLINT
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000869
870 // Split timeout into second and nanosecond parts.
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000871 struct timeval delta;
872 delta.tv_usec = timeout % kOneSecondMicros;
873 delta.tv_sec = timeout / kOneSecondMicros;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000874
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000875 struct timeval current_time;
876 // Get the current time.
877 if (gettimeofday(&current_time, NULL) == -1) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000878 return false;
879 }
880
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000881 // Calculate time for end of timeout.
882 struct timeval end_time;
883 timeradd(&current_time, &delta, &end_time);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000884
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000885 struct timespec ts;
886 TIMEVAL_TO_TIMESPEC(&end_time, &ts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000887 // Wait for semaphore signalled or timeout.
888 while (true) {
889 int result = sem_timedwait(&sem_, &ts);
890 if (result == 0) return true; // Successfully got semaphore.
891 if (result > 0) {
892 // For glibc prior to 2.3.4 sem_timedwait returns the error instead of -1.
893 errno = result;
894 result = -1;
895 }
896 if (result == -1 && errno == ETIMEDOUT) return false; // Timeout.
897 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
898 }
899}
900
901
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000902Semaphore* OS::CreateSemaphore(int count) {
903 return new LinuxSemaphore(count);
904}
905
ager@chromium.org381abbb2009-02-25 13:23:22 +0000906
kasperl@chromium.orgacae3782009-04-11 09:17:08 +0000907#if !defined(__GLIBC__) && (defined(__arm__) || defined(__thumb__))
908// Android runs a fairly new Linux kernel, so signal info is there,
909// but the C library doesn't have the structs defined.
910
911struct sigcontext {
912 uint32_t trap_no;
913 uint32_t error_code;
914 uint32_t oldmask;
915 uint32_t gregs[16];
916 uint32_t arm_cpsr;
917 uint32_t fault_address;
918};
919typedef uint32_t __sigset_t;
920typedef struct sigcontext mcontext_t;
921typedef struct ucontext {
922 uint32_t uc_flags;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000923 struct ucontext* uc_link;
kasperl@chromium.orgacae3782009-04-11 09:17:08 +0000924 stack_t uc_stack;
925 mcontext_t uc_mcontext;
926 __sigset_t uc_sigmask;
927} ucontext_t;
928enum ArmRegisters {R15 = 15, R13 = 13, R11 = 11};
929
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000930#elif !defined(__GLIBC__) && defined(__mips__)
931// MIPS version of sigcontext, for Android bionic.
932struct sigcontext {
933 uint32_t regmask;
934 uint32_t status;
935 uint64_t pc;
936 uint64_t gregs[32];
937 uint64_t fpregs[32];
938 uint32_t acx;
939 uint32_t fpc_csr;
940 uint32_t fpc_eir;
941 uint32_t used_math;
942 uint32_t dsp;
943 uint64_t mdhi;
944 uint64_t mdlo;
945 uint32_t hi1;
946 uint32_t lo1;
947 uint32_t hi2;
948 uint32_t lo2;
949 uint32_t hi3;
950 uint32_t lo3;
951};
952typedef uint32_t __sigset_t;
953typedef struct sigcontext mcontext_t;
954typedef struct ucontext {
955 uint32_t uc_flags;
956 struct ucontext* uc_link;
957 stack_t uc_stack;
958 mcontext_t uc_mcontext;
959 __sigset_t uc_sigmask;
960} ucontext_t;
961
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000962#elif !defined(__GLIBC__) && defined(__i386__)
963// x86 version for Android.
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +0000964struct sigcontext {
965 uint32_t gregs[19];
966 void* fpregs;
967 uint32_t oldmask;
968 uint32_t cr2;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000969};
970
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +0000971typedef uint32_t __sigset_t;
972typedef struct sigcontext mcontext_t;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000973typedef struct ucontext {
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +0000974 uint32_t uc_flags;
975 struct ucontext* uc_link;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000976 stack_t uc_stack;
977 mcontext_t uc_mcontext;
978 __sigset_t uc_sigmask;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000979} ucontext_t;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000980enum { REG_EBP = 6, REG_ESP = 7, REG_EIP = 14 };
kasperl@chromium.orgacae3782009-04-11 09:17:08 +0000981#endif
982
983
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000984static int GetThreadID() {
985 // Glibc doesn't provide a wrapper for gettid(2).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000986#if defined(ANDROID)
987 return syscall(__NR_gettid);
988#else
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000989 return syscall(SYS_gettid);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000990#endif
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000991}
992
993
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000994static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
995 USE(info);
996 if (signal != SIGPROF) return;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000997 Isolate* isolate = Isolate::UncheckedCurrent();
998 if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
999 // We require a fully initialized and entered isolate.
1000 return;
1001 }
vitalyr@chromium.org0ec56d62011-04-15 22:22:08 +00001002 if (v8::Locker::IsActive() &&
1003 !isolate->thread_manager()->IsLockedByCurrentThread()) {
1004 return;
1005 }
1006
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001007 Sampler* sampler = isolate->logger()->sampler();
1008 if (sampler == NULL || !sampler->IsActive()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001009
lrn@chromium.org25156de2010-04-06 13:10:27 +00001010 TickSample sample_obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001011 TickSample* sample = CpuProfiler::TickSampleEvent(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +00001012 if (sample == NULL) sample = &sample_obj;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001013
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001014 // Extracting the sample from the context is extremely machine dependent.
1015 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
1016 mcontext_t& mcontext = ucontext->uc_mcontext;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001017 sample->state = isolate->current_vm_state();
ager@chromium.org9085a012009-05-11 19:22:57 +00001018#if V8_HOST_ARCH_IA32
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001019 sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
1020 sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
1021 sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]);
ager@chromium.org9085a012009-05-11 19:22:57 +00001022#elif V8_HOST_ARCH_X64
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001023 sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]);
1024 sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]);
1025 sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]);
ager@chromium.org9085a012009-05-11 19:22:57 +00001026#elif V8_HOST_ARCH_ARM
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001027// An undefined macro evaluates to 0, so this applies to Android's Bionic also.
1028#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001029 sample->pc = reinterpret_cast<Address>(mcontext.gregs[R15]);
1030 sample->sp = reinterpret_cast<Address>(mcontext.gregs[R13]);
1031 sample->fp = reinterpret_cast<Address>(mcontext.gregs[R11]);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001032#else
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001033 sample->pc = reinterpret_cast<Address>(mcontext.arm_pc);
1034 sample->sp = reinterpret_cast<Address>(mcontext.arm_sp);
1035 sample->fp = reinterpret_cast<Address>(mcontext.arm_fp);
danno@chromium.orgc612e022011-11-10 11:38:15 +00001036#endif // (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
ager@chromium.org5c838252010-02-19 08:53:10 +00001037#elif V8_HOST_ARCH_MIPS
danno@chromium.orgc612e022011-11-10 11:38:15 +00001038 sample->pc = reinterpret_cast<Address>(mcontext.pc);
1039 sample->sp = reinterpret_cast<Address>(mcontext.gregs[29]);
1040 sample->fp = reinterpret_cast<Address>(mcontext.gregs[30]);
1041#endif // V8_HOST_ARCH_*
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001042 sampler->SampleStack(sample);
1043 sampler->Tick(sample);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001044}
1045
1046
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001047class Sampler::PlatformData : public Malloced {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001048 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001049 PlatformData() : vm_tid_(GetThreadID()) {}
1050
1051 int vm_tid() const { return vm_tid_; }
1052
1053 private:
1054 const int vm_tid_;
1055};
1056
1057
1058class SignalSender : public Thread {
1059 public:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001060 enum SleepInterval {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001061 HALF_INTERVAL,
1062 FULL_INTERVAL
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001063 };
1064
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00001065 static const int kSignalSenderStackSize = 64 * KB;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001066
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001067 explicit SignalSender(int interval)
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001068 : Thread(Thread::Options("SignalSender", kSignalSenderStackSize)),
lrn@chromium.org303ada72010-10-27 09:33:13 +00001069 vm_tgid_(getpid()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001070 interval_(interval) {}
1071
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001072 static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
1073 static void TearDown() { delete mutex_; }
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001074
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001075 static void InstallSignalHandler() {
1076 struct sigaction sa;
1077 sa.sa_sigaction = ProfilerSignalHandler;
1078 sigemptyset(&sa.sa_mask);
1079 sa.sa_flags = SA_RESTART | SA_SIGINFO;
1080 signal_handler_installed_ =
1081 (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
1082 }
1083
1084 static void RestoreSignalHandler() {
1085 if (signal_handler_installed_) {
1086 sigaction(SIGPROF, &old_signal_handler_, 0);
1087 signal_handler_installed_ = false;
1088 }
1089 }
1090
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001091 static void AddActiveSampler(Sampler* sampler) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001092 ScopedLock lock(mutex_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001093 SamplerRegistry::AddActiveSampler(sampler);
1094 if (instance_ == NULL) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001095 // Start a thread that will send SIGPROF signal to VM threads,
1096 // when CPU profiling will be enabled.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001097 instance_ = new SignalSender(sampler->interval());
1098 instance_->Start();
1099 } else {
1100 ASSERT(instance_->interval_ == sampler->interval());
1101 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001102 }
1103
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001104 static void RemoveActiveSampler(Sampler* sampler) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001105 ScopedLock lock(mutex_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001106 SamplerRegistry::RemoveActiveSampler(sampler);
1107 if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001108 RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001109 delete instance_;
1110 instance_ = NULL;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001111 RestoreSignalHandler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001112 }
1113 }
1114
1115 // Implement Thread::Run().
1116 virtual void Run() {
1117 SamplerRegistry::State state;
1118 while ((state = SamplerRegistry::GetState()) !=
1119 SamplerRegistry::HAS_NO_SAMPLERS) {
1120 bool cpu_profiling_enabled =
1121 (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS);
1122 bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled();
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001123 if (cpu_profiling_enabled && !signal_handler_installed_) {
1124 InstallSignalHandler();
1125 } else if (!cpu_profiling_enabled && signal_handler_installed_) {
1126 RestoreSignalHandler();
1127 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001128 // When CPU profiling is enabled both JavaScript and C++ code is
1129 // profiled. We must not suspend.
1130 if (!cpu_profiling_enabled) {
1131 if (rate_limiter_.SuspendIfNecessary()) continue;
1132 }
1133 if (cpu_profiling_enabled && runtime_profiler_enabled) {
1134 if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) {
1135 return;
1136 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001137 Sleep(HALF_INTERVAL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001138 if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) {
1139 return;
1140 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001141 Sleep(HALF_INTERVAL);
1142 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001143 if (cpu_profiling_enabled) {
1144 if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile,
1145 this)) {
1146 return;
1147 }
1148 }
1149 if (runtime_profiler_enabled) {
1150 if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile,
1151 NULL)) {
1152 return;
1153 }
1154 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001155 Sleep(FULL_INTERVAL);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001156 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001157 }
1158 }
1159
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001160 static void DoCpuProfile(Sampler* sampler, void* raw_sender) {
1161 if (!sampler->IsProfiling()) return;
1162 SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender);
1163 sender->SendProfilingSignal(sampler->platform_data()->vm_tid());
1164 }
1165
1166 static void DoRuntimeProfile(Sampler* sampler, void* ignored) {
1167 if (!sampler->isolate()->IsInitialized()) return;
1168 sampler->isolate()->runtime_profiler()->NotifyTick();
1169 }
1170
1171 void SendProfilingSignal(int tid) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001172 if (!signal_handler_installed_) return;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001173 // Glibc doesn't provide a wrapper for tgkill(2).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001174#if defined(ANDROID)
1175 syscall(__NR_tgkill, vm_tgid_, tid, SIGPROF);
1176#else
1177 syscall(SYS_tgkill, vm_tgid_, tid, SIGPROF);
1178#endif
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001179 }
1180
1181 void Sleep(SleepInterval full_or_half) {
1182 // Convert ms to us and subtract 100 us to compensate delays
1183 // occuring during signal delivery.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001184 useconds_t interval = interval_ * 1000 - 100;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001185 if (full_or_half == HALF_INTERVAL) interval /= 2;
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001186#if defined(ANDROID)
1187 usleep(interval);
1188#else
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001189 int result = usleep(interval);
1190#ifdef DEBUG
1191 if (result != 0 && errno != EINTR) {
1192 fprintf(stderr,
1193 "SignalSender usleep error; interval = %u, errno = %d\n",
1194 interval,
1195 errno);
1196 ASSERT(result == 0 || errno == EINTR);
1197 }
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001198#endif // DEBUG
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001199 USE(result);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001200#endif // ANDROID
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001201 }
1202
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001203 const int vm_tgid_;
1204 const int interval_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001205 RuntimeProfilerRateLimiter rate_limiter_;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001206
1207 // Protects the process wide state below.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001208 static Mutex* mutex_;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001209 static SignalSender* instance_;
1210 static bool signal_handler_installed_;
1211 static struct sigaction old_signal_handler_;
1212
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001213 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001214 DISALLOW_COPY_AND_ASSIGN(SignalSender);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215};
1216
1217
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001218Mutex* SignalSender::mutex_ = NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001219SignalSender* SignalSender::instance_ = NULL;
1220struct sigaction SignalSender::old_signal_handler_;
1221bool SignalSender::signal_handler_installed_ = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00001222
1223
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001224void OS::SetUp() {
1225 // Seed the random number generator. We preserve microsecond resolution.
1226 uint64_t seed = Ticks() ^ (getpid() << 16);
1227 srandom(static_cast<unsigned int>(seed));
1228 limit_mutex = CreateMutex();
1229
1230#ifdef __arm__
1231 // When running on ARM hardware check that the EABI used by V8 and
1232 // by the C code is the same.
1233 bool hard_float = OS::ArmUsingHardFloat();
1234 if (hard_float) {
1235#if !USE_EABI_HARDFLOAT
1236 PrintF("ERROR: Binary compiled with -mfloat-abi=hard but without "
1237 "-DUSE_EABI_HARDFLOAT\n");
1238 exit(1);
1239#endif
1240 } else {
1241#if USE_EABI_HARDFLOAT
1242 PrintF("ERROR: Binary not compiled with -mfloat-abi=hard but with "
1243 "-DUSE_EABI_HARDFLOAT\n");
1244 exit(1);
1245#endif
1246 }
1247#endif
1248 SignalSender::SetUp();
1249}
1250
1251
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001252void OS::TearDown() {
1253 SignalSender::TearDown();
1254 delete limit_mutex;
1255}
1256
1257
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001258Sampler::Sampler(Isolate* isolate, int interval)
1259 : isolate_(isolate),
1260 interval_(interval),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001261 profiling_(false),
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001262 active_(false),
1263 samples_taken_(0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001264 data_ = new PlatformData;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001265}
1266
1267
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001268Sampler::~Sampler() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001269 ASSERT(!IsActive());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001270 delete data_;
1271}
1272
1273
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001274void Sampler::Start() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001275 ASSERT(!IsActive());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001276 SetActive(true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001277 SignalSender::AddActiveSampler(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001278}
1279
1280
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001281void Sampler::Stop() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001282 ASSERT(IsActive());
1283 SignalSender::RemoveActiveSampler(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001284 SetActive(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001285}
1286
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001287
1288} } // namespace v8::internal