blob: 46ca7dc68ce1c24d2999c1c093fa42456acbb313 [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
28// Platform specific code for Linux goes here
29
30#include <pthread.h>
31#include <semaphore.h>
32#include <signal.h>
33#include <sys/time.h>
34#include <sys/resource.h>
35#include <stdlib.h>
36
37// Ubuntu Dapper requires memory pages to be marked as
38// executable. Otherwise, OS raises an exception when executing code
39// in that page.
40#include <sys/types.h> // mmap & munmap
ager@chromium.org236ad962008-09-25 09:45:57 +000041#include <sys/mman.h> // mmap & munmap
42#include <sys/stat.h> // open
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043#include <sys/fcntl.h> // open
ager@chromium.org236ad962008-09-25 09:45:57 +000044#include <unistd.h> // getpagesize
45#include <execinfo.h> // backtrace, backtrace_symbols
46#include <strings.h> // index
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000047#include <errno.h>
48#include <stdarg.h>
49
50#undef MAP_TYPE
51
52#include "v8.h"
53
54#include "platform.h"
55
56
57namespace v8 { namespace internal {
58
59// 0 is never a valid thread id on Linux since tids and pids share a
60// name space and pid 0 is reserved (see man 2 kill).
61static const pthread_t kNoThread = (pthread_t) 0;
62
63
64double ceiling(double x) {
65 return ceil(x);
66}
67
68
69void OS::Setup() {
70 // Seed the random number generator.
ager@chromium.org9258b6b2008-09-11 09:11:10 +000071 // Convert the current time to a 64-bit integer first, before converting it
72 // to an unsigned. Going directly can cause an overflow and the seed to be
73 // set to all ones. The seed will be identical for different instances that
74 // call this setup code within the same millisecond.
75 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
76 srandom(static_cast<unsigned int>(seed));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000077}
78
79
80int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) {
81 struct rusage usage;
82
83 if (getrusage(RUSAGE_SELF, &usage) < 0) return -1;
84 *secs = usage.ru_utime.tv_sec;
85 *usecs = usage.ru_utime.tv_usec;
86 return 0;
87}
88
89
90double OS::TimeCurrentMillis() {
91 struct timeval tv;
92 if (gettimeofday(&tv, NULL) < 0) return 0.0;
93 return (static_cast<double>(tv.tv_sec) * 1000) +
94 (static_cast<double>(tv.tv_usec) / 1000);
95}
96
97
98int64_t OS::Ticks() {
99 // Linux's gettimeofday has microsecond resolution.
100 struct timeval tv;
101 if (gettimeofday(&tv, NULL) < 0)
102 return 0;
103 return (static_cast<int64_t>(tv.tv_sec) * 1000000) + tv.tv_usec;
104}
105
106
107char* OS::LocalTimezone(double time) {
108 time_t tv = static_cast<time_t>(floor(time/msPerSecond));
109 struct tm* t = localtime(&tv);
110 return const_cast<char*>(t->tm_zone);
111}
112
113
114double OS::DaylightSavingsOffset(double time) {
115 time_t tv = static_cast<time_t>(floor(time/msPerSecond));
116 struct tm* t = localtime(&tv);
kasper.lund7276f142008-07-30 08:49:36 +0000117 return t->tm_isdst > 0 ? 3600 * msPerSecond : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000118}
119
120
121double OS::LocalTimeOffset() {
kasper.lund7276f142008-07-30 08:49:36 +0000122 time_t tv = time(NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000123 struct tm* t = localtime(&tv);
kasper.lund7276f142008-07-30 08:49:36 +0000124 // tm_gmtoff includes any daylight savings offset, so subtract it.
125 return static_cast<double>(t->tm_gmtoff * msPerSecond -
126 (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000127}
128
129
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000130FILE* OS::FOpen(const char* path, const char* mode) {
131 return fopen(path, mode);
132}
133
134
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000135void OS::Print(const char* format, ...) {
136 va_list args;
137 va_start(args, format);
138 VPrint(format, args);
139 va_end(args);
140}
141
142
143void OS::VPrint(const char* format, va_list args) {
144 vprintf(format, args);
145}
146
147
148void OS::PrintError(const char* format, ...) {
149 va_list args;
150 va_start(args, format);
151 VPrintError(format, args);
152 va_end(args);
153}
154
155
156void OS::VPrintError(const char* format, va_list args) {
157 vfprintf(stderr, format, args);
158}
159
160
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000161int OS::SNPrintF(Vector<char> str, const char* format, ...) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000162 va_list args;
163 va_start(args, format);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000164 int result = VSNPrintF(str, format, args);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000165 va_end(args);
166 return result;
167}
168
169
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000170int OS::VSNPrintF(Vector<char> str,
171 const char* format,
172 va_list args) {
173 int n = vsnprintf(str.start(), str.length(), format, args);
174 if (n < 0 || n >= str.length()) {
175 str[str.length() - 1] = '\0';
kasper.lund7276f142008-07-30 08:49:36 +0000176 return -1;
177 } else {
178 return n;
179 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000180}
181
182
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000183void OS::StrNCpy(Vector<char> dest, const char* src, size_t n) {
184 strncpy(dest.start(), src, n);
185}
186
187
188void OS::WcsCpy(Vector<wchar_t> dest, const wchar_t* src) {
189 wcscpy(dest.start(), src);
190}
191
192
193char *OS::StrDup(const char* str) {
194 return strdup(str);
195}
196
197
ager@chromium.org236ad962008-09-25 09:45:57 +0000198double OS::nan_value() {
199 return NAN;
200}
201
202
203int OS::ActivationFrameAlignment() {
204 // No constraint on Linux.
205 return 0;
206}
207
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000208
209// We keep the lowest and highest addresses mapped as a quick way of
210// determining that pointers are outside the heap (used mostly in assertions
211// and verification). The estimate is conservative, ie, not all addresses in
212// 'allocated' space are actually allocated to our heap. The range is
213// [lowest, highest), inclusive on the low and and exclusive on the high end.
214static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
215static void* highest_ever_allocated = reinterpret_cast<void*>(0);
216
217
218static void UpdateAllocatedSpaceLimits(void* address, int size) {
219 lowest_ever_allocated = Min(lowest_ever_allocated, address);
220 highest_ever_allocated =
221 Max(highest_ever_allocated,
222 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
223}
224
225
226bool OS::IsOutsideAllocatedSpace(void* address) {
227 return address < lowest_ever_allocated || address >= highest_ever_allocated;
228}
229
230
231size_t OS::AllocateAlignment() {
232 return getpagesize();
233}
234
235
kasper.lund7276f142008-07-30 08:49:36 +0000236void* OS::Allocate(const size_t requested,
237 size_t* allocated,
238 bool executable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000239 const size_t msize = RoundUp(requested, getpagesize());
kasper.lund7276f142008-07-30 08:49:36 +0000240 int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
241 void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000242 if (mbase == MAP_FAILED) {
243 LOG(StringEvent("OS::Allocate", "mmap failed"));
244 return NULL;
245 }
246 *allocated = msize;
247 UpdateAllocatedSpaceLimits(mbase, msize);
248 return mbase;
249}
250
251
252void OS::Free(void* buf, const size_t length) {
253 // TODO(1240712): munmap has a return value which is ignored here.
254 munmap(buf, length);
255}
256
257
258void OS::Sleep(int milliseconds) {
259 unsigned int ms = static_cast<unsigned int>(milliseconds);
260 usleep(1000 * ms);
261}
262
263
264void OS::Abort() {
265 // Redirect to std abort to signal abnormal program termination.
266 abort();
267}
268
269
kasper.lund7276f142008-07-30 08:49:36 +0000270void OS::DebugBreak() {
271#if defined (__arm__) || defined(__thumb__)
272 asm("bkpt 0");
273#else
274 asm("int $3");
275#endif
276}
277
278
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000279class PosixMemoryMappedFile : public OS::MemoryMappedFile {
280 public:
281 PosixMemoryMappedFile(FILE* file, void* memory, int size)
282 : file_(file), memory_(memory), size_(size) { }
283 virtual ~PosixMemoryMappedFile();
284 virtual void* memory() { return memory_; }
285 private:
286 FILE* file_;
287 void* memory_;
288 int size_;
289};
290
291
292OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
293 void* initial) {
294 FILE* file = fopen(name, "w+");
295 if (file == NULL) return NULL;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000296 int result = fwrite(initial, size, 1, file);
297 if (result < 1) {
298 fclose(file);
299 return NULL;
300 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000301 void* memory =
302 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
303 return new PosixMemoryMappedFile(file, memory, size);
304}
305
306
307PosixMemoryMappedFile::~PosixMemoryMappedFile() {
308 if (memory_) munmap(memory_, size_);
309 fclose(file_);
310}
311
312#ifdef ENABLE_LOGGING_AND_PROFILING
313static unsigned StringToLongLong(char* buffer) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000314 return static_cast<unsigned>(strtoll(buffer, NULL, 16)); // NOLINT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000315}
316
317#endif
318
319void OS::LogSharedLibraryAddresses() {
320#ifdef ENABLE_LOGGING_AND_PROFILING
321 static const int MAP_LENGTH = 1024;
322 int fd = open("/proc/self/maps", O_RDONLY);
323 if (fd < 0) return;
324 while (true) {
325 char addr_buffer[11];
326 addr_buffer[0] = '0';
327 addr_buffer[1] = 'x';
328 addr_buffer[10] = 0;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000329 int result = read(fd, addr_buffer + 2, 8);
330 if (result < 8) break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000331 unsigned start = StringToLongLong(addr_buffer);
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000332 result = read(fd, addr_buffer + 2, 1);
333 if (result < 1) break;
334 if (addr_buffer[2] != '-') break;
335 result = read(fd, addr_buffer + 2, 8);
336 if (result < 8) break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000337 unsigned end = StringToLongLong(addr_buffer);
338 char buffer[MAP_LENGTH];
339 int bytes_read = -1;
340 do {
341 bytes_read++;
ager@chromium.orgc27e4e72008-09-04 13:52:27 +0000342 if (bytes_read >= MAP_LENGTH - 1)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000343 break;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000344 result = read(fd, buffer + bytes_read, 1);
345 if (result < 1) break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000346 } while (buffer[bytes_read] != '\n');
347 buffer[bytes_read] = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000348 // Ignore mappings that are not executable.
349 if (buffer[3] != 'x') continue;
ager@chromium.org236ad962008-09-25 09:45:57 +0000350 char* start_of_path = index(buffer, '/');
351 // There may be no filename in this line. Skip to next.
352 if (start_of_path == NULL) continue;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000353 buffer[bytes_read] = 0;
ager@chromium.org236ad962008-09-25 09:45:57 +0000354 LOG(SharedLibraryEvent(start_of_path, start, end));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000355 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000356 close(fd);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000357#endif
358}
359
360
361int OS::StackWalk(OS::StackFrame* frames, int frames_size) {
362 void** addresses = NewArray<void*>(frames_size);
363
364 int frames_count = backtrace(addresses, frames_size);
365
366 char** symbols;
367 symbols = backtrace_symbols(addresses, frames_count);
368 if (symbols == NULL) {
369 DeleteArray(addresses);
370 return kStackWalkError;
371 }
372
373 for (int i = 0; i < frames_count; i++) {
374 frames[i].address = addresses[i];
375 // Format a text representation of the frame based on the information
376 // available.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000377 SNPrintF(MutableCStrVector(frames[i].text, kStackWalkMaxTextLen),
378 "%s",
379 symbols[i]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000380 // Make sure line termination is in place.
381 frames[i].text[kStackWalkMaxTextLen - 1] = '\0';
382 }
383
384 DeleteArray(addresses);
385 free(symbols);
386
387 return frames_count;
388}
389
390
391// Constants used for mmap.
392static const int kMmapFd = -1;
393static const int kMmapFdOffset = 0;
394
395
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000396VirtualMemory::VirtualMemory(size_t size) {
397 address_ = mmap(NULL, size, PROT_NONE,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000398 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
399 kMmapFd, kMmapFdOffset);
400 size_ = size;
401}
402
403
404VirtualMemory::~VirtualMemory() {
405 if (IsReserved()) {
406 if (0 == munmap(address(), size())) address_ = MAP_FAILED;
407 }
408}
409
410
411bool VirtualMemory::IsReserved() {
412 return address_ != MAP_FAILED;
413}
414
415
kasper.lund7276f142008-07-30 08:49:36 +0000416bool VirtualMemory::Commit(void* address, size_t size, bool executable) {
417 int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
418 if (MAP_FAILED == mmap(address, size, prot,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000419 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
420 kMmapFd, kMmapFdOffset)) {
421 return false;
422 }
423
424 UpdateAllocatedSpaceLimits(address, size);
425 return true;
426}
427
428
429bool VirtualMemory::Uncommit(void* address, size_t size) {
430 return mmap(address, size, PROT_NONE,
431 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
432 kMmapFd, kMmapFdOffset) != MAP_FAILED;
433}
434
435
436class ThreadHandle::PlatformData : public Malloced {
437 public:
438 explicit PlatformData(ThreadHandle::Kind kind) {
439 Initialize(kind);
440 }
441
442 void Initialize(ThreadHandle::Kind kind) {
443 switch (kind) {
444 case ThreadHandle::SELF: thread_ = pthread_self(); break;
445 case ThreadHandle::INVALID: thread_ = kNoThread; break;
446 }
447 }
448 pthread_t thread_; // Thread handle for pthread.
449};
450
451
452ThreadHandle::ThreadHandle(Kind kind) {
453 data_ = new PlatformData(kind);
454}
455
456
457void ThreadHandle::Initialize(ThreadHandle::Kind kind) {
458 data_->Initialize(kind);
459}
460
461
462ThreadHandle::~ThreadHandle() {
463 delete data_;
464}
465
466
467bool ThreadHandle::IsSelf() const {
468 return pthread_equal(data_->thread_, pthread_self());
469}
470
471
472bool ThreadHandle::IsValid() const {
473 return data_->thread_ != kNoThread;
474}
475
476
477Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
478}
479
480
481Thread::~Thread() {
482}
483
484
485static void* ThreadEntry(void* arg) {
486 Thread* thread = reinterpret_cast<Thread*>(arg);
487 // This is also initialized by the first argument to pthread_create() but we
488 // don't know which thread will run first (the original thread or the new
489 // one) so we initialize it here too.
490 thread->thread_handle_data()->thread_ = pthread_self();
491 ASSERT(thread->IsValid());
492 thread->Run();
493 return NULL;
494}
495
496
497void Thread::Start() {
498 pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
499 ASSERT(IsValid());
500}
501
502
503void Thread::Join() {
504 pthread_join(thread_handle_data()->thread_, NULL);
505}
506
507
508Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
509 pthread_key_t key;
510 int result = pthread_key_create(&key, NULL);
511 USE(result);
512 ASSERT(result == 0);
513 return static_cast<LocalStorageKey>(key);
514}
515
516
517void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
518 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
519 int result = pthread_key_delete(pthread_key);
520 USE(result);
521 ASSERT(result == 0);
522}
523
524
525void* Thread::GetThreadLocal(LocalStorageKey key) {
526 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
527 return pthread_getspecific(pthread_key);
528}
529
530
531void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
532 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
533 pthread_setspecific(pthread_key, value);
534}
535
536
537void Thread::YieldCPU() {
538 sched_yield();
539}
540
541
542class LinuxMutex : public Mutex {
543 public:
544
545 LinuxMutex() {
546 pthread_mutexattr_t attrs;
547 int result = pthread_mutexattr_init(&attrs);
548 ASSERT(result == 0);
549 result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
550 ASSERT(result == 0);
551 result = pthread_mutex_init(&mutex_, &attrs);
552 ASSERT(result == 0);
553 }
554
555 virtual ~LinuxMutex() { pthread_mutex_destroy(&mutex_); }
556
557 virtual int Lock() {
558 int result = pthread_mutex_lock(&mutex_);
559 return result;
560 }
561
562 virtual int Unlock() {
563 int result = pthread_mutex_unlock(&mutex_);
564 return result;
565 }
566
567 private:
568 pthread_mutex_t mutex_; // Pthread mutex for POSIX platforms.
569};
570
571
572Mutex* OS::CreateMutex() {
573 return new LinuxMutex();
574}
575
576
577class LinuxSemaphore : public Semaphore {
578 public:
579 explicit LinuxSemaphore(int count) { sem_init(&sem_, 0, count); }
580 virtual ~LinuxSemaphore() { sem_destroy(&sem_); }
581
kasper.lund7276f142008-07-30 08:49:36 +0000582 virtual void Wait();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000583 virtual void Signal() { sem_post(&sem_); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000584 private:
585 sem_t sem_;
586};
587
kasper.lund7276f142008-07-30 08:49:36 +0000588void LinuxSemaphore::Wait() {
589 while (true) {
590 int result = sem_wait(&sem_);
591 if (result == 0) return; // Successfully got semaphore.
592 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
593 }
594}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000595
596Semaphore* OS::CreateSemaphore(int count) {
597 return new LinuxSemaphore(count);
598}
599
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000600#ifdef ENABLE_LOGGING_AND_PROFILING
601
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000602static Sampler* active_sampler_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000603
604static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
605 USE(info);
606 if (signal != SIGPROF) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000607 if (active_sampler_ == NULL) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000608
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000609 TickSample sample;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000610
611 // If profiling, we extract the current pc and sp.
612 if (active_sampler_->IsProfiling()) {
613 // Extracting the sample from the context is extremely machine dependent.
614 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
615 mcontext_t& mcontext = ucontext->uc_mcontext;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000616#if defined (__arm__) || defined(__thumb__)
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000617 sample.pc = mcontext.gregs[R15];
618 sample.sp = mcontext.gregs[R13];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000619#else
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000620 sample.pc = mcontext.gregs[REG_EIP];
621 sample.sp = mcontext.gregs[REG_ESP];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000622#endif
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000623 }
624
625 // We always sample the VM state.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000626 sample.state = Logger::state();
627
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000628 active_sampler_->Tick(&sample);
629}
630
631
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000632class Sampler::PlatformData : public Malloced {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000633 public:
634 PlatformData() {
635 signal_handler_installed_ = false;
636 }
637
638 bool signal_handler_installed_;
639 struct sigaction old_signal_handler_;
640 struct itimerval old_timer_value_;
641};
642
643
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000644Sampler::Sampler(int interval, bool profiling)
645 : interval_(interval), profiling_(profiling), active_(false) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000646 data_ = new PlatformData();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000647}
648
649
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000650Sampler::~Sampler() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000651 delete data_;
652}
653
654
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000655void Sampler::Start() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000656 // There can only be one active sampler at the time on POSIX
657 // platforms.
658 if (active_sampler_ != NULL) return;
659
660 // Request profiling signals.
661 struct sigaction sa;
662 sa.sa_sigaction = ProfilerSignalHandler;
663 sigemptyset(&sa.sa_mask);
664 sa.sa_flags = SA_SIGINFO;
665 if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return;
666 data_->signal_handler_installed_ = true;
667
668 // Set the itimer to generate a tick for each interval.
669 itimerval itimer;
670 itimer.it_interval.tv_sec = interval_ / 1000;
671 itimer.it_interval.tv_usec = (interval_ % 1000) * 1000;
672 itimer.it_value.tv_sec = itimer.it_interval.tv_sec;
673 itimer.it_value.tv_usec = itimer.it_interval.tv_usec;
674 setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_);
675
676 // Set this sampler as the active sampler.
677 active_sampler_ = this;
678 active_ = true;
679}
680
681
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000682void Sampler::Stop() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000683 // Restore old signal handler
684 if (data_->signal_handler_installed_) {
685 setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL);
686 sigaction(SIGPROF, &data_->old_signal_handler_, 0);
687 data_->signal_handler_installed_ = false;
688 }
689
690 // This sampler is no longer the active sampler.
691 active_sampler_ = NULL;
692 active_ = false;
693}
694
695#endif // ENABLE_LOGGING_AND_PROFILING
696
697} } // namespace v8::internal