blob: dc4493aab9f0e0e323fb868618e2234f5d9e5428 [file] [log] [blame]
Leon Clarked91b9f72010-01-27 17:25:45 +00001// Copyright 2006-2009 the V8 project authors. All rights reserved.
2// 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 Solaris 10 goes here. For the POSIX comaptible
29// parts the implementation is in platform-posix.cc.
30
31#ifdef __sparc
32# error "V8 does not support the SPARC CPU architecture."
33#endif
34
35#include <sys/stack.h> // for stack alignment
36#include <unistd.h> // getpagesize(), usleep()
37#include <sys/mman.h> // mmap()
Leon Clarkef7060e22010-06-03 12:02:55 +010038#include <ucontext.h> // walkstack(), getcontext()
39#include <dlfcn.h> // dladdr
Leon Clarked91b9f72010-01-27 17:25:45 +000040#include <pthread.h>
41#include <sched.h> // for sched_yield
42#include <semaphore.h>
43#include <time.h>
44#include <sys/time.h> // gettimeofday(), timeradd()
45#include <errno.h>
46#include <ieeefp.h> // finite()
47#include <signal.h> // sigemptyset(), etc
Ben Murdochb8e0da22011-05-16 14:20:40 +010048#include <sys/kdi_regs.h>
Leon Clarked91b9f72010-01-27 17:25:45 +000049
50
51#undef MAP_TYPE
52
53#include "v8.h"
54
55#include "platform.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010056#include "vm-state-inl.h"
Leon Clarked91b9f72010-01-27 17:25:45 +000057
58
Leon Clarkef7060e22010-06-03 12:02:55 +010059// It seems there is a bug in some Solaris distributions (experienced in
60// SunOS 5.10 Generic_141445-09) which make it difficult or impossible to
61// access signbit() despite the availability of other C99 math functions.
62#ifndef signbit
63// Test sign - usually defined in math.h
64int signbit(double x) {
65 // We need to take care of the special case of both positive and negative
66 // versions of zero.
67 if (x == 0) {
68 return fpclass(x) & FP_NZERO;
69 } else {
70 // This won't detect negative NaN but that should be okay since we don't
71 // assume that behavior.
72 return x < 0;
73 }
74}
75#endif // signbit
76
Leon Clarked91b9f72010-01-27 17:25:45 +000077namespace v8 {
78namespace internal {
79
80
81// 0 is never a valid thread id on Solaris since the main thread is 1 and
82// subsequent have their ids incremented from there
83static const pthread_t kNoThread = (pthread_t) 0;
84
85
86double ceiling(double x) {
87 return ceil(x);
88}
89
90
91void OS::Setup() {
92 // Seed the random number generator.
93 // Convert the current time to a 64-bit integer first, before converting it
94 // to an unsigned. Going directly will cause an overflow and the seed to be
95 // set to all ones. The seed will be identical for different instances that
96 // call this setup code within the same millisecond.
97 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
98 srandom(static_cast<unsigned int>(seed));
99}
100
101
102uint64_t OS::CpuFeaturesImpliedByPlatform() {
103 return 0; // Solaris runs on a lot of things.
104}
105
106
107int OS::ActivationFrameAlignment() {
108 return STACK_ALIGN;
109}
110
111
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100112void OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) {
113 __asm__ __volatile__("" : : : "memory");
114 *ptr = value;
115}
116
117
Leon Clarked91b9f72010-01-27 17:25:45 +0000118const char* OS::LocalTimezone(double time) {
119 if (isnan(time)) return "";
120 time_t tv = static_cast<time_t>(floor(time/msPerSecond));
121 struct tm* t = localtime(&tv);
122 if (NULL == t) return "";
123 return tzname[0]; // The location of the timezone string on Solaris.
124}
125
126
127double OS::LocalTimeOffset() {
128 // On Solaris, struct tm does not contain a tm_gmtoff field.
129 time_t utc = time(NULL);
130 ASSERT(utc != -1);
131 struct tm* loc = localtime(&utc);
132 ASSERT(loc != NULL);
133 return static_cast<double>((mktime(loc) - utc) * msPerSecond);
134}
135
136
137// We keep the lowest and highest addresses mapped as a quick way of
138// determining that pointers are outside the heap (used mostly in assertions
139// and verification). The estimate is conservative, ie, not all addresses in
140// 'allocated' space are actually allocated to our heap. The range is
141// [lowest, highest), inclusive on the low and and exclusive on the high end.
142static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
143static void* highest_ever_allocated = reinterpret_cast<void*>(0);
144
145
146static void UpdateAllocatedSpaceLimits(void* address, int size) {
147 lowest_ever_allocated = Min(lowest_ever_allocated, address);
148 highest_ever_allocated =
149 Max(highest_ever_allocated,
150 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
151}
152
153
154bool OS::IsOutsideAllocatedSpace(void* address) {
155 return address < lowest_ever_allocated || address >= highest_ever_allocated;
156}
157
158
159size_t OS::AllocateAlignment() {
160 return static_cast<size_t>(getpagesize());
161}
162
163
164void* OS::Allocate(const size_t requested,
165 size_t* allocated,
166 bool is_executable) {
167 const size_t msize = RoundUp(requested, getpagesize());
168 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
169 void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
170
171 if (mbase == MAP_FAILED) {
172 LOG(StringEvent("OS::Allocate", "mmap failed"));
173 return NULL;
174 }
175 *allocated = msize;
176 UpdateAllocatedSpaceLimits(mbase, msize);
177 return mbase;
178}
179
180
181void OS::Free(void* address, const size_t size) {
182 // TODO(1240712): munmap has a return value which is ignored here.
183 int result = munmap(address, size);
184 USE(result);
185 ASSERT(result == 0);
186}
187
188
189#ifdef ENABLE_HEAP_PROTECTION
190
191void OS::Protect(void* address, size_t size) {
192 // TODO(1240712): mprotect has a return value which is ignored here.
193 mprotect(address, size, PROT_READ);
194}
195
196
197void OS::Unprotect(void* address, size_t size, bool is_executable) {
198 // TODO(1240712): mprotect has a return value which is ignored here.
199 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
200 mprotect(address, size, prot);
201}
202
203#endif
204
205
206void OS::Sleep(int milliseconds) {
207 useconds_t ms = static_cast<useconds_t>(milliseconds);
208 usleep(1000 * ms);
209}
210
211
212void OS::Abort() {
213 // Redirect to std abort to signal abnormal program termination.
214 abort();
215}
216
217
218void OS::DebugBreak() {
219 asm("int $3");
220}
221
222
223class PosixMemoryMappedFile : public OS::MemoryMappedFile {
224 public:
225 PosixMemoryMappedFile(FILE* file, void* memory, int size)
226 : file_(file), memory_(memory), size_(size) { }
227 virtual ~PosixMemoryMappedFile();
228 virtual void* memory() { return memory_; }
229 private:
230 FILE* file_;
231 void* memory_;
232 int size_;
233};
234
235
236OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
237 void* initial) {
238 FILE* file = fopen(name, "w+");
239 if (file == NULL) return NULL;
240 int result = fwrite(initial, size, 1, file);
241 if (result < 1) {
242 fclose(file);
243 return NULL;
244 }
245 void* memory =
246 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
247 return new PosixMemoryMappedFile(file, memory, size);
248}
249
250
251PosixMemoryMappedFile::~PosixMemoryMappedFile() {
252 if (memory_) munmap(memory_, size_);
253 fclose(file_);
254}
255
256
257void OS::LogSharedLibraryAddresses() {
258}
259
260
Ben Murdochf87a2032010-10-22 12:50:53 +0100261void OS::SignalCodeMovingGC() {
262}
263
264
Leon Clarkef7060e22010-06-03 12:02:55 +0100265struct StackWalker {
266 Vector<OS::StackFrame>& frames;
267 int index;
268};
269
270
271static int StackWalkCallback(uintptr_t pc, int signo, void* data) {
272 struct StackWalker* walker = static_cast<struct StackWalker*>(data);
273 Dl_info info;
274
275 int i = walker->index;
276
277 walker->frames[i].address = reinterpret_cast<void*>(pc);
278
279 // Make sure line termination is in place.
280 walker->frames[i].text[OS::kStackWalkMaxTextLen - 1] = '\0';
281
282 Vector<char> text = MutableCStrVector(walker->frames[i].text,
283 OS::kStackWalkMaxTextLen);
284
285 if (dladdr(reinterpret_cast<void*>(pc), &info) == 0) {
286 OS::SNPrintF(text, "[0x%p]", pc);
287 } else if ((info.dli_fname != NULL && info.dli_sname != NULL)) {
288 // We have symbol info.
289 OS::SNPrintF(text, "%s'%s+0x%x", info.dli_fname, info.dli_sname, pc);
290 } else {
291 // No local symbol info.
292 OS::SNPrintF(text,
293 "%s'0x%p [0x%p]",
294 info.dli_fname,
295 pc - reinterpret_cast<uintptr_t>(info.dli_fbase),
296 pc);
297 }
298 walker->index++;
299 return 0;
300}
301
302
Leon Clarked91b9f72010-01-27 17:25:45 +0000303int OS::StackWalk(Vector<OS::StackFrame> frames) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100304 ucontext_t ctx;
305 struct StackWalker walker = { frames, 0 };
Leon Clarked91b9f72010-01-27 17:25:45 +0000306
Leon Clarkef7060e22010-06-03 12:02:55 +0100307 if (getcontext(&ctx) < 0) return kStackWalkError;
Leon Clarked91b9f72010-01-27 17:25:45 +0000308
Leon Clarkef7060e22010-06-03 12:02:55 +0100309 if (!walkcontext(&ctx, StackWalkCallback, &walker)) {
Leon Clarked91b9f72010-01-27 17:25:45 +0000310 return kStackWalkError;
311 }
312
Leon Clarkef7060e22010-06-03 12:02:55 +0100313 return walker.index;
Leon Clarked91b9f72010-01-27 17:25:45 +0000314}
315
316
317// Constants used for mmap.
318static const int kMmapFd = -1;
319static const int kMmapFdOffset = 0;
320
321
322VirtualMemory::VirtualMemory(size_t size) {
323 address_ = mmap(NULL, size, PROT_NONE,
324 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
325 kMmapFd, kMmapFdOffset);
326 size_ = size;
327}
328
329
330VirtualMemory::~VirtualMemory() {
331 if (IsReserved()) {
332 if (0 == munmap(address(), size())) address_ = MAP_FAILED;
333 }
334}
335
336
337bool VirtualMemory::IsReserved() {
338 return address_ != MAP_FAILED;
339}
340
341
342bool VirtualMemory::Commit(void* address, size_t size, bool executable) {
343 int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
344 if (MAP_FAILED == mmap(address, size, prot,
345 MAP_PRIVATE | MAP_ANON | MAP_FIXED,
346 kMmapFd, kMmapFdOffset)) {
347 return false;
348 }
349
350 UpdateAllocatedSpaceLimits(address, size);
351 return true;
352}
353
354
355bool VirtualMemory::Uncommit(void* address, size_t size) {
356 return mmap(address, size, PROT_NONE,
357 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | MAP_FIXED,
358 kMmapFd, kMmapFdOffset) != MAP_FAILED;
359}
360
361
362class ThreadHandle::PlatformData : public Malloced {
363 public:
364 explicit PlatformData(ThreadHandle::Kind kind) {
365 Initialize(kind);
366 }
367
368 void Initialize(ThreadHandle::Kind kind) {
369 switch (kind) {
370 case ThreadHandle::SELF: thread_ = pthread_self(); break;
371 case ThreadHandle::INVALID: thread_ = kNoThread; break;
372 }
373 }
374
375 pthread_t thread_; // Thread handle for pthread.
376};
377
378
379ThreadHandle::ThreadHandle(Kind kind) {
380 data_ = new PlatformData(kind);
381}
382
383
384void ThreadHandle::Initialize(ThreadHandle::Kind kind) {
385 data_->Initialize(kind);
386}
387
388
389ThreadHandle::~ThreadHandle() {
390 delete data_;
391}
392
393
394bool ThreadHandle::IsSelf() const {
395 return pthread_equal(data_->thread_, pthread_self());
396}
397
398
399bool ThreadHandle::IsValid() const {
400 return data_->thread_ != kNoThread;
401}
402
403
404Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
Steve Block9fac8402011-05-12 15:51:54 +0100405 set_name("v8:<unknown>");
406}
407
408
409Thread::Thread(const char* name) : ThreadHandle(ThreadHandle::INVALID) {
410 set_name(name);
Leon Clarked91b9f72010-01-27 17:25:45 +0000411}
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
Steve Block9fac8402011-05-12 15:51:54 +0100430void Thread::set_name(const char* name) {
431 strncpy(name_, name, sizeof(name_));
432 name_[sizeof(name_) - 1] = '\0';
433}
434
435
Leon Clarked91b9f72010-01-27 17:25:45 +0000436void Thread::Start() {
437 pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
438 ASSERT(IsValid());
439}
440
441
442void Thread::Join() {
443 pthread_join(thread_handle_data()->thread_, NULL);
444}
445
446
447Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
448 pthread_key_t key;
449 int result = pthread_key_create(&key, NULL);
450 USE(result);
451 ASSERT(result == 0);
452 return static_cast<LocalStorageKey>(key);
453}
454
455
456void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
457 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
458 int result = pthread_key_delete(pthread_key);
459 USE(result);
460 ASSERT(result == 0);
461}
462
463
464void* Thread::GetThreadLocal(LocalStorageKey key) {
465 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
466 return pthread_getspecific(pthread_key);
467}
468
469
470void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
471 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
472 pthread_setspecific(pthread_key, value);
473}
474
475
476void Thread::YieldCPU() {
477 sched_yield();
478}
479
480
481class SolarisMutex : public Mutex {
482 public:
483
484 SolarisMutex() {
485 pthread_mutexattr_t attr;
486 pthread_mutexattr_init(&attr);
487 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
488 pthread_mutex_init(&mutex_, &attr);
489 }
490
491 ~SolarisMutex() { pthread_mutex_destroy(&mutex_); }
492
493 int Lock() { return pthread_mutex_lock(&mutex_); }
494
495 int Unlock() { return pthread_mutex_unlock(&mutex_); }
496
Ben Murdochb8e0da22011-05-16 14:20:40 +0100497 virtual bool TryLock() {
498 int result = pthread_mutex_trylock(&mutex_);
499 // Return false if the lock is busy and locking failed.
500 if (result == EBUSY) {
501 return false;
502 }
503 ASSERT(result == 0); // Verify no other errors.
504 return true;
505 }
506
Leon Clarked91b9f72010-01-27 17:25:45 +0000507 private:
508 pthread_mutex_t mutex_;
509};
510
511
512Mutex* OS::CreateMutex() {
513 return new SolarisMutex();
514}
515
516
517class SolarisSemaphore : public Semaphore {
518 public:
519 explicit SolarisSemaphore(int count) { sem_init(&sem_, 0, count); }
520 virtual ~SolarisSemaphore() { sem_destroy(&sem_); }
521
522 virtual void Wait();
523 virtual bool Wait(int timeout);
524 virtual void Signal() { sem_post(&sem_); }
525 private:
526 sem_t sem_;
527};
528
529
530void SolarisSemaphore::Wait() {
531 while (true) {
532 int result = sem_wait(&sem_);
533 if (result == 0) return; // Successfully got semaphore.
534 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
535 }
536}
537
538
539#ifndef TIMEVAL_TO_TIMESPEC
540#define TIMEVAL_TO_TIMESPEC(tv, ts) do { \
541 (ts)->tv_sec = (tv)->tv_sec; \
542 (ts)->tv_nsec = (tv)->tv_usec * 1000; \
543} while (false)
544#endif
545
546
547#ifndef timeradd
548#define timeradd(a, b, result) \
549 do { \
550 (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
551 (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
552 if ((result)->tv_usec >= 1000000) { \
553 ++(result)->tv_sec; \
554 (result)->tv_usec -= 1000000; \
555 } \
556 } while (0)
557#endif
558
559
560bool SolarisSemaphore::Wait(int timeout) {
561 const long kOneSecondMicros = 1000000; // NOLINT
562
563 // Split timeout into second and nanosecond parts.
564 struct timeval delta;
565 delta.tv_usec = timeout % kOneSecondMicros;
566 delta.tv_sec = timeout / kOneSecondMicros;
567
568 struct timeval current_time;
569 // Get the current time.
570 if (gettimeofday(&current_time, NULL) == -1) {
571 return false;
572 }
573
574 // Calculate time for end of timeout.
575 struct timeval end_time;
576 timeradd(&current_time, &delta, &end_time);
577
578 struct timespec ts;
579 TIMEVAL_TO_TIMESPEC(&end_time, &ts);
580 // Wait for semaphore signalled or timeout.
581 while (true) {
582 int result = sem_timedwait(&sem_, &ts);
583 if (result == 0) return true; // Successfully got semaphore.
584 if (result == -1 && errno == ETIMEDOUT) return false; // Timeout.
585 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
586 }
587}
588
589
590Semaphore* OS::CreateSemaphore(int count) {
591 return new SolarisSemaphore(count);
592}
593
594
595#ifdef ENABLE_LOGGING_AND_PROFILING
596
597static Sampler* active_sampler_ = NULL;
Ben Murdochb8e0da22011-05-16 14:20:40 +0100598static pthread_t vm_tid_ = 0;
599
Leon Clarked91b9f72010-01-27 17:25:45 +0000600
601static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
602 USE(info);
603 if (signal != SIGPROF) return;
Ben Murdochb8e0da22011-05-16 14:20:40 +0100604 if (active_sampler_ == NULL || !active_sampler_->IsActive()) return;
605 if (vm_tid_ != pthread_self()) return;
Leon Clarked91b9f72010-01-27 17:25:45 +0000606
Ben Murdochb8e0da22011-05-16 14:20:40 +0100607 TickSample sample_obj;
608 TickSample* sample = CpuProfiler::TickSampleEvent();
609 if (sample == NULL) sample = &sample_obj;
Leon Clarked91b9f72010-01-27 17:25:45 +0000610
Ben Murdochb8e0da22011-05-16 14:20:40 +0100611 // Extracting the sample from the context is extremely machine dependent.
612 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
613 mcontext_t& mcontext = ucontext->uc_mcontext;
614 sample->state = Top::current_vm_state();
Leon Clarked91b9f72010-01-27 17:25:45 +0000615
Ben Murdochb8e0da22011-05-16 14:20:40 +0100616#if V8_HOST_ARCH_IA32
617 sample->pc = reinterpret_cast<Address>(mcontext.gregs[KDIREG_EIP]);
618 sample->sp = reinterpret_cast<Address>(mcontext.gregs[KDIREG_ESP]);
619 sample->fp = reinterpret_cast<Address>(mcontext.gregs[KDIREG_EBP]);
620#elif V8_HOST_ARCH_X64
621 sample->pc = reinterpret_cast<Address>(mcontext.gregs[KDIREG_RIP]);
622 sample->sp = reinterpret_cast<Address>(mcontext.gregs[KDIREG_RSP]);
623 sample->fp = reinterpret_cast<Address>(mcontext.gregs[KDIREG_RBP]);
624#else
625 UNIMPLEMENTED();
626#endif
627 active_sampler_->SampleStack(sample);
628 active_sampler_->Tick(sample);
Leon Clarked91b9f72010-01-27 17:25:45 +0000629}
630
631
632class Sampler::PlatformData : public Malloced {
633 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
Ben Murdochb0fe1622011-05-05 13:52:32 +0100644Sampler::Sampler(int interval)
Ben Murdochf87a2032010-10-22 12:50:53 +0100645 : interval_(interval),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100646 profiling_(false),
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800647 active_(false),
648 samples_taken_(0) {
Leon Clarked91b9f72010-01-27 17:25:45 +0000649 data_ = new PlatformData();
650}
651
652
653Sampler::~Sampler() {
654 delete data_;
655}
656
657
658void Sampler::Start() {
659 // There can only be one active sampler at the time on POSIX
660 // platforms.
661 if (active_sampler_ != NULL) return;
662
663 // Request profiling signals.
664 struct sigaction sa;
665 sa.sa_sigaction = ProfilerSignalHandler;
666 sigemptyset(&sa.sa_mask);
667 sa.sa_flags = SA_SIGINFO;
668 if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return;
669 data_->signal_handler_installed_ = true;
670
671 // Set the itimer to generate a tick for each interval.
672 itimerval itimer;
673 itimer.it_interval.tv_sec = interval_ / 1000;
674 itimer.it_interval.tv_usec = (interval_ % 1000) * 1000;
675 itimer.it_value.tv_sec = itimer.it_interval.tv_sec;
676 itimer.it_value.tv_usec = itimer.it_interval.tv_usec;
677 setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_);
678
679 // Set this sampler as the active sampler.
680 active_sampler_ = this;
681 active_ = true;
682}
683
684
685void Sampler::Stop() {
686 // Restore old signal handler
687 if (data_->signal_handler_installed_) {
688 setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL);
689 sigaction(SIGPROF, &data_->old_signal_handler_, 0);
690 data_->signal_handler_installed_ = false;
691 }
692
693 // This sampler is no longer the active sampler.
694 active_sampler_ = NULL;
695 active_ = false;
696}
697
698#endif // ENABLE_LOGGING_AND_PROFILING
699
700} } // namespace v8::internal