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 15 matching lines...) Expand all Loading... |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
28 // Platform specific code for Linux goes here. For the POSIX comaptible parts | 28 // Platform specific code for Linux goes here. For the POSIX comaptible parts |
29 // the implementation is in platform-posix.cc. | 29 // the implementation is in platform-posix.cc. |
30 | 30 |
31 #include <pthread.h> | 31 #include <pthread.h> |
32 #include <semaphore.h> | 32 #include <semaphore.h> |
33 #include <signal.h> | 33 #include <signal.h> |
34 #include <sys/time.h> | 34 #include <sys/time.h> |
35 #include <sys/resource.h> | 35 #include <sys/resource.h> |
| 36 #include <sys/syscall.h> |
36 #include <sys/types.h> | 37 #include <sys/types.h> |
37 #include <stdlib.h> | 38 #include <stdlib.h> |
38 | 39 |
39 // Ubuntu Dapper requires memory pages to be marked as | 40 // Ubuntu Dapper requires memory pages to be marked as |
40 // executable. Otherwise, OS raises an exception when executing code | 41 // executable. Otherwise, OS raises an exception when executing code |
41 // in that page. | 42 // in that page. |
42 #include <sys/types.h> // mmap & munmap | 43 #include <sys/types.h> // mmap & munmap |
43 #include <sys/mman.h> // mmap & munmap | 44 #include <sys/mman.h> // mmap & munmap |
44 #include <sys/stat.h> // open | 45 #include <sys/stat.h> // open |
45 #include <fcntl.h> // open | 46 #include <fcntl.h> // open |
(...skipping 661 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
707 | 708 |
708 | 709 |
709 Semaphore* OS::CreateSemaphore(int count) { | 710 Semaphore* OS::CreateSemaphore(int count) { |
710 return new LinuxSemaphore(count); | 711 return new LinuxSemaphore(count); |
711 } | 712 } |
712 | 713 |
713 | 714 |
714 #ifdef ENABLE_LOGGING_AND_PROFILING | 715 #ifdef ENABLE_LOGGING_AND_PROFILING |
715 | 716 |
716 static Sampler* active_sampler_ = NULL; | 717 static Sampler* active_sampler_ = NULL; |
717 static pthread_t vm_thread_ = 0; | |
718 | 718 |
719 | 719 |
720 #if !defined(__GLIBC__) && (defined(__arm__) || defined(__thumb__)) | 720 #if !defined(__GLIBC__) && (defined(__arm__) || defined(__thumb__)) |
721 // Android runs a fairly new Linux kernel, so signal info is there, | 721 // Android runs a fairly new Linux kernel, so signal info is there, |
722 // but the C library doesn't have the structs defined. | 722 // but the C library doesn't have the structs defined. |
723 | 723 |
724 struct sigcontext { | 724 struct sigcontext { |
725 uint32_t trap_no; | 725 uint32_t trap_no; |
726 uint32_t error_code; | 726 uint32_t error_code; |
727 uint32_t oldmask; | 727 uint32_t oldmask; |
728 uint32_t gregs[16]; | 728 uint32_t gregs[16]; |
729 uint32_t arm_cpsr; | 729 uint32_t arm_cpsr; |
730 uint32_t fault_address; | 730 uint32_t fault_address; |
731 }; | 731 }; |
732 typedef uint32_t __sigset_t; | 732 typedef uint32_t __sigset_t; |
733 typedef struct sigcontext mcontext_t; | 733 typedef struct sigcontext mcontext_t; |
734 typedef struct ucontext { | 734 typedef struct ucontext { |
735 uint32_t uc_flags; | 735 uint32_t uc_flags; |
736 struct ucontext* uc_link; | 736 struct ucontext* uc_link; |
737 stack_t uc_stack; | 737 stack_t uc_stack; |
738 mcontext_t uc_mcontext; | 738 mcontext_t uc_mcontext; |
739 __sigset_t uc_sigmask; | 739 __sigset_t uc_sigmask; |
740 } ucontext_t; | 740 } ucontext_t; |
741 enum ArmRegisters {R15 = 15, R13 = 13, R11 = 11}; | 741 enum ArmRegisters {R15 = 15, R13 = 13, R11 = 11}; |
742 | 742 |
743 #endif | 743 #endif |
744 | 744 |
745 | 745 |
746 // A function that determines if a signal handler is called in the context | |
747 // of a VM thread. | |
748 // | |
749 // The problem is that SIGPROF signal can be delivered to an arbitrary thread | |
750 // (see http://code.google.com/p/google-perftools/issues/detail?id=106#c2) | |
751 // So, if the signal is being handled in the context of a non-VM thread, | |
752 // it means that the VM thread is running, and trying to sample its stack can | |
753 // cause a crash. | |
754 static inline bool IsVmThread() { | |
755 // In the case of a single VM thread, this check is enough. | |
756 if (pthread_equal(pthread_self(), vm_thread_)) return true; | |
757 // If there are multiple threads that use VM, they must have a thread id | |
758 // stored in TLS. To verify that the thread is really executing VM, | |
759 // we check Top's data. Having that ThreadManager::RestoreThread first | |
760 // restores ThreadLocalTop from TLS, and only then erases the TLS value, | |
761 // reading Top::thread_id() should not be affected by races. | |
762 if (ThreadManager::HasId() && !ThreadManager::IsArchived() && | |
763 ThreadManager::CurrentId() == Top::thread_id()) { | |
764 return true; | |
765 } | |
766 return false; | |
767 } | |
768 | |
769 | |
770 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { | 746 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { |
771 #ifndef V8_HOST_ARCH_MIPS | 747 #ifndef V8_HOST_ARCH_MIPS |
772 USE(info); | 748 USE(info); |
773 if (signal != SIGPROF) return; | 749 if (signal != SIGPROF) return; |
774 if (active_sampler_ == NULL) return; | 750 if (active_sampler_ == NULL) return; |
775 if (!IsVmThread()) return; | |
776 | 751 |
777 TickSample sample_obj; | 752 TickSample sample_obj; |
778 TickSample* sample = CpuProfiler::TickSampleEvent(); | 753 TickSample* sample = CpuProfiler::TickSampleEvent(); |
779 if (sample == NULL) sample = &sample_obj; | 754 if (sample == NULL) sample = &sample_obj; |
780 | 755 |
781 // We always sample the VM state. | 756 // We always sample the VM state. |
782 sample->state = VMState::current_state(); | 757 sample->state = VMState::current_state(); |
783 | 758 |
784 // If profiling, we extract the current pc and sp. | 759 // If profiling, we extract the current pc and sp. |
785 if (active_sampler_->IsProfiling()) { | 760 if (active_sampler_->IsProfiling()) { |
(...skipping 26 matching lines...) Expand all Loading... |
812 active_sampler_->SampleStack(sample); | 787 active_sampler_->SampleStack(sample); |
813 } | 788 } |
814 | 789 |
815 active_sampler_->Tick(sample); | 790 active_sampler_->Tick(sample); |
816 #endif | 791 #endif |
817 } | 792 } |
818 | 793 |
819 | 794 |
820 class Sampler::PlatformData : public Malloced { | 795 class Sampler::PlatformData : public Malloced { |
821 public: | 796 public: |
822 PlatformData() { | 797 explicit PlatformData(Sampler* sampler) |
823 signal_handler_installed_ = false; | 798 : sampler_(sampler), |
| 799 signal_handler_installed_(false), |
| 800 vm_tgid_(getpid()), |
| 801 // Glibc doesn't provide a wrapper for gettid(2). |
| 802 vm_tid_(syscall(SYS_gettid)), |
| 803 signal_sender_launched_(false) { |
824 } | 804 } |
825 | 805 |
| 806 void SignalSender() { |
| 807 while (sampler_->IsActive()) { |
| 808 // Glibc doesn't provide a wrapper for tgkill(2). |
| 809 syscall(SYS_tgkill, vm_tgid_, vm_tid_, SIGPROF); |
| 810 // Convert ms to us and subtract 100 us to compensate delays |
| 811 // occuring during signal delivery. |
| 812 int result = usleep(sampler_->interval_ * 1000 - 100); |
| 813 ASSERT(result == 0 || errno == EINTR); |
| 814 USE(result); |
| 815 } |
| 816 } |
| 817 |
| 818 Sampler* sampler_; |
826 bool signal_handler_installed_; | 819 bool signal_handler_installed_; |
827 struct sigaction old_signal_handler_; | 820 struct sigaction old_signal_handler_; |
828 struct itimerval old_timer_value_; | 821 int vm_tgid_; |
| 822 int vm_tid_; |
| 823 bool signal_sender_launched_; |
| 824 pthread_t signal_sender_thread_; |
829 }; | 825 }; |
830 | 826 |
831 | 827 |
| 828 static void* SenderEntry(void* arg) { |
| 829 Sampler::PlatformData* data = |
| 830 reinterpret_cast<Sampler::PlatformData*>(arg); |
| 831 data->SignalSender(); |
| 832 return 0; |
| 833 } |
| 834 |
| 835 |
832 Sampler::Sampler(int interval, bool profiling) | 836 Sampler::Sampler(int interval, bool profiling) |
833 : interval_(interval), | 837 : interval_(interval), |
834 profiling_(profiling), | 838 profiling_(profiling), |
835 synchronous_(profiling), | 839 synchronous_(profiling), |
836 active_(false) { | 840 active_(false) { |
837 data_ = new PlatformData(); | 841 data_ = new PlatformData(this); |
838 } | 842 } |
839 | 843 |
840 | 844 |
841 Sampler::~Sampler() { | 845 Sampler::~Sampler() { |
842 delete data_; | 846 delete data_; |
843 } | 847 } |
844 | 848 |
845 | 849 |
846 void Sampler::Start() { | 850 void Sampler::Start() { |
847 // There can only be one active sampler at the time on POSIX | 851 // There can only be one active sampler at the time on POSIX |
848 // platforms. | 852 // platforms. |
849 if (active_sampler_ != NULL) return; | 853 if (active_sampler_ != NULL) return; |
850 | 854 |
851 vm_thread_ = pthread_self(); | |
852 | |
853 // Request profiling signals. | 855 // Request profiling signals. |
854 struct sigaction sa; | 856 struct sigaction sa; |
855 sa.sa_sigaction = ProfilerSignalHandler; | 857 sa.sa_sigaction = ProfilerSignalHandler; |
856 sigemptyset(&sa.sa_mask); | 858 sigemptyset(&sa.sa_mask); |
857 sa.sa_flags = SA_SIGINFO; | 859 sa.sa_flags = SA_SIGINFO; |
858 if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return; | 860 if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return; |
859 data_->signal_handler_installed_ = true; | 861 data_->signal_handler_installed_ = true; |
860 | 862 |
861 // Set the itimer to generate a tick for each interval. | 863 // Start a thread that sends SIGPROF signal to VM thread. |
862 itimerval itimer; | 864 // Sending the signal ourselves instead of relying on itimer provides |
863 itimer.it_interval.tv_sec = interval_ / 1000; | 865 // much better accuracy. |
864 itimer.it_interval.tv_usec = (interval_ % 1000) * 1000; | 866 active_ = true; |
865 itimer.it_value.tv_sec = itimer.it_interval.tv_sec; | 867 if (pthread_create( |
866 itimer.it_value.tv_usec = itimer.it_interval.tv_usec; | 868 &data_->signal_sender_thread_, NULL, SenderEntry, data_) == 0) { |
867 setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_); | 869 data_->signal_sender_launched_ = true; |
| 870 } |
868 | 871 |
869 // Set this sampler as the active sampler. | 872 // Set this sampler as the active sampler. |
870 active_sampler_ = this; | 873 active_sampler_ = this; |
871 active_ = true; | |
872 } | 874 } |
873 | 875 |
874 | 876 |
875 void Sampler::Stop() { | 877 void Sampler::Stop() { |
| 878 active_ = false; |
| 879 |
| 880 // Wait for signal sender termination (it will exit after setting |
| 881 // active_ to false). |
| 882 if (data_->signal_sender_launched_) { |
| 883 pthread_join(data_->signal_sender_thread_, NULL); |
| 884 data_->signal_sender_launched_ = false; |
| 885 } |
| 886 |
876 // Restore old signal handler | 887 // Restore old signal handler |
877 if (data_->signal_handler_installed_) { | 888 if (data_->signal_handler_installed_) { |
878 setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL); | |
879 sigaction(SIGPROF, &data_->old_signal_handler_, 0); | 889 sigaction(SIGPROF, &data_->old_signal_handler_, 0); |
880 data_->signal_handler_installed_ = false; | 890 data_->signal_handler_installed_ = false; |
881 } | 891 } |
882 | 892 |
883 // This sampler is no longer the active sampler. | 893 // This sampler is no longer the active sampler. |
884 active_sampler_ = NULL; | 894 active_sampler_ = NULL; |
885 active_ = false; | |
886 } | 895 } |
887 | 896 |
888 | 897 |
889 #endif // ENABLE_LOGGING_AND_PROFILING | 898 #endif // ENABLE_LOGGING_AND_PROFILING |
890 | 899 |
891 } } // namespace v8::internal | 900 } } // namespace v8::internal |
OLD | NEW |