blob: 6ec5070f911c787973b838bc28d549ca5c29a730 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 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>
34#include <sys/time.h>
35#include <sys/resource.h>
ager@chromium.org381abbb2009-02-25 13:23:22 +000036#include <sys/types.h>
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include <stdlib.h>
38
39// Ubuntu Dapper requires memory pages to be marked as
40// executable. Otherwise, OS raises an exception when executing code
41// in that page.
42#include <sys/types.h> // mmap & munmap
ager@chromium.org236ad962008-09-25 09:45:57 +000043#include <sys/mman.h> // mmap & munmap
44#include <sys/stat.h> // open
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000045#include <fcntl.h> // open
46#include <unistd.h> // sysconf
47#ifdef __GLIBC__
ager@chromium.org236ad962008-09-25 09:45:57 +000048#include <execinfo.h> // backtrace, backtrace_symbols
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000049#endif // def __GLIBC__
ager@chromium.org236ad962008-09-25 09:45:57 +000050#include <strings.h> // index
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000051#include <errno.h>
52#include <stdarg.h>
53
54#undef MAP_TYPE
55
56#include "v8.h"
57
58#include "platform.h"
59
60
kasperl@chromium.org71affb52009-05-26 05:44:31 +000061namespace v8 {
62namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000063
64// 0 is never a valid thread id on Linux since tids and pids share a
65// name space and pid 0 is reserved (see man 2 kill).
66static const pthread_t kNoThread = (pthread_t) 0;
67
68
69double ceiling(double x) {
70 return ceil(x);
71}
72
73
74void OS::Setup() {
75 // Seed the random number generator.
ager@chromium.org9258b6b2008-09-11 09:11:10 +000076 // Convert the current time to a 64-bit integer first, before converting it
77 // to an unsigned. Going directly can cause an overflow and the seed to be
78 // set to all ones. The seed will be identical for different instances that
79 // call this setup code within the same millisecond.
80 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
81 srandom(static_cast<unsigned int>(seed));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000082}
83
84
ager@chromium.org236ad962008-09-25 09:45:57 +000085double OS::nan_value() {
86 return NAN;
87}
88
89
90int OS::ActivationFrameAlignment() {
ager@chromium.orge2902be2009-06-08 12:21:35 +000091#ifdef V8_TARGET_ARCH_ARM
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +000092 // On EABI ARM targets this is required for fp correctness in the
93 // runtime system.
ager@chromium.org3a6061e2009-03-12 14:24:36 +000094 return 8;
ager@chromium.orge2902be2009-06-08 12:21:35 +000095#else
96 // With gcc 4.4 the tree vectorization optimiser can generate code
97 // that requires 16 byte alignment such as movdqa on x86.
98 return 16;
99#endif
ager@chromium.org236ad962008-09-25 09:45:57 +0000100}
101
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000102
103// We keep the lowest and highest addresses mapped as a quick way of
104// determining that pointers are outside the heap (used mostly in assertions
105// and verification). The estimate is conservative, ie, not all addresses in
106// 'allocated' space are actually allocated to our heap. The range is
107// [lowest, highest), inclusive on the low and and exclusive on the high end.
108static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
109static void* highest_ever_allocated = reinterpret_cast<void*>(0);
110
111
112static void UpdateAllocatedSpaceLimits(void* address, int size) {
113 lowest_ever_allocated = Min(lowest_ever_allocated, address);
114 highest_ever_allocated =
115 Max(highest_ever_allocated,
116 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
117}
118
119
120bool OS::IsOutsideAllocatedSpace(void* address) {
121 return address < lowest_ever_allocated || address >= highest_ever_allocated;
122}
123
124
125size_t OS::AllocateAlignment() {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000126 return sysconf(_SC_PAGESIZE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000127}
128
129
kasper.lund7276f142008-07-30 08:49:36 +0000130void* OS::Allocate(const size_t requested,
131 size_t* allocated,
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000132 bool is_executable) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000133 const size_t msize = RoundUp(requested, sysconf(_SC_PAGESIZE));
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000134 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
kasper.lund7276f142008-07-30 08:49:36 +0000135 void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000136 if (mbase == MAP_FAILED) {
137 LOG(StringEvent("OS::Allocate", "mmap failed"));
138 return NULL;
139 }
140 *allocated = msize;
141 UpdateAllocatedSpaceLimits(mbase, msize);
142 return mbase;
143}
144
145
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000146void OS::Free(void* address, const size_t size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000147 // TODO(1240712): munmap has a return value which is ignored here.
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000148 munmap(address, size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000149}
150
151
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000152#ifdef ENABLE_HEAP_PROTECTION
153
154void OS::Protect(void* address, size_t size) {
155 // TODO(1240712): mprotect has a return value which is ignored here.
156 mprotect(address, size, PROT_READ);
157}
158
159
160void OS::Unprotect(void* address, size_t size, bool is_executable) {
161 // TODO(1240712): mprotect has a return value which is ignored here.
162 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
163 mprotect(address, size, prot);
164}
165
166#endif
167
168
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000169void OS::Sleep(int milliseconds) {
170 unsigned int ms = static_cast<unsigned int>(milliseconds);
171 usleep(1000 * ms);
172}
173
174
175void OS::Abort() {
176 // Redirect to std abort to signal abnormal program termination.
177 abort();
178}
179
180
kasper.lund7276f142008-07-30 08:49:36 +0000181void OS::DebugBreak() {
ager@chromium.org5ec48922009-05-05 07:25:34 +0000182// TODO(lrn): Introduce processor define for runtime system (!= V8_ARCH_x,
183// which is the architecture of generated code).
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000184#if defined(__arm__) || defined(__thumb__)
kasper.lund7276f142008-07-30 08:49:36 +0000185 asm("bkpt 0");
186#else
187 asm("int $3");
188#endif
189}
190
191
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000192class PosixMemoryMappedFile : public OS::MemoryMappedFile {
193 public:
194 PosixMemoryMappedFile(FILE* file, void* memory, int size)
195 : file_(file), memory_(memory), size_(size) { }
196 virtual ~PosixMemoryMappedFile();
197 virtual void* memory() { return memory_; }
198 private:
199 FILE* file_;
200 void* memory_;
201 int size_;
202};
203
204
205OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
206 void* initial) {
207 FILE* file = fopen(name, "w+");
208 if (file == NULL) return NULL;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000209 int result = fwrite(initial, size, 1, file);
210 if (result < 1) {
211 fclose(file);
212 return NULL;
213 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000214 void* memory =
215 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
216 return new PosixMemoryMappedFile(file, memory, size);
217}
218
219
220PosixMemoryMappedFile::~PosixMemoryMappedFile() {
221 if (memory_) munmap(memory_, size_);
222 fclose(file_);
223}
224
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000225
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000226void OS::LogSharedLibraryAddresses() {
227#ifdef ENABLE_LOGGING_AND_PROFILING
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000228 // This function assumes that the layout of the file is as follows:
229 // hex_start_addr-hex_end_addr rwxp <unused data> [binary_file_name]
230 // If we encounter an unexpected situation we abort scanning further entries.
231 FILE *fp = fopen("/proc/self/maps", "r");
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000232 if (fp == NULL) return;
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000233
234 // Allocate enough room to be able to store a full file name.
235 const int kLibNameLen = FILENAME_MAX + 1;
236 char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen));
237
238 // This loop will terminate once the scanning hits an EOF.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000239 while (true) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000240 uintptr_t start, end;
241 char attr_r, attr_w, attr_x, attr_p;
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000242 // Parse the addresses and permission bits at the beginning of the line.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000243 if (fscanf(fp, "%" V8PRIxPTR "-%" V8PRIxPTR, &start, &end) != 2) break;
244 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 +0000245
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000246 int c;
247 if (attr_r == 'r' && attr_x == 'x') {
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000248 // Found a readable and executable entry. Skip characters until we reach
249 // the beginning of the filename or the end of the line.
250 do {
251 c = getc(fp);
252 } while ((c != EOF) && (c != '\n') && (c != '/'));
253 if (c == EOF) break; // EOF: Was unexpected, just exit.
254
255 // Process the filename if found.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000256 if (c == '/') {
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000257 ungetc(c, fp); // Push the '/' back into the stream to be read below.
258
259 // Read to the end of the line. Exit if the read fails.
260 if (fgets(lib_name, kLibNameLen, fp) == NULL) break;
261
262 // Drop the newline character read by fgets. We do not need to check
263 // for a zero-length string because we know that we at least read the
264 // '/' character.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000265 lib_name[strlen(lib_name) - 1] = '\0';
266 } else {
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000267 // No library name found, just record the raw address range.
268 snprintf(lib_name, kLibNameLen,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000269 "%08" V8PRIxPTR "-%08" V8PRIxPTR, start, end);
270 }
271 LOG(SharedLibraryEvent(lib_name, start, end));
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000272 } else {
273 // Entry not describing executable data. Skip to end of line to setup
274 // reading the next entry.
275 do {
276 c = getc(fp);
277 } while ((c != EOF) && (c != '\n'));
278 if (c == EOF) break;
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000279 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000280 }
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000281 free(lib_name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000282 fclose(fp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000283#endif
284}
285
286
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000287int OS::StackWalk(Vector<OS::StackFrame> frames) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000288 // backtrace is a glibc extension.
289#ifdef __GLIBC__
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000290 int frames_size = frames.length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000291 void** addresses = NewArray<void*>(frames_size);
292
293 int frames_count = backtrace(addresses, frames_size);
294
295 char** symbols;
296 symbols = backtrace_symbols(addresses, frames_count);
297 if (symbols == NULL) {
298 DeleteArray(addresses);
299 return kStackWalkError;
300 }
301
302 for (int i = 0; i < frames_count; i++) {
303 frames[i].address = addresses[i];
304 // Format a text representation of the frame based on the information
305 // available.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000306 SNPrintF(MutableCStrVector(frames[i].text, kStackWalkMaxTextLen),
307 "%s",
308 symbols[i]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000309 // Make sure line termination is in place.
310 frames[i].text[kStackWalkMaxTextLen - 1] = '\0';
311 }
312
313 DeleteArray(addresses);
314 free(symbols);
315
316 return frames_count;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000317#else // ndef __GLIBC__
318 return 0;
319#endif // ndef __GLIBC__
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000320}
321
322
323// Constants used for mmap.
324static const int kMmapFd = -1;
325static const int kMmapFdOffset = 0;
326
327
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000328VirtualMemory::VirtualMemory(size_t size) {
329 address_ = mmap(NULL, size, PROT_NONE,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000330 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
331 kMmapFd, kMmapFdOffset);
332 size_ = size;
333}
334
335
336VirtualMemory::~VirtualMemory() {
337 if (IsReserved()) {
338 if (0 == munmap(address(), size())) address_ = MAP_FAILED;
339 }
340}
341
342
343bool VirtualMemory::IsReserved() {
344 return address_ != MAP_FAILED;
345}
346
347
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000348bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
349 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
kasper.lund7276f142008-07-30 08:49:36 +0000350 if (MAP_FAILED == mmap(address, size, prot,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000351 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
352 kMmapFd, kMmapFdOffset)) {
353 return false;
354 }
355
356 UpdateAllocatedSpaceLimits(address, size);
357 return true;
358}
359
360
361bool VirtualMemory::Uncommit(void* address, size_t size) {
362 return mmap(address, size, PROT_NONE,
363 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
364 kMmapFd, kMmapFdOffset) != MAP_FAILED;
365}
366
367
368class ThreadHandle::PlatformData : public Malloced {
369 public:
370 explicit PlatformData(ThreadHandle::Kind kind) {
371 Initialize(kind);
372 }
373
374 void Initialize(ThreadHandle::Kind kind) {
375 switch (kind) {
376 case ThreadHandle::SELF: thread_ = pthread_self(); break;
377 case ThreadHandle::INVALID: thread_ = kNoThread; break;
378 }
379 }
ager@chromium.org41826e72009-03-30 13:30:57 +0000380
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000381 pthread_t thread_; // Thread handle for pthread.
382};
383
384
385ThreadHandle::ThreadHandle(Kind kind) {
386 data_ = new PlatformData(kind);
387}
388
389
390void ThreadHandle::Initialize(ThreadHandle::Kind kind) {
391 data_->Initialize(kind);
392}
393
394
395ThreadHandle::~ThreadHandle() {
396 delete data_;
397}
398
399
400bool ThreadHandle::IsSelf() const {
401 return pthread_equal(data_->thread_, pthread_self());
402}
403
404
405bool ThreadHandle::IsValid() const {
406 return data_->thread_ != kNoThread;
407}
408
409
410Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
411}
412
413
414Thread::~Thread() {
415}
416
417
418static void* ThreadEntry(void* arg) {
419 Thread* thread = reinterpret_cast<Thread*>(arg);
420 // This is also initialized by the first argument to pthread_create() but we
421 // don't know which thread will run first (the original thread or the new
422 // one) so we initialize it here too.
423 thread->thread_handle_data()->thread_ = pthread_self();
424 ASSERT(thread->IsValid());
425 thread->Run();
426 return NULL;
427}
428
429
430void Thread::Start() {
431 pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
432 ASSERT(IsValid());
433}
434
435
436void Thread::Join() {
437 pthread_join(thread_handle_data()->thread_, NULL);
438}
439
440
441Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
442 pthread_key_t key;
443 int result = pthread_key_create(&key, NULL);
444 USE(result);
445 ASSERT(result == 0);
446 return static_cast<LocalStorageKey>(key);
447}
448
449
450void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
451 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
452 int result = pthread_key_delete(pthread_key);
453 USE(result);
454 ASSERT(result == 0);
455}
456
457
458void* Thread::GetThreadLocal(LocalStorageKey key) {
459 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
460 return pthread_getspecific(pthread_key);
461}
462
463
464void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
465 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
466 pthread_setspecific(pthread_key, value);
467}
468
469
470void Thread::YieldCPU() {
471 sched_yield();
472}
473
474
475class LinuxMutex : public Mutex {
476 public:
477
478 LinuxMutex() {
479 pthread_mutexattr_t attrs;
480 int result = pthread_mutexattr_init(&attrs);
481 ASSERT(result == 0);
482 result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
483 ASSERT(result == 0);
484 result = pthread_mutex_init(&mutex_, &attrs);
485 ASSERT(result == 0);
486 }
487
488 virtual ~LinuxMutex() { pthread_mutex_destroy(&mutex_); }
489
490 virtual int Lock() {
491 int result = pthread_mutex_lock(&mutex_);
492 return result;
493 }
494
495 virtual int Unlock() {
496 int result = pthread_mutex_unlock(&mutex_);
497 return result;
498 }
499
500 private:
501 pthread_mutex_t mutex_; // Pthread mutex for POSIX platforms.
502};
503
504
505Mutex* OS::CreateMutex() {
506 return new LinuxMutex();
507}
508
509
510class LinuxSemaphore : public Semaphore {
511 public:
512 explicit LinuxSemaphore(int count) { sem_init(&sem_, 0, count); }
513 virtual ~LinuxSemaphore() { sem_destroy(&sem_); }
514
kasper.lund7276f142008-07-30 08:49:36 +0000515 virtual void Wait();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000516 virtual bool Wait(int timeout);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000517 virtual void Signal() { sem_post(&sem_); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000518 private:
519 sem_t sem_;
520};
521
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000522
kasper.lund7276f142008-07-30 08:49:36 +0000523void LinuxSemaphore::Wait() {
524 while (true) {
525 int result = sem_wait(&sem_);
526 if (result == 0) return; // Successfully got semaphore.
527 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
528 }
529}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000530
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000531
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000532#ifndef TIMEVAL_TO_TIMESPEC
533#define TIMEVAL_TO_TIMESPEC(tv, ts) do { \
534 (ts)->tv_sec = (tv)->tv_sec; \
535 (ts)->tv_nsec = (tv)->tv_usec * 1000; \
536} while (false)
537#endif
538
539
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000540bool LinuxSemaphore::Wait(int timeout) {
541 const long kOneSecondMicros = 1000000; // NOLINT
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000542
543 // Split timeout into second and nanosecond parts.
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000544 struct timeval delta;
545 delta.tv_usec = timeout % kOneSecondMicros;
546 delta.tv_sec = timeout / kOneSecondMicros;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000547
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000548 struct timeval current_time;
549 // Get the current time.
550 if (gettimeofday(&current_time, NULL) == -1) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000551 return false;
552 }
553
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000554 // Calculate time for end of timeout.
555 struct timeval end_time;
556 timeradd(&current_time, &delta, &end_time);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000557
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000558 struct timespec ts;
559 TIMEVAL_TO_TIMESPEC(&end_time, &ts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000560 // Wait for semaphore signalled or timeout.
561 while (true) {
562 int result = sem_timedwait(&sem_, &ts);
563 if (result == 0) return true; // Successfully got semaphore.
564 if (result > 0) {
565 // For glibc prior to 2.3.4 sem_timedwait returns the error instead of -1.
566 errno = result;
567 result = -1;
568 }
569 if (result == -1 && errno == ETIMEDOUT) return false; // Timeout.
570 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
571 }
572}
573
574
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000575Semaphore* OS::CreateSemaphore(int count) {
576 return new LinuxSemaphore(count);
577}
578
ager@chromium.org381abbb2009-02-25 13:23:22 +0000579
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000580#ifdef ENABLE_LOGGING_AND_PROFILING
581
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000582static Sampler* active_sampler_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000583
kasperl@chromium.orgacae3782009-04-11 09:17:08 +0000584
585#if !defined(__GLIBC__) && (defined(__arm__) || defined(__thumb__))
586// Android runs a fairly new Linux kernel, so signal info is there,
587// but the C library doesn't have the structs defined.
588
589struct sigcontext {
590 uint32_t trap_no;
591 uint32_t error_code;
592 uint32_t oldmask;
593 uint32_t gregs[16];
594 uint32_t arm_cpsr;
595 uint32_t fault_address;
596};
597typedef uint32_t __sigset_t;
598typedef struct sigcontext mcontext_t;
599typedef struct ucontext {
600 uint32_t uc_flags;
601 struct ucontext *uc_link;
602 stack_t uc_stack;
603 mcontext_t uc_mcontext;
604 __sigset_t uc_sigmask;
605} ucontext_t;
606enum ArmRegisters {R15 = 15, R13 = 13, R11 = 11};
607
608#endif
609
610
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000611static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
612 USE(info);
613 if (signal != SIGPROF) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000614 if (active_sampler_ == NULL) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000615
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000616 TickSample sample;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000617
618 // If profiling, we extract the current pc and sp.
619 if (active_sampler_->IsProfiling()) {
620 // Extracting the sample from the context is extremely machine dependent.
621 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
622 mcontext_t& mcontext = ucontext->uc_mcontext;
ager@chromium.org9085a012009-05-11 19:22:57 +0000623#if V8_HOST_ARCH_IA32
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000624 sample.pc = mcontext.gregs[REG_EIP];
625 sample.sp = mcontext.gregs[REG_ESP];
ager@chromium.org381abbb2009-02-25 13:23:22 +0000626 sample.fp = mcontext.gregs[REG_EBP];
ager@chromium.org9085a012009-05-11 19:22:57 +0000627#elif V8_HOST_ARCH_X64
628 sample.pc = mcontext.gregs[REG_RIP];
629 sample.sp = mcontext.gregs[REG_RSP];
630 sample.fp = mcontext.gregs[REG_RBP];
631#elif V8_HOST_ARCH_ARM
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000632// An undefined macro evaluates to 0, so this applies to Android's Bionic also.
633#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
ager@chromium.org9085a012009-05-11 19:22:57 +0000634 sample.pc = mcontext.gregs[R15];
635 sample.sp = mcontext.gregs[R13];
636 sample.fp = mcontext.gregs[R11];
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000637#else
638 sample.pc = mcontext.arm_pc;
639 sample.sp = mcontext.arm_sp;
640 sample.fp = mcontext.arm_fp;
641#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000642#endif
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000643 active_sampler_->SampleStack(&sample);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000644 }
645
646 // We always sample the VM state.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000647 sample.state = Logger::state();
648
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000649 active_sampler_->Tick(&sample);
650}
651
652
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000653class Sampler::PlatformData : public Malloced {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000654 public:
655 PlatformData() {
656 signal_handler_installed_ = false;
657 }
658
659 bool signal_handler_installed_;
660 struct sigaction old_signal_handler_;
661 struct itimerval old_timer_value_;
662};
663
664
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000665Sampler::Sampler(int interval, bool profiling)
666 : interval_(interval), profiling_(profiling), active_(false) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000667 data_ = new PlatformData();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000668}
669
670
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000671Sampler::~Sampler() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000672 delete data_;
673}
674
675
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000676void Sampler::Start() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000677 // There can only be one active sampler at the time on POSIX
678 // platforms.
679 if (active_sampler_ != NULL) return;
680
681 // Request profiling signals.
682 struct sigaction sa;
683 sa.sa_sigaction = ProfilerSignalHandler;
684 sigemptyset(&sa.sa_mask);
685 sa.sa_flags = SA_SIGINFO;
686 if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return;
687 data_->signal_handler_installed_ = true;
688
689 // Set the itimer to generate a tick for each interval.
690 itimerval itimer;
691 itimer.it_interval.tv_sec = interval_ / 1000;
692 itimer.it_interval.tv_usec = (interval_ % 1000) * 1000;
693 itimer.it_value.tv_sec = itimer.it_interval.tv_sec;
694 itimer.it_value.tv_usec = itimer.it_interval.tv_usec;
695 setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_);
696
697 // Set this sampler as the active sampler.
698 active_sampler_ = this;
699 active_ = true;
700}
701
702
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000703void Sampler::Stop() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000704 // Restore old signal handler
705 if (data_->signal_handler_installed_) {
706 setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL);
707 sigaction(SIGPROF, &data_->old_signal_handler_, 0);
708 data_->signal_handler_installed_ = false;
709 }
710
711 // This sampler is no longer the active sampler.
712 active_sampler_ = NULL;
713 active_ = false;
714}
715
716#endif // ENABLE_LOGGING_AND_PROFILING
717
718} } // namespace v8::internal