blob: ba72768a7ceb02a156e04a13a4178bd3ac4a9a57 [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
41#include <sys/mman.h> // mmap & munmap
42#include <sys/stat.h> // open
43#include <sys/fcntl.h> // open
44#include <unistd.h> // getpagesize
45#include <execinfo.h> // backtrace, backtrace_symbols
46#include <errno.h>
47#include <stdarg.h>
48
49#undef MAP_TYPE
50
51#include "v8.h"
52
53#include "platform.h"
54
55
56namespace v8 { namespace internal {
57
58// 0 is never a valid thread id on Linux since tids and pids share a
59// name space and pid 0 is reserved (see man 2 kill).
60static const pthread_t kNoThread = (pthread_t) 0;
61
62
63double ceiling(double x) {
64 return ceil(x);
65}
66
67
68void OS::Setup() {
69 // Seed the random number generator.
ager@chromium.org9258b6b2008-09-11 09:11:10 +000070 // Convert the current time to a 64-bit integer first, before converting it
71 // to an unsigned. Going directly can cause an overflow and the seed to be
72 // set to all ones. The seed will be identical for different instances that
73 // call this setup code within the same millisecond.
74 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
75 srandom(static_cast<unsigned int>(seed));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000076}
77
78
79int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) {
80 struct rusage usage;
81
82 if (getrusage(RUSAGE_SELF, &usage) < 0) return -1;
83 *secs = usage.ru_utime.tv_sec;
84 *usecs = usage.ru_utime.tv_usec;
85 return 0;
86}
87
88
89double OS::TimeCurrentMillis() {
90 struct timeval tv;
91 if (gettimeofday(&tv, NULL) < 0) return 0.0;
92 return (static_cast<double>(tv.tv_sec) * 1000) +
93 (static_cast<double>(tv.tv_usec) / 1000);
94}
95
96
97int64_t OS::Ticks() {
98 // Linux's gettimeofday has microsecond resolution.
99 struct timeval tv;
100 if (gettimeofday(&tv, NULL) < 0)
101 return 0;
102 return (static_cast<int64_t>(tv.tv_sec) * 1000000) + tv.tv_usec;
103}
104
105
106char* OS::LocalTimezone(double time) {
107 time_t tv = static_cast<time_t>(floor(time/msPerSecond));
108 struct tm* t = localtime(&tv);
109 return const_cast<char*>(t->tm_zone);
110}
111
112
113double OS::DaylightSavingsOffset(double time) {
114 time_t tv = static_cast<time_t>(floor(time/msPerSecond));
115 struct tm* t = localtime(&tv);
kasper.lund7276f142008-07-30 08:49:36 +0000116 return t->tm_isdst > 0 ? 3600 * msPerSecond : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000117}
118
119
120double OS::LocalTimeOffset() {
kasper.lund7276f142008-07-30 08:49:36 +0000121 time_t tv = time(NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000122 struct tm* t = localtime(&tv);
kasper.lund7276f142008-07-30 08:49:36 +0000123 // tm_gmtoff includes any daylight savings offset, so subtract it.
124 return static_cast<double>(t->tm_gmtoff * msPerSecond -
125 (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000126}
127
128
129void OS::Print(const char* format, ...) {
130 va_list args;
131 va_start(args, format);
132 VPrint(format, args);
133 va_end(args);
134}
135
136
137void OS::VPrint(const char* format, va_list args) {
138 vprintf(format, args);
139}
140
141
142void OS::PrintError(const char* format, ...) {
143 va_list args;
144 va_start(args, format);
145 VPrintError(format, args);
146 va_end(args);
147}
148
149
150void OS::VPrintError(const char* format, va_list args) {
151 vfprintf(stderr, format, args);
152}
153
154
155int OS::SNPrintF(char* str, size_t size, const char* format, ...) {
156 va_list args;
157 va_start(args, format);
158 int result = VSNPrintF(str, size, format, args);
159 va_end(args);
160 return result;
161}
162
163
164int OS::VSNPrintF(char* str, size_t size, const char* format, va_list args) {
kasper.lund7276f142008-07-30 08:49:36 +0000165 int n = vsnprintf(str, size, format, args); // forward to linux.
166 if (n < 0 || static_cast<size_t>(n) >= size) {
167 str[size - 1] = '\0';
168 return -1;
169 } else {
170 return n;
171 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000172}
173
174
175double OS::nan_value() { return NAN; }
176
177// We keep the lowest and highest addresses mapped as a quick way of
178// determining that pointers are outside the heap (used mostly in assertions
179// and verification). The estimate is conservative, ie, not all addresses in
180// 'allocated' space are actually allocated to our heap. The range is
181// [lowest, highest), inclusive on the low and and exclusive on the high end.
182static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
183static void* highest_ever_allocated = reinterpret_cast<void*>(0);
184
185
186static void UpdateAllocatedSpaceLimits(void* address, int size) {
187 lowest_ever_allocated = Min(lowest_ever_allocated, address);
188 highest_ever_allocated =
189 Max(highest_ever_allocated,
190 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
191}
192
193
194bool OS::IsOutsideAllocatedSpace(void* address) {
195 return address < lowest_ever_allocated || address >= highest_ever_allocated;
196}
197
198
199size_t OS::AllocateAlignment() {
200 return getpagesize();
201}
202
203
kasper.lund7276f142008-07-30 08:49:36 +0000204void* OS::Allocate(const size_t requested,
205 size_t* allocated,
206 bool executable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000207 const size_t msize = RoundUp(requested, getpagesize());
kasper.lund7276f142008-07-30 08:49:36 +0000208 int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
209 void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000210 if (mbase == MAP_FAILED) {
211 LOG(StringEvent("OS::Allocate", "mmap failed"));
212 return NULL;
213 }
214 *allocated = msize;
215 UpdateAllocatedSpaceLimits(mbase, msize);
216 return mbase;
217}
218
219
220void OS::Free(void* buf, const size_t length) {
221 // TODO(1240712): munmap has a return value which is ignored here.
222 munmap(buf, length);
223}
224
225
226void OS::Sleep(int milliseconds) {
227 unsigned int ms = static_cast<unsigned int>(milliseconds);
228 usleep(1000 * ms);
229}
230
231
232void OS::Abort() {
233 // Redirect to std abort to signal abnormal program termination.
234 abort();
235}
236
237
kasper.lund7276f142008-07-30 08:49:36 +0000238void OS::DebugBreak() {
239#if defined (__arm__) || defined(__thumb__)
240 asm("bkpt 0");
241#else
242 asm("int $3");
243#endif
244}
245
246
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000247class PosixMemoryMappedFile : public OS::MemoryMappedFile {
248 public:
249 PosixMemoryMappedFile(FILE* file, void* memory, int size)
250 : file_(file), memory_(memory), size_(size) { }
251 virtual ~PosixMemoryMappedFile();
252 virtual void* memory() { return memory_; }
253 private:
254 FILE* file_;
255 void* memory_;
256 int size_;
257};
258
259
260OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
261 void* initial) {
262 FILE* file = fopen(name, "w+");
263 if (file == NULL) return NULL;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000264 int result = fwrite(initial, size, 1, file);
265 if (result < 1) {
266 fclose(file);
267 return NULL;
268 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000269 void* memory =
270 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
271 return new PosixMemoryMappedFile(file, memory, size);
272}
273
274
275PosixMemoryMappedFile::~PosixMemoryMappedFile() {
276 if (memory_) munmap(memory_, size_);
277 fclose(file_);
278}
279
280#ifdef ENABLE_LOGGING_AND_PROFILING
281static unsigned StringToLongLong(char* buffer) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000282 return static_cast<unsigned>(strtoll(buffer, NULL, 16)); // NOLINT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000283}
284
285#endif
286
287void OS::LogSharedLibraryAddresses() {
288#ifdef ENABLE_LOGGING_AND_PROFILING
289 static const int MAP_LENGTH = 1024;
290 int fd = open("/proc/self/maps", O_RDONLY);
291 if (fd < 0) return;
292 while (true) {
293 char addr_buffer[11];
294 addr_buffer[0] = '0';
295 addr_buffer[1] = 'x';
296 addr_buffer[10] = 0;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000297 int result = read(fd, addr_buffer + 2, 8);
298 if (result < 8) break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000299 unsigned start = StringToLongLong(addr_buffer);
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000300 result = read(fd, addr_buffer + 2, 1);
301 if (result < 1) break;
302 if (addr_buffer[2] != '-') break;
303 result = read(fd, addr_buffer + 2, 8);
304 if (result < 8) break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000305 unsigned end = StringToLongLong(addr_buffer);
306 char buffer[MAP_LENGTH];
307 int bytes_read = -1;
308 do {
309 bytes_read++;
ager@chromium.orgc27e4e72008-09-04 13:52:27 +0000310 if (bytes_read >= MAP_LENGTH - 1)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000311 break;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000312 result = read(fd, buffer + bytes_read, 1);
313 if (result < 1) break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000314 } while (buffer[bytes_read] != '\n');
315 buffer[bytes_read] = 0;
316 // There are 56 chars to ignore at this point in the line.
317 if (bytes_read < 56) continue;
318 // Ignore mappings that are not executable.
319 if (buffer[3] != 'x') continue;
320 buffer[bytes_read] = 0;
321 LOG(SharedLibraryEvent(buffer + 56, start, end));
322 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000323 close(fd);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000324#endif
325}
326
327
328int OS::StackWalk(OS::StackFrame* frames, int frames_size) {
329 void** addresses = NewArray<void*>(frames_size);
330
331 int frames_count = backtrace(addresses, frames_size);
332
333 char** symbols;
334 symbols = backtrace_symbols(addresses, frames_count);
335 if (symbols == NULL) {
336 DeleteArray(addresses);
337 return kStackWalkError;
338 }
339
340 for (int i = 0; i < frames_count; i++) {
341 frames[i].address = addresses[i];
342 // Format a text representation of the frame based on the information
343 // available.
344 SNPrintF(frames[i].text, kStackWalkMaxTextLen, "%s", symbols[i]);
345 // Make sure line termination is in place.
346 frames[i].text[kStackWalkMaxTextLen - 1] = '\0';
347 }
348
349 DeleteArray(addresses);
350 free(symbols);
351
352 return frames_count;
353}
354
355
356// Constants used for mmap.
357static const int kMmapFd = -1;
358static const int kMmapFdOffset = 0;
359
360
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000361VirtualMemory::VirtualMemory(size_t size) {
362 address_ = mmap(NULL, size, PROT_NONE,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000363 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
364 kMmapFd, kMmapFdOffset);
365 size_ = size;
366}
367
368
369VirtualMemory::~VirtualMemory() {
370 if (IsReserved()) {
371 if (0 == munmap(address(), size())) address_ = MAP_FAILED;
372 }
373}
374
375
376bool VirtualMemory::IsReserved() {
377 return address_ != MAP_FAILED;
378}
379
380
kasper.lund7276f142008-07-30 08:49:36 +0000381bool VirtualMemory::Commit(void* address, size_t size, bool executable) {
382 int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
383 if (MAP_FAILED == mmap(address, size, prot,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000384 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
385 kMmapFd, kMmapFdOffset)) {
386 return false;
387 }
388
389 UpdateAllocatedSpaceLimits(address, size);
390 return true;
391}
392
393
394bool VirtualMemory::Uncommit(void* address, size_t size) {
395 return mmap(address, size, PROT_NONE,
396 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
397 kMmapFd, kMmapFdOffset) != MAP_FAILED;
398}
399
400
401class ThreadHandle::PlatformData : public Malloced {
402 public:
403 explicit PlatformData(ThreadHandle::Kind kind) {
404 Initialize(kind);
405 }
406
407 void Initialize(ThreadHandle::Kind kind) {
408 switch (kind) {
409 case ThreadHandle::SELF: thread_ = pthread_self(); break;
410 case ThreadHandle::INVALID: thread_ = kNoThread; break;
411 }
412 }
413 pthread_t thread_; // Thread handle for pthread.
414};
415
416
417ThreadHandle::ThreadHandle(Kind kind) {
418 data_ = new PlatformData(kind);
419}
420
421
422void ThreadHandle::Initialize(ThreadHandle::Kind kind) {
423 data_->Initialize(kind);
424}
425
426
427ThreadHandle::~ThreadHandle() {
428 delete data_;
429}
430
431
432bool ThreadHandle::IsSelf() const {
433 return pthread_equal(data_->thread_, pthread_self());
434}
435
436
437bool ThreadHandle::IsValid() const {
438 return data_->thread_ != kNoThread;
439}
440
441
442Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
443}
444
445
446Thread::~Thread() {
447}
448
449
450static void* ThreadEntry(void* arg) {
451 Thread* thread = reinterpret_cast<Thread*>(arg);
452 // This is also initialized by the first argument to pthread_create() but we
453 // don't know which thread will run first (the original thread or the new
454 // one) so we initialize it here too.
455 thread->thread_handle_data()->thread_ = pthread_self();
456 ASSERT(thread->IsValid());
457 thread->Run();
458 return NULL;
459}
460
461
462void Thread::Start() {
463 pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
464 ASSERT(IsValid());
465}
466
467
468void Thread::Join() {
469 pthread_join(thread_handle_data()->thread_, NULL);
470}
471
472
473Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
474 pthread_key_t key;
475 int result = pthread_key_create(&key, NULL);
476 USE(result);
477 ASSERT(result == 0);
478 return static_cast<LocalStorageKey>(key);
479}
480
481
482void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
483 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
484 int result = pthread_key_delete(pthread_key);
485 USE(result);
486 ASSERT(result == 0);
487}
488
489
490void* Thread::GetThreadLocal(LocalStorageKey key) {
491 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
492 return pthread_getspecific(pthread_key);
493}
494
495
496void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
497 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
498 pthread_setspecific(pthread_key, value);
499}
500
501
502void Thread::YieldCPU() {
503 sched_yield();
504}
505
506
507class LinuxMutex : public Mutex {
508 public:
509
510 LinuxMutex() {
511 pthread_mutexattr_t attrs;
512 int result = pthread_mutexattr_init(&attrs);
513 ASSERT(result == 0);
514 result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
515 ASSERT(result == 0);
516 result = pthread_mutex_init(&mutex_, &attrs);
517 ASSERT(result == 0);
518 }
519
520 virtual ~LinuxMutex() { pthread_mutex_destroy(&mutex_); }
521
522 virtual int Lock() {
523 int result = pthread_mutex_lock(&mutex_);
524 return result;
525 }
526
527 virtual int Unlock() {
528 int result = pthread_mutex_unlock(&mutex_);
529 return result;
530 }
531
532 private:
533 pthread_mutex_t mutex_; // Pthread mutex for POSIX platforms.
534};
535
536
537Mutex* OS::CreateMutex() {
538 return new LinuxMutex();
539}
540
541
542class LinuxSemaphore : public Semaphore {
543 public:
544 explicit LinuxSemaphore(int count) { sem_init(&sem_, 0, count); }
545 virtual ~LinuxSemaphore() { sem_destroy(&sem_); }
546
kasper.lund7276f142008-07-30 08:49:36 +0000547 virtual void Wait();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000548 virtual void Signal() { sem_post(&sem_); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000549 private:
550 sem_t sem_;
551};
552
kasper.lund7276f142008-07-30 08:49:36 +0000553void LinuxSemaphore::Wait() {
554 while (true) {
555 int result = sem_wait(&sem_);
556 if (result == 0) return; // Successfully got semaphore.
557 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
558 }
559}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000560
561Semaphore* OS::CreateSemaphore(int count) {
562 return new LinuxSemaphore(count);
563}
564
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000565#ifdef ENABLE_LOGGING_AND_PROFILING
566
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000567static Sampler* active_sampler_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000568
569static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
570 USE(info);
571 if (signal != SIGPROF) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000572 if (active_sampler_ == NULL) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000573
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000574 TickSample sample;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000575
576 // If profiling, we extract the current pc and sp.
577 if (active_sampler_->IsProfiling()) {
578 // Extracting the sample from the context is extremely machine dependent.
579 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
580 mcontext_t& mcontext = ucontext->uc_mcontext;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000581#if defined (__arm__) || defined(__thumb__)
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000582 sample.pc = mcontext.gregs[R15];
583 sample.sp = mcontext.gregs[R13];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000584#else
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000585 sample.pc = mcontext.gregs[REG_EIP];
586 sample.sp = mcontext.gregs[REG_ESP];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000587#endif
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000588 }
589
590 // We always sample the VM state.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000591 sample.state = Logger::state();
592
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000593 active_sampler_->Tick(&sample);
594}
595
596
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000597class Sampler::PlatformData : public Malloced {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000598 public:
599 PlatformData() {
600 signal_handler_installed_ = false;
601 }
602
603 bool signal_handler_installed_;
604 struct sigaction old_signal_handler_;
605 struct itimerval old_timer_value_;
606};
607
608
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000609Sampler::Sampler(int interval, bool profiling)
610 : interval_(interval), profiling_(profiling), active_(false) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000611 data_ = new PlatformData();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000612}
613
614
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000615Sampler::~Sampler() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000616 delete data_;
617}
618
619
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000620void Sampler::Start() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000621 // There can only be one active sampler at the time on POSIX
622 // platforms.
623 if (active_sampler_ != NULL) return;
624
625 // Request profiling signals.
626 struct sigaction sa;
627 sa.sa_sigaction = ProfilerSignalHandler;
628 sigemptyset(&sa.sa_mask);
629 sa.sa_flags = SA_SIGINFO;
630 if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return;
631 data_->signal_handler_installed_ = true;
632
633 // Set the itimer to generate a tick for each interval.
634 itimerval itimer;
635 itimer.it_interval.tv_sec = interval_ / 1000;
636 itimer.it_interval.tv_usec = (interval_ % 1000) * 1000;
637 itimer.it_value.tv_sec = itimer.it_interval.tv_sec;
638 itimer.it_value.tv_usec = itimer.it_interval.tv_usec;
639 setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_);
640
641 // Set this sampler as the active sampler.
642 active_sampler_ = this;
643 active_ = true;
644}
645
646
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000647void Sampler::Stop() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000648 // Restore old signal handler
649 if (data_->signal_handler_installed_) {
650 setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL);
651 sigaction(SIGPROF, &data_->old_signal_handler_, 0);
652 data_->signal_handler_installed_ = false;
653 }
654
655 // This sampler is no longer the active sampler.
656 active_sampler_ = NULL;
657 active_ = false;
658}
659
660#endif // ENABLE_LOGGING_AND_PROFILING
661
662} } // namespace v8::internal