| OLD | NEW |
| 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| 11 // with the distribution. | 11 // with the distribution. |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 81 // 0 is never a valid thread id on Solaris since the main thread is 1 and | 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 | 82 // subsequent have their ids incremented from there |
| 83 static const pthread_t kNoThread = (pthread_t) 0; | 83 static const pthread_t kNoThread = (pthread_t) 0; |
| 84 | 84 |
| 85 | 85 |
| 86 double ceiling(double x) { | 86 double ceiling(double x) { |
| 87 return ceil(x); | 87 return ceil(x); |
| 88 } | 88 } |
| 89 | 89 |
| 90 | 90 |
| 91 static Mutex* limit_mutex = NULL; |
| 91 void OS::Setup() { | 92 void OS::Setup() { |
| 92 // Seed the random number generator. | 93 // Seed the random number generator. |
| 93 // Convert the current time to a 64-bit integer first, before converting it | 94 // 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 // 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 // set to all ones. The seed will be identical for different instances that |
| 96 // call this setup code within the same millisecond. | 97 // call this setup code within the same millisecond. |
| 97 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); | 98 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); |
| 98 srandom(static_cast<unsigned int>(seed)); | 99 srandom(static_cast<unsigned int>(seed)); |
| 100 limit_mutex = CreateMutex(); |
| 99 } | 101 } |
| 100 | 102 |
| 101 | 103 |
| 102 uint64_t OS::CpuFeaturesImpliedByPlatform() { | 104 uint64_t OS::CpuFeaturesImpliedByPlatform() { |
| 103 return 0; // Solaris runs on a lot of things. | 105 return 0; // Solaris runs on a lot of things. |
| 104 } | 106 } |
| 105 | 107 |
| 106 | 108 |
| 107 int OS::ActivationFrameAlignment() { | 109 int OS::ActivationFrameAlignment() { |
| 108 return STACK_ALIGN; | 110 // GCC generates code that requires 16 byte alignment such as movdqa. |
| 111 return Max(STACK_ALIGN, 16); |
| 109 } | 112 } |
| 110 | 113 |
| 111 | 114 |
| 112 void OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) { | 115 void OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) { |
| 113 __asm__ __volatile__("" : : : "memory"); | 116 __asm__ __volatile__("" : : : "memory"); |
| 114 *ptr = value; | 117 *ptr = value; |
| 115 } | 118 } |
| 116 | 119 |
| 117 | 120 |
| 118 const char* OS::LocalTimezone(double time) { | 121 const char* OS::LocalTimezone(double time) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 137 // We keep the lowest and highest addresses mapped as a quick way of | 140 // 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 | 141 // determining that pointers are outside the heap (used mostly in assertions |
| 139 // and verification). The estimate is conservative, ie, not all addresses in | 142 // and verification). The estimate is conservative, ie, not all addresses in |
| 140 // 'allocated' space are actually allocated to our heap. The range is | 143 // '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. | 144 // [lowest, highest), inclusive on the low and and exclusive on the high end. |
| 142 static void* lowest_ever_allocated = reinterpret_cast<void*>(-1); | 145 static void* lowest_ever_allocated = reinterpret_cast<void*>(-1); |
| 143 static void* highest_ever_allocated = reinterpret_cast<void*>(0); | 146 static void* highest_ever_allocated = reinterpret_cast<void*>(0); |
| 144 | 147 |
| 145 | 148 |
| 146 static void UpdateAllocatedSpaceLimits(void* address, int size) { | 149 static void UpdateAllocatedSpaceLimits(void* address, int size) { |
| 150 ASSERT(limit_mutex != NULL); |
| 151 ScopedLock lock(limit_mutex); |
| 152 |
| 147 lowest_ever_allocated = Min(lowest_ever_allocated, address); | 153 lowest_ever_allocated = Min(lowest_ever_allocated, address); |
| 148 highest_ever_allocated = | 154 highest_ever_allocated = |
| 149 Max(highest_ever_allocated, | 155 Max(highest_ever_allocated, |
| 150 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size)); | 156 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size)); |
| 151 } | 157 } |
| 152 | 158 |
| 153 | 159 |
| 154 bool OS::IsOutsideAllocatedSpace(void* address) { | 160 bool OS::IsOutsideAllocatedSpace(void* address) { |
| 155 return address < lowest_ever_allocated || address >= highest_ever_allocated; | 161 return address < lowest_ever_allocated || address >= highest_ever_allocated; |
| 156 } | 162 } |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 373 } | 379 } |
| 374 | 380 |
| 375 | 381 |
| 376 class Thread::PlatformData : public Malloced { | 382 class Thread::PlatformData : public Malloced { |
| 377 public: | 383 public: |
| 378 PlatformData() : thread_(kNoThread) { } | 384 PlatformData() : thread_(kNoThread) { } |
| 379 | 385 |
| 380 pthread_t thread_; // Thread handle for pthread. | 386 pthread_t thread_; // Thread handle for pthread. |
| 381 }; | 387 }; |
| 382 | 388 |
| 383 Thread::Thread(Isolate* isolate, const Options& options) | 389 Thread::Thread(const Options& options) |
| 384 : data_(new PlatformData()), | 390 : data_(new PlatformData()), |
| 385 isolate_(isolate), | |
| 386 stack_size_(options.stack_size) { | 391 stack_size_(options.stack_size) { |
| 387 set_name(options.name); | 392 set_name(options.name); |
| 388 } | 393 } |
| 389 | 394 |
| 390 | 395 |
| 391 Thread::Thread(Isolate* isolate, const char* name) | 396 Thread::Thread(const char* name) |
| 392 : data_(new PlatformData()), | 397 : data_(new PlatformData()), |
| 393 isolate_(isolate), | |
| 394 stack_size_(0) { | 398 stack_size_(0) { |
| 395 set_name(name); | 399 set_name(name); |
| 396 } | 400 } |
| 397 | 401 |
| 398 | 402 |
| 399 Thread::~Thread() { | 403 Thread::~Thread() { |
| 400 delete data_; | 404 delete data_; |
| 401 } | 405 } |
| 402 | 406 |
| 403 | 407 |
| 404 static void* ThreadEntry(void* arg) { | 408 static void* ThreadEntry(void* arg) { |
| 405 Thread* thread = reinterpret_cast<Thread*>(arg); | 409 Thread* thread = reinterpret_cast<Thread*>(arg); |
| 406 // This is also initialized by the first argument to pthread_create() but we | 410 // This is also initialized by the first argument to pthread_create() but we |
| 407 // don't know which thread will run first (the original thread or the new | 411 // don't know which thread will run first (the original thread or the new |
| 408 // one) so we initialize it here too. | 412 // one) so we initialize it here too. |
| 409 thread->data()->thread_ = pthread_self(); | 413 thread->data()->thread_ = pthread_self(); |
| 410 ASSERT(thread->data()->thread_ != kNoThread); | 414 ASSERT(thread->data()->thread_ != kNoThread); |
| 411 Thread::SetThreadLocal(Isolate::isolate_key(), thread->isolate()); | |
| 412 thread->Run(); | 415 thread->Run(); |
| 413 return NULL; | 416 return NULL; |
| 414 } | 417 } |
| 415 | 418 |
| 416 | 419 |
| 417 void Thread::set_name(const char* name) { | 420 void Thread::set_name(const char* name) { |
| 418 strncpy(name_, name, sizeof(name_)); | 421 strncpy(name_, name, sizeof(name_)); |
| 419 name_[sizeof(name_) - 1] = '\0'; | 422 name_[sizeof(name_) - 1] = '\0'; |
| 420 } | 423 } |
| 421 | 424 |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 581 } | 584 } |
| 582 | 585 |
| 583 | 586 |
| 584 Semaphore* OS::CreateSemaphore(int count) { | 587 Semaphore* OS::CreateSemaphore(int count) { |
| 585 return new SolarisSemaphore(count); | 588 return new SolarisSemaphore(count); |
| 586 } | 589 } |
| 587 | 590 |
| 588 | 591 |
| 589 #ifdef ENABLE_LOGGING_AND_PROFILING | 592 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 590 | 593 |
| 591 static Sampler* active_sampler_ = NULL; | |
| 592 static pthread_t vm_tid_ = 0; | |
| 593 | |
| 594 | |
| 595 static pthread_t GetThreadID() { | 594 static pthread_t GetThreadID() { |
| 596 return pthread_self(); | 595 return pthread_self(); |
| 597 } | 596 } |
| 598 | 597 |
| 599 | |
| 600 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { | 598 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { |
| 601 USE(info); | 599 USE(info); |
| 602 if (signal != SIGPROF) return; | 600 if (signal != SIGPROF) return; |
| 603 if (active_sampler_ == NULL || !active_sampler_->IsActive()) return; | 601 Isolate* isolate = Isolate::UncheckedCurrent(); |
| 604 if (vm_tid_ != GetThreadID()) return; | 602 if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) { |
| 603 // We require a fully initialized and entered isolate. |
| 604 return; |
| 605 } |
| 606 if (v8::Locker::IsActive() && |
| 607 !isolate->thread_manager()->IsLockedByCurrentThread()) { |
| 608 return; |
| 609 } |
| 610 |
| 611 Sampler* sampler = isolate->logger()->sampler(); |
| 612 if (sampler == NULL || !sampler->IsActive()) return; |
| 605 | 613 |
| 606 TickSample sample_obj; | 614 TickSample sample_obj; |
| 607 TickSample* sample = CpuProfiler::TickSampleEvent(); | 615 TickSample* sample = CpuProfiler::TickSampleEvent(isolate); |
| 608 if (sample == NULL) sample = &sample_obj; | 616 if (sample == NULL) sample = &sample_obj; |
| 609 | 617 |
| 610 // Extracting the sample from the context is extremely machine dependent. | 618 // Extracting the sample from the context is extremely machine dependent. |
| 611 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); | 619 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); |
| 612 mcontext_t& mcontext = ucontext->uc_mcontext; | 620 mcontext_t& mcontext = ucontext->uc_mcontext; |
| 613 sample->state = Top::current_vm_state(); | 621 sample->state = isolate->current_vm_state(); |
| 614 | 622 |
| 615 sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_PC]); | 623 sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_PC]); |
| 616 sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_SP]); | 624 sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_SP]); |
| 617 sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_FP]); | 625 sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_FP]); |
| 618 | 626 |
| 619 active_sampler_->SampleStack(sample); | 627 sampler->SampleStack(sample); |
| 620 active_sampler_->Tick(sample); | 628 sampler->Tick(sample); |
| 621 } | 629 } |
| 622 | 630 |
| 623 | |
| 624 class Sampler::PlatformData : public Malloced { | 631 class Sampler::PlatformData : public Malloced { |
| 625 public: | 632 public: |
| 633 PlatformData() : vm_tid_(GetThreadID()) {} |
| 634 |
| 635 pthread_t vm_tid() const { return vm_tid_; } |
| 636 |
| 637 private: |
| 638 pthread_t vm_tid_; |
| 639 }; |
| 640 |
| 641 |
| 642 class SignalSender : public Thread { |
| 643 public: |
| 626 enum SleepInterval { | 644 enum SleepInterval { |
| 627 FULL_INTERVAL, | 645 HALF_INTERVAL, |
| 628 HALF_INTERVAL | 646 FULL_INTERVAL |
| 629 }; | 647 }; |
| 630 | 648 |
| 631 explicit PlatformData(Sampler* sampler) | 649 explicit SignalSender(int interval) |
| 632 : sampler_(sampler), | 650 : Thread("SignalSender"), |
| 633 signal_handler_installed_(false), | 651 interval_(interval) {} |
| 634 vm_tgid_(getpid()), | 652 |
| 635 signal_sender_launched_(false) { | 653 static void InstallSignalHandler() { |
| 654 struct sigaction sa; |
| 655 sa.sa_sigaction = ProfilerSignalHandler; |
| 656 sigemptyset(&sa.sa_mask); |
| 657 sa.sa_flags = SA_RESTART | SA_SIGINFO; |
| 658 signal_handler_installed_ = |
| 659 (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0); |
| 636 } | 660 } |
| 637 | 661 |
| 638 void SignalSender() { | 662 static void RestoreSignalHandler() { |
| 639 while (sampler_->IsActive()) { | 663 if (signal_handler_installed_) { |
| 640 if (rate_limiter_.SuspendIfNecessary()) continue; | 664 sigaction(SIGPROF, &old_signal_handler_, 0); |
| 641 if (sampler_->IsProfiling() && RuntimeProfiler::IsEnabled()) { | 665 signal_handler_installed_ = false; |
| 642 SendProfilingSignal(); | 666 } |
| 667 } |
| 668 |
| 669 static void AddActiveSampler(Sampler* sampler) { |
| 670 ScopedLock lock(mutex_); |
| 671 SamplerRegistry::AddActiveSampler(sampler); |
| 672 if (instance_ == NULL) { |
| 673 // Start a thread that will send SIGPROF signal to VM threads, |
| 674 // when CPU profiling will be enabled. |
| 675 instance_ = new SignalSender(sampler->interval()); |
| 676 instance_->Start(); |
| 677 } else { |
| 678 ASSERT(instance_->interval_ == sampler->interval()); |
| 679 } |
| 680 } |
| 681 |
| 682 static void RemoveActiveSampler(Sampler* sampler) { |
| 683 ScopedLock lock(mutex_); |
| 684 SamplerRegistry::RemoveActiveSampler(sampler); |
| 685 if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) { |
| 686 RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_); |
| 687 delete instance_; |
| 688 instance_ = NULL; |
| 689 RestoreSignalHandler(); |
| 690 } |
| 691 } |
| 692 |
| 693 // Implement Thread::Run(). |
| 694 virtual void Run() { |
| 695 SamplerRegistry::State state; |
| 696 while ((state = SamplerRegistry::GetState()) != |
| 697 SamplerRegistry::HAS_NO_SAMPLERS) { |
| 698 bool cpu_profiling_enabled = |
| 699 (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS); |
| 700 bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled(); |
| 701 if (cpu_profiling_enabled && !signal_handler_installed_) { |
| 702 InstallSignalHandler(); |
| 703 } else if (!cpu_profiling_enabled && signal_handler_installed_) { |
| 704 RestoreSignalHandler(); |
| 705 } |
| 706 |
| 707 // When CPU profiling is enabled both JavaScript and C++ code is |
| 708 // profiled. We must not suspend. |
| 709 if (!cpu_profiling_enabled) { |
| 710 if (rate_limiter_.SuspendIfNecessary()) continue; |
| 711 } |
| 712 if (cpu_profiling_enabled && runtime_profiler_enabled) { |
| 713 if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) { |
| 714 return; |
| 715 } |
| 643 Sleep(HALF_INTERVAL); | 716 Sleep(HALF_INTERVAL); |
| 644 RuntimeProfiler::NotifyTick(); | 717 if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) { |
| 718 return; |
| 719 } |
| 645 Sleep(HALF_INTERVAL); | 720 Sleep(HALF_INTERVAL); |
| 646 } else { | 721 } else { |
| 647 if (sampler_->IsProfiling()) SendProfilingSignal(); | 722 if (cpu_profiling_enabled) { |
| 648 if (RuntimeProfiler::IsEnabled()) RuntimeProfiler::NotifyTick(); | 723 if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, |
| 724 this)) { |
| 725 return; |
| 726 } |
| 727 } |
| 728 if (runtime_profiler_enabled) { |
| 729 if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, |
| 730 NULL)) { |
| 731 return; |
| 732 } |
| 733 } |
| 649 Sleep(FULL_INTERVAL); | 734 Sleep(FULL_INTERVAL); |
| 650 } | 735 } |
| 651 } | 736 } |
| 652 } | 737 } |
| 653 | 738 |
| 654 void SendProfilingSignal() { | 739 static void DoCpuProfile(Sampler* sampler, void* raw_sender) { |
| 740 if (!sampler->IsProfiling()) return; |
| 741 SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender); |
| 742 sender->SendProfilingSignal(sampler->platform_data()->vm_tid()); |
| 743 } |
| 744 |
| 745 static void DoRuntimeProfile(Sampler* sampler, void* ignored) { |
| 746 if (!sampler->isolate()->IsInitialized()) return; |
| 747 sampler->isolate()->runtime_profiler()->NotifyTick(); |
| 748 } |
| 749 |
| 750 void SendProfilingSignal(pthread_t tid) { |
| 655 if (!signal_handler_installed_) return; | 751 if (!signal_handler_installed_) return; |
| 656 pthread_kill(vm_tid_, SIGPROF); | 752 pthread_kill(tid, SIGPROF); |
| 657 } | 753 } |
| 658 | 754 |
| 659 void Sleep(SleepInterval full_or_half) { | 755 void Sleep(SleepInterval full_or_half) { |
| 660 // Convert ms to us and subtract 100 us to compensate delays | 756 // Convert ms to us and subtract 100 us to compensate delays |
| 661 // occuring during signal delivery. | 757 // occuring during signal delivery. |
| 662 useconds_t interval = sampler_->interval_ * 1000 - 100; | 758 useconds_t interval = interval_ * 1000 - 100; |
| 663 if (full_or_half == HALF_INTERVAL) interval /= 2; | 759 if (full_or_half == HALF_INTERVAL) interval /= 2; |
| 664 int result = usleep(interval); | 760 int result = usleep(interval); |
| 665 #ifdef DEBUG | 761 #ifdef DEBUG |
| 666 if (result != 0 && errno != EINTR) { | 762 if (result != 0 && errno != EINTR) { |
| 667 fprintf(stderr, | 763 fprintf(stderr, |
| 668 "SignalSender usleep error; interval = %u, errno = %d\n", | 764 "SignalSender usleep error; interval = %u, errno = %d\n", |
| 669 interval, | 765 interval, |
| 670 errno); | 766 errno); |
| 671 ASSERT(result == 0 || errno == EINTR); | 767 ASSERT(result == 0 || errno == EINTR); |
| 672 } | 768 } |
| 673 #endif | 769 #endif |
| 674 USE(result); | 770 USE(result); |
| 675 } | 771 } |
| 676 | 772 |
| 677 Sampler* sampler_; | 773 const int interval_; |
| 678 bool signal_handler_installed_; | |
| 679 struct sigaction old_signal_handler_; | |
| 680 int vm_tgid_; | |
| 681 bool signal_sender_launched_; | |
| 682 pthread_t signal_sender_thread_; | |
| 683 RuntimeProfilerRateLimiter rate_limiter_; | 774 RuntimeProfilerRateLimiter rate_limiter_; |
| 775 |
| 776 // Protects the process wide state below. |
| 777 static Mutex* mutex_; |
| 778 static SignalSender* instance_; |
| 779 static bool signal_handler_installed_; |
| 780 static struct sigaction old_signal_handler_; |
| 781 |
| 782 DISALLOW_COPY_AND_ASSIGN(SignalSender); |
| 684 }; | 783 }; |
| 685 | 784 |
| 686 | 785 Mutex* SignalSender::mutex_ = OS::CreateMutex(); |
| 687 static void* SenderEntry(void* arg) { | 786 SignalSender* SignalSender::instance_ = NULL; |
| 688 Sampler::PlatformData* data = | 787 struct sigaction SignalSender::old_signal_handler_; |
| 689 reinterpret_cast<Sampler::PlatformData*>(arg); | 788 bool SignalSender::signal_handler_installed_ = false; |
| 690 data->SignalSender(); | |
| 691 return 0; | |
| 692 } | |
| 693 | 789 |
| 694 | 790 |
| 695 Sampler::Sampler(Isolate* isolate, int interval) | 791 Sampler::Sampler(Isolate* isolate, int interval) |
| 696 : isolate_(isolate), | 792 : isolate_(isolate), |
| 697 interval_(interval), | 793 interval_(interval), |
| 698 profiling_(false), | 794 profiling_(false), |
| 699 active_(false), | 795 active_(false), |
| 700 samples_taken_(0) { | 796 samples_taken_(0) { |
| 701 data_ = new PlatformData(this); | 797 data_ = new PlatformData; |
| 702 } | 798 } |
| 703 | 799 |
| 704 | 800 |
| 705 Sampler::~Sampler() { | 801 Sampler::~Sampler() { |
| 706 ASSERT(!data_->signal_sender_launched_); | 802 ASSERT(!IsActive()); |
| 707 delete data_; | 803 delete data_; |
| 708 } | 804 } |
| 709 | 805 |
| 710 | 806 |
| 711 void Sampler::Start() { | 807 void Sampler::Start() { |
| 712 // There can only be one active sampler at the time on POSIX | |
| 713 // platforms. | |
| 714 ASSERT(!IsActive()); | 808 ASSERT(!IsActive()); |
| 715 vm_tid_ = GetThreadID(); | |
| 716 | |
| 717 // Request profiling signals. | |
| 718 struct sigaction sa; | |
| 719 sa.sa_sigaction = ProfilerSignalHandler; | |
| 720 sigemptyset(&sa.sa_mask); | |
| 721 sa.sa_flags = SA_RESTART | SA_SIGINFO; | |
| 722 data_->signal_handler_installed_ = | |
| 723 sigaction(SIGPROF, &sa, &data_->old_signal_handler_) == 0; | |
| 724 | |
| 725 // Start a thread that sends SIGPROF signal to VM thread. | |
| 726 // Sending the signal ourselves instead of relying on itimer provides | |
| 727 // much better accuracy. | |
| 728 SetActive(true); | 809 SetActive(true); |
| 729 if (pthread_create( | 810 SignalSender::AddActiveSampler(this); |
| 730 &data_->signal_sender_thread_, NULL, SenderEntry, data_) == 0) { | |
| 731 data_->signal_sender_launched_ = true; | |
| 732 } | |
| 733 | |
| 734 // Set this sampler as the active sampler. | |
| 735 active_sampler_ = this; | |
| 736 } | 811 } |
| 737 | 812 |
| 738 | 813 |
| 739 void Sampler::Stop() { | 814 void Sampler::Stop() { |
| 815 ASSERT(IsActive()); |
| 816 SignalSender::RemoveActiveSampler(this); |
| 740 SetActive(false); | 817 SetActive(false); |
| 741 | |
| 742 // Wait for signal sender termination (it will exit after setting | |
| 743 // active_ to false). | |
| 744 if (data_->signal_sender_launched_) { | |
| 745 Top::WakeUpRuntimeProfilerThreadBeforeShutdown(); | |
| 746 pthread_join(data_->signal_sender_thread_, NULL); | |
| 747 data_->signal_sender_launched_ = false; | |
| 748 } | |
| 749 | |
| 750 // Restore old signal handler | |
| 751 if (data_->signal_handler_installed_) { | |
| 752 sigaction(SIGPROF, &data_->old_signal_handler_, 0); | |
| 753 data_->signal_handler_installed_ = false; | |
| 754 } | |
| 755 | |
| 756 // This sampler is no longer the active sampler. | |
| 757 active_sampler_ = NULL; | |
| 758 } | 818 } |
| 759 | 819 |
| 760 #endif // ENABLE_LOGGING_AND_PROFILING | 820 #endif // ENABLE_LOGGING_AND_PROFILING |
| 761 | 821 |
| 762 } } // namespace v8::internal | 822 } } // namespace v8::internal |
| OLD | NEW |