Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 68 double ceiling(double x) { | 68 double ceiling(double x) { |
| 69 // Correct as on OS X | 69 // Correct as on OS X |
| 70 if (-1.0 < x && x < 0.0) { | 70 if (-1.0 < x && x < 0.0) { |
| 71 return -0.0; | 71 return -0.0; |
| 72 } else { | 72 } else { |
| 73 return ceil(x); | 73 return ceil(x); |
| 74 } | 74 } |
| 75 } | 75 } |
| 76 | 76 |
| 77 | 77 |
| 78 static Mutex* limit_mutex = NULL; | |
| 79 | |
| 80 | |
| 78 void OS::Setup() { | 81 void OS::Setup() { |
| 79 // Seed the random number generator. | 82 // Seed the random number generator. |
| 80 // Convert the current time to a 64-bit integer first, before converting it | 83 // Convert the current time to a 64-bit integer first, before converting it |
| 81 // to an unsigned. Going directly can cause an overflow and the seed to be | 84 // to an unsigned. Going directly can cause an overflow and the seed to be |
| 82 // set to all ones. The seed will be identical for different instances that | 85 // set to all ones. The seed will be identical for different instances that |
| 83 // call this setup code within the same millisecond. | 86 // call this setup code within the same millisecond. |
| 84 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); | 87 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); |
| 85 srandom(static_cast<unsigned int>(seed)); | 88 srandom(static_cast<unsigned int>(seed)); |
| 89 limit_mutex = CreateMutex(); | |
| 86 } | 90 } |
| 87 | 91 |
| 88 | 92 |
| 89 void OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) { | 93 void OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) { |
| 90 __asm__ __volatile__("" : : : "memory"); | 94 __asm__ __volatile__("" : : : "memory"); |
| 91 *ptr = value; | 95 *ptr = value; |
| 92 } | 96 } |
| 93 | 97 |
| 94 | 98 |
| 95 uint64_t OS::CpuFeaturesImpliedByPlatform() { | 99 uint64_t OS::CpuFeaturesImpliedByPlatform() { |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 124 // We keep the lowest and highest addresses mapped as a quick way of | 128 // We keep the lowest and highest addresses mapped as a quick way of |
| 125 // determining that pointers are outside the heap (used mostly in assertions | 129 // determining that pointers are outside the heap (used mostly in assertions |
| 126 // and verification). The estimate is conservative, ie, not all addresses in | 130 // and verification). The estimate is conservative, ie, not all addresses in |
| 127 // 'allocated' space are actually allocated to our heap. The range is | 131 // 'allocated' space are actually allocated to our heap. The range is |
| 128 // [lowest, highest), inclusive on the low and and exclusive on the high end. | 132 // [lowest, highest), inclusive on the low and and exclusive on the high end. |
| 129 static void* lowest_ever_allocated = reinterpret_cast<void*>(-1); | 133 static void* lowest_ever_allocated = reinterpret_cast<void*>(-1); |
| 130 static void* highest_ever_allocated = reinterpret_cast<void*>(0); | 134 static void* highest_ever_allocated = reinterpret_cast<void*>(0); |
| 131 | 135 |
| 132 | 136 |
| 133 static void UpdateAllocatedSpaceLimits(void* address, int size) { | 137 static void UpdateAllocatedSpaceLimits(void* address, int size) { |
| 138 ASSERT(limit_mutex != NULL); | |
| 139 ScopedLock lock(limit_mutex); | |
| 140 | |
| 134 lowest_ever_allocated = Min(lowest_ever_allocated, address); | 141 lowest_ever_allocated = Min(lowest_ever_allocated, address); |
| 135 highest_ever_allocated = | 142 highest_ever_allocated = |
| 136 Max(highest_ever_allocated, | 143 Max(highest_ever_allocated, |
| 137 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size)); | 144 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size)); |
| 138 } | 145 } |
| 139 | 146 |
| 140 | 147 |
| 141 bool OS::IsOutsideAllocatedSpace(void* address) { | 148 bool OS::IsOutsideAllocatedSpace(void* address) { |
| 142 return address < lowest_ever_allocated || address >= highest_ever_allocated; | 149 return address < lowest_ever_allocated || address >= highest_ever_allocated; |
| 143 } | 150 } |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 293 result = read(fd, buffer + bytes_read, 1); | 300 result = read(fd, buffer + bytes_read, 1); |
| 294 if (result < 1) break; | 301 if (result < 1) break; |
| 295 } while (buffer[bytes_read] != '\n'); | 302 } while (buffer[bytes_read] != '\n'); |
| 296 buffer[bytes_read] = 0; | 303 buffer[bytes_read] = 0; |
| 297 // Ignore mappings that are not executable. | 304 // Ignore mappings that are not executable. |
| 298 if (buffer[3] != 'x') continue; | 305 if (buffer[3] != 'x') continue; |
| 299 char* start_of_path = index(buffer, '/'); | 306 char* start_of_path = index(buffer, '/'); |
| 300 // There may be no filename in this line. Skip to next. | 307 // There may be no filename in this line. Skip to next. |
| 301 if (start_of_path == NULL) continue; | 308 if (start_of_path == NULL) continue; |
| 302 buffer[bytes_read] = 0; | 309 buffer[bytes_read] = 0; |
| 303 LOG(SharedLibraryEvent(start_of_path, start, end)); | 310 LOG(i::Isolate::Current(), SharedLibraryEvent(start_of_path, start, end)); |
| 304 } | 311 } |
| 305 close(fd); | 312 close(fd); |
| 306 #endif | 313 #endif |
| 307 } | 314 } |
| 308 | 315 |
| 309 | 316 |
| 310 void OS::SignalCodeMovingGC() { | 317 void OS::SignalCodeMovingGC() { |
| 311 } | 318 } |
| 312 | 319 |
| 313 | 320 |
| (...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 612 } | 619 } |
| 613 | 620 |
| 614 | 621 |
| 615 Semaphore* OS::CreateSemaphore(int count) { | 622 Semaphore* OS::CreateSemaphore(int count) { |
| 616 return new FreeBSDSemaphore(count); | 623 return new FreeBSDSemaphore(count); |
| 617 } | 624 } |
| 618 | 625 |
| 619 | 626 |
| 620 #ifdef ENABLE_LOGGING_AND_PROFILING | 627 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 621 | 628 |
| 622 static Sampler* active_sampler_ = NULL; | |
| 623 static pthread_t vm_tid_ = NULL; | |
| 624 | |
| 625 | |
| 626 static pthread_t GetThreadID() { | 629 static pthread_t GetThreadID() { |
| 627 pthread_t thread_id = pthread_self(); | 630 pthread_t thread_id = pthread_self(); |
| 628 return thread_id; | 631 return thread_id; |
| 629 } | 632 } |
| 630 | 633 |
| 631 | 634 |
| 632 class Sampler::PlatformData : public Malloced { | 635 class Sampler::PlatformData : public Malloced { |
| 633 public: | 636 public: |
| 634 enum SleepInterval { | 637 PlatformData() : vm_tid_(GetThreadID()) {} |
| 635 FULL_INTERVAL, | |
| 636 HALF_INTERVAL | |
| 637 }; | |
| 638 | 638 |
| 639 explicit PlatformData(Sampler* sampler) | 639 const pthread *vm_tid() const { return vm_tid_; } |
|
Vitaly Repeshko
2011/03/28 12:02:30
I think this should return "pthread_t" (no const).
Ben Laurie (Chromium)
2011/03/28 12:08:48
Done.
| |
| 640 : sampler_(sampler), | |
| 641 signal_handler_installed_(false), | |
| 642 signal_sender_launched_(false) { | |
| 643 } | |
| 644 | 640 |
| 645 void SignalSender() { | 641 private: |
| 646 while (sampler_->IsActive()) { | 642 const pthread *vm_tid_; |
|
Vitaly Repeshko
2011/03/28 12:02:30
pthread_t
Ben Laurie (Chromium)
2011/03/28 12:08:48
Done.
| |
| 647 if (rate_limiter_.SuspendIfNecessary()) continue; | |
| 648 if (sampler_->IsProfiling() && RuntimeProfiler::IsEnabled()) { | |
| 649 Sleep(FULL_INTERVAL); | |
| 650 RuntimeProfiler::NotifyTick(); | |
| 651 } else { | |
| 652 if (RuntimeProfiler::IsEnabled()) RuntimeProfiler::NotifyTick(); | |
| 653 Sleep(FULL_INTERVAL); | |
| 654 } | |
| 655 } | |
| 656 } | |
| 657 | |
| 658 void Sleep(SleepInterval full_or_half) { | |
| 659 // Convert ms to us and subtract 100 us to compensate delays | |
| 660 // occuring during signal delivery. | |
| 661 useconds_t interval = sampler_->interval_ * 1000 - 100; | |
| 662 if (full_or_half == HALF_INTERVAL) interval /= 2; | |
| 663 int result = usleep(interval); | |
| 664 #ifdef DEBUG | |
| 665 if (result != 0 && errno != EINTR) { | |
| 666 fprintf(stderr, | |
| 667 "SignalSender usleep error; interval = %u, errno = %d\n", | |
| 668 interval, | |
| 669 errno); | |
| 670 ASSERT(result == 0 || errno == EINTR); | |
| 671 } | |
| 672 #endif | |
| 673 USE(result); | |
| 674 } | |
| 675 | |
| 676 Sampler* sampler_; | |
| 677 bool signal_handler_installed_; | |
| 678 struct sigaction old_signal_handler_; | |
| 679 struct itimerval old_timer_value_; | |
| 680 bool signal_sender_launched_; | |
| 681 pthread_t signal_sender_thread_; | |
| 682 RuntimeProfilerRateLimiter rate_limiter_; | |
| 683 }; | 643 }; |
| 684 | 644 |
| 685 | 645 |
| 686 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { | 646 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { |
| 687 USE(info); | 647 USE(info); |
| 688 if (signal != SIGPROF) return; | 648 if (signal != SIGPROF) return; |
| 689 if (active_sampler_ == NULL) return; | 649 Isolate* isolate = Isolate::UncheckedCurrent(); |
| 690 if (!active_sampler_->IsActive()) { | 650 if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) { |
| 691 // Restore old signal handler | 651 // We require a fully initialized and entered isolate. |
| 692 Sampler::PlatformData* data = active_sampler_->data(); | |
| 693 if (data->signal_handler_installed_) { | |
| 694 sigaction(SIGPROF, &data->old_signal_handler_, 0); | |
| 695 data->signal_handler_installed_ = false; | |
| 696 } | |
| 697 return; | 652 return; |
| 698 } | 653 } |
| 699 | 654 Sampler* sampler = isolate->logger()->sampler(); |
| 700 if (vm_tid_ != GetThreadID()) return; | 655 if (sampler == NULL || !sampler->IsActive()) return; |
| 701 | 656 |
| 702 TickSample sample_obj; | 657 TickSample sample_obj; |
| 703 TickSample* sample = CpuProfiler::TickSampleEvent(); | 658 TickSample* sample = CpuProfiler::TickSampleEvent(isolate); |
| 704 if (sample == NULL) sample = &sample_obj; | 659 if (sample == NULL) sample = &sample_obj; |
| 705 | 660 |
| 706 // Extracting the sample from the context is extremely machine dependent. | 661 // Extracting the sample from the context is extremely machine dependent. |
| 707 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); | 662 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); |
| 708 mcontext_t& mcontext = ucontext->uc_mcontext; | 663 mcontext_t& mcontext = ucontext->uc_mcontext; |
| 664 sample->state = isolate->current_vm_state(); | |
| 709 #if V8_HOST_ARCH_IA32 | 665 #if V8_HOST_ARCH_IA32 |
| 710 sample->pc = reinterpret_cast<Address>(mcontext.mc_eip); | 666 sample->pc = reinterpret_cast<Address>(mcontext.mc_eip); |
| 711 sample->sp = reinterpret_cast<Address>(mcontext.mc_esp); | 667 sample->sp = reinterpret_cast<Address>(mcontext.mc_esp); |
| 712 sample->fp = reinterpret_cast<Address>(mcontext.mc_ebp); | 668 sample->fp = reinterpret_cast<Address>(mcontext.mc_ebp); |
| 713 #elif V8_HOST_ARCH_X64 | 669 #elif V8_HOST_ARCH_X64 |
| 714 sample->pc = reinterpret_cast<Address>(mcontext.mc_rip); | 670 sample->pc = reinterpret_cast<Address>(mcontext.mc_rip); |
| 715 sample->sp = reinterpret_cast<Address>(mcontext.mc_rsp); | 671 sample->sp = reinterpret_cast<Address>(mcontext.mc_rsp); |
| 716 sample->fp = reinterpret_cast<Address>(mcontext.mc_rbp); | 672 sample->fp = reinterpret_cast<Address>(mcontext.mc_rbp); |
| 717 #elif V8_HOST_ARCH_ARM | 673 #elif V8_HOST_ARCH_ARM |
| 718 sample->pc = reinterpret_cast<Address>(mcontext.mc_r15); | 674 sample->pc = reinterpret_cast<Address>(mcontext.mc_r15); |
| 719 sample->sp = reinterpret_cast<Address>(mcontext.mc_r13); | 675 sample->sp = reinterpret_cast<Address>(mcontext.mc_r13); |
| 720 sample->fp = reinterpret_cast<Address>(mcontext.mc_r11); | 676 sample->fp = reinterpret_cast<Address>(mcontext.mc_r11); |
| 721 #endif | 677 #endif |
| 722 active_sampler_->SampleStack(sample); | 678 sampler->SampleStack(sample); |
| 723 active_sampler_->Tick(sample); | 679 sampler->Tick(sample); |
| 724 } | 680 } |
| 725 | 681 |
| 726 | 682 |
| 727 static void* SenderEntry(void* arg) { | 683 class SignalSender : public Thread { |
| 728 Sampler::PlatformData* data = | 684 public: |
| 729 reinterpret_cast<Sampler::PlatformData*>(arg); | 685 enum SleepInterval { |
| 730 data->SignalSender(); | 686 HALF_INTERVAL, |
| 731 return 0; | 687 FULL_INTERVAL |
| 732 } | 688 }; |
| 689 | |
| 690 explicit SignalSender(int interval) | |
| 691 : Thread(NULL, "SignalSender"), | |
| 692 » thread_id_(pthread_self()), | |
|
Vitaly Repeshko
2011/03/28 12:02:30
Should be unused -- see below.
Ben Laurie (Chromium)
2011/03/28 12:08:48
Done.
| |
| 693 interval_(interval) {} | |
| 694 | |
| 695 static void AddActiveSampler(Sampler* sampler) { | |
| 696 ScopedLock lock(mutex_); | |
| 697 SamplerRegistry::AddActiveSampler(sampler); | |
| 698 if (instance_ == NULL) { | |
| 699 // Install a signal handler. | |
| 700 struct sigaction sa; | |
| 701 sa.sa_sigaction = ProfilerSignalHandler; | |
| 702 sigemptyset(&sa.sa_mask); | |
| 703 sa.sa_flags = SA_RESTART | SA_SIGINFO; | |
| 704 signal_handler_installed_ = | |
| 705 (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0); | |
| 706 | |
| 707 // Start a thread that sends SIGPROF signal to VM threads. | |
| 708 instance_ = new SignalSender(sampler->interval()); | |
| 709 instance_->Start(); | |
| 710 } else { | |
| 711 ASSERT(instance_->interval_ == sampler->interval()); | |
| 712 } | |
| 713 } | |
| 714 | |
| 715 static void RemoveActiveSampler(Sampler* sampler) { | |
| 716 ScopedLock lock(mutex_); | |
| 717 SamplerRegistry::RemoveActiveSampler(sampler); | |
| 718 if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) { | |
| 719 RuntimeProfiler::WakeUpRuntimeProfilerThreadBeforeShutdown(); | |
| 720 instance_->Join(); | |
| 721 delete instance_; | |
| 722 instance_ = NULL; | |
| 723 | |
| 724 // Restore the old signal handler. | |
| 725 if (signal_handler_installed_) { | |
| 726 sigaction(SIGPROF, &old_signal_handler_, 0); | |
| 727 signal_handler_installed_ = false; | |
| 728 } | |
| 729 } | |
| 730 } | |
| 731 | |
| 732 // Implement Thread::Run(). | |
| 733 virtual void Run() { | |
| 734 SamplerRegistry::State state; | |
| 735 while ((state = SamplerRegistry::GetState()) != | |
| 736 SamplerRegistry::HAS_NO_SAMPLERS) { | |
| 737 bool cpu_profiling_enabled = | |
| 738 (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS); | |
| 739 bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled(); | |
| 740 // When CPU profiling is enabled both JavaScript and C++ code is | |
| 741 // profiled. We must not suspend. | |
| 742 if (!cpu_profiling_enabled) { | |
| 743 if (rate_limiter_.SuspendIfNecessary()) continue; | |
| 744 } | |
| 745 if (cpu_profiling_enabled && runtime_profiler_enabled) { | |
| 746 if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) { | |
| 747 return; | |
| 748 } | |
| 749 Sleep(HALF_INTERVAL); | |
| 750 if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) { | |
| 751 return; | |
| 752 } | |
| 753 Sleep(HALF_INTERVAL); | |
| 754 } else { | |
| 755 if (cpu_profiling_enabled) { | |
| 756 if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, | |
| 757 this)) { | |
| 758 return; | |
| 759 } | |
| 760 } | |
| 761 if (runtime_profiler_enabled) { | |
| 762 if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, | |
| 763 NULL)) { | |
| 764 return; | |
| 765 } | |
| 766 } | |
| 767 Sleep(FULL_INTERVAL); | |
| 768 } | |
| 769 } | |
| 770 } | |
| 771 | |
| 772 static void DoCpuProfile(Sampler* sampler, void* raw_sender) { | |
| 773 if (!sampler->IsProfiling()) return; | |
| 774 SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender); | |
| 775 sender->SendProfilingSignal(sampler->platform_data()->vm_tid()); | |
| 776 } | |
| 777 | |
| 778 static void DoRuntimeProfile(Sampler* sampler, void* ignored) { | |
| 779 if (!sampler->isolate()->IsInitialized()) return; | |
| 780 sampler->isolate()->runtime_profiler()->NotifyTick(); | |
| 781 } | |
| 782 | |
| 783 void SendProfilingSignal(const pthread *tid) { | |
|
Vitaly Repeshko
2011/03/28 12:02:30
pthread_t
Ben Laurie (Chromium)
2011/03/28 12:08:48
Done.
| |
| 784 if (!signal_handler_installed_) return; | |
| 785 pthread_kill(thread_id_, SIGPROF); | |
|
Vitaly Repeshko
2011/03/28 12:02:30
Use the thread id parameter here.
Ben Laurie (Chromium)
2011/03/28 12:08:48
Done.
| |
| 786 } | |
| 787 | |
| 788 void Sleep(SleepInterval full_or_half) { | |
| 789 // Convert ms to us and subtract 100 us to compensate delays | |
| 790 // occuring during signal delivery. | |
| 791 useconds_t interval = interval_ * 1000 - 100; | |
| 792 if (full_or_half == HALF_INTERVAL) interval /= 2; | |
| 793 int result = usleep(interval); | |
| 794 #ifdef DEBUG | |
| 795 if (result != 0 && errno != EINTR) { | |
| 796 fprintf(stderr, | |
| 797 "SignalSender usleep error; interval = %u, errno = %d\n", | |
| 798 interval, | |
| 799 errno); | |
| 800 ASSERT(result == 0 || errno == EINTR); | |
| 801 } | |
| 802 #endif | |
| 803 USE(result); | |
| 804 } | |
| 805 | |
| 806 const pthread_t thread_id_; | |
| 807 const int interval_; | |
| 808 RuntimeProfilerRateLimiter rate_limiter_; | |
| 809 | |
| 810 // Protects the process wide state below. | |
| 811 static Mutex* mutex_; | |
| 812 static SignalSender* instance_; | |
| 813 static bool signal_handler_installed_; | |
| 814 static struct sigaction old_signal_handler_; | |
| 815 | |
| 816 DISALLOW_COPY_AND_ASSIGN(SignalSender); | |
| 817 }; | |
| 818 | |
| 819 Mutex* SignalSender::mutex_ = OS::CreateMutex(); | |
| 820 SignalSender* SignalSender::instance_ = NULL; | |
| 821 struct sigaction SignalSender::old_signal_handler_; | |
| 822 bool SignalSender::signal_handler_installed_ = false; | |
| 733 | 823 |
| 734 | 824 |
| 735 Sampler::Sampler(Isolate* isolate, int interval) | 825 Sampler::Sampler(Isolate* isolate, int interval) |
| 736 : isolate_(isolate), | 826 : isolate_(isolate), |
| 737 interval_(interval), | 827 interval_(interval), |
| 738 profiling_(false), | 828 profiling_(false), |
| 739 active_(false), | 829 active_(false), |
| 740 samples_taken_(0) { | 830 samples_taken_(0) { |
| 741 data_ = new PlatformData(this); | 831 data_ = new PlatformData; |
| 742 } | 832 } |
| 743 | 833 |
| 744 | 834 |
| 745 Sampler::~Sampler() { | 835 Sampler::~Sampler() { |
| 836 ASSERT(!IsActive()); | |
| 746 delete data_; | 837 delete data_; |
| 747 } | 838 } |
| 748 | 839 |
| 749 | 840 |
| 750 void Sampler::Start() { | 841 void Sampler::Start() { |
| 751 // There can only be one active sampler at the time on POSIX | |
| 752 // platforms. | |
| 753 ASSERT(!IsActive()); | 842 ASSERT(!IsActive()); |
| 754 vm_tid_ = GetThreadID(); | |
| 755 | |
| 756 // Request profiling signals. | |
| 757 struct sigaction sa; | |
| 758 sa.sa_sigaction = ProfilerSignalHandler; | |
| 759 sigemptyset(&sa.sa_mask); | |
| 760 sa.sa_flags = SA_SIGINFO; | |
| 761 if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return; | |
| 762 data_->signal_handler_installed_ = true; | |
| 763 | |
| 764 // Set the itimer to generate a tick for each interval. | |
| 765 itimerval itimer; | |
| 766 itimer.it_interval.tv_sec = interval_ / 1000; | |
| 767 itimer.it_interval.tv_usec = (interval_ % 1000) * 1000; | |
| 768 itimer.it_value.tv_sec = itimer.it_interval.tv_sec; | |
| 769 itimer.it_value.tv_usec = itimer.it_interval.tv_usec; | |
| 770 setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_); | |
| 771 | |
| 772 // Set this sampler as the active sampler. | |
| 773 active_sampler_ = this; | |
| 774 SetActive(true); | 843 SetActive(true); |
| 775 | 844 SignalSender::AddActiveSampler(this); |
| 776 // There's no way to send a signal to a thread on FreeBSD, but we can | |
| 777 // start a thread that uses the stack guard to interrupt the JS thread. | |
| 778 if (pthread_create( | |
| 779 &data_->signal_sender_thread_, NULL, SenderEntry, data_) == 0) { | |
| 780 data_->signal_sender_launched_ = true; | |
| 781 } | |
| 782 } | 845 } |
| 783 | 846 |
| 784 | 847 |
| 785 void Sampler::Stop() { | 848 void Sampler::Stop() { |
| 786 // This sampler is no longer the active sampler. | 849 ASSERT(IsActive()); |
| 787 active_sampler_ = NULL; | 850 SignalSender::RemoveActiveSampler(this); |
| 788 SetActive(false); | 851 SetActive(false); |
| 789 | |
| 790 // Wait for signal sender termination (it will exit after setting | |
| 791 // active_ to false). | |
| 792 if (data_->signal_sender_launched_) { | |
| 793 Top::WakeUpRuntimeProfilerThreadBeforeShutdown(); | |
| 794 pthread_join(data_->signal_sender_thread_, NULL); | |
| 795 data_->signal_sender_launched_ = false; | |
| 796 } | |
| 797 } | 852 } |
| 798 | 853 |
| 799 #endif // ENABLE_LOGGING_AND_PROFILING | 854 #endif // ENABLE_LOGGING_AND_PROFILING |
| 800 | 855 |
| 801 } } // namespace v8::internal | 856 } } // namespace v8::internal |
| OLD | NEW |