Chromium Code Reviews| Index: src/platform-solaris.cc |
| diff --git a/src/platform-solaris.cc b/src/platform-solaris.cc |
| index ebe0475f4d3f123afca187d792338104196bcc33..833bea7e44cfcc9331d4eb4a7e90c4b8f8ecb673 100644 |
| --- a/src/platform-solaris.cc |
| +++ b/src/platform-solaris.cc |
| @@ -612,11 +612,16 @@ static Sampler* active_sampler_ = NULL; |
| static pthread_t vm_tid_ = 0; |
| +static pthread_t GetThreadID() { |
| + return pthread_self(); |
| +} |
| + |
| + |
| static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { |
| USE(info); |
| if (signal != SIGPROF) return; |
| if (active_sampler_ == NULL || !active_sampler_->IsActive()) return; |
| - if (vm_tid_ != pthread_self()) return; |
| + if (vm_tid_ != GetThreadID()) return; |
| TickSample sample_obj; |
| TickSample* sample = CpuProfiler::TickSampleEvent(); |
| @@ -645,26 +650,86 @@ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { |
| class Sampler::PlatformData : public Malloced { |
| public: |
| - PlatformData() { |
| - signal_handler_installed_ = false; |
| + enum SleepInterval { |
| + FULL_INTERVAL, |
| + HALF_INTERVAL |
| + }; |
| + |
| + explicit PlatformData(Sampler* sampler) |
| + : sampler_(sampler), |
| + signal_handler_installed_(false), |
| + vm_tgid_(getpid()), |
| + signal_sender_launched_(false) { |
| + } |
| + |
| + void SignalSender() { |
| + while (sampler_->IsActive()) { |
| + if (rate_limiter_.SuspendIfNecessary()) continue; |
| + if (sampler_->IsProfiling() && RuntimeProfiler::IsEnabled()) { |
| + SendProfilingSignal(); |
| + Sleep(HALF_INTERVAL); |
| + RuntimeProfiler::NotifyTick(); |
| + Sleep(HALF_INTERVAL); |
| + } else { |
| + if (sampler_->IsProfiling()) SendProfilingSignal(); |
| + if (RuntimeProfiler::IsEnabled()) RuntimeProfiler::NotifyTick(); |
| + Sleep(FULL_INTERVAL); |
| + } |
| + } |
| + } |
| + |
| + void SendProfilingSignal() { |
| + if (!signal_handler_installed_) return; |
| + pthread_kill(vm_tgid_, SIGPROF); |
|
Vitaly Repeshko
2011/03/11 00:08:27
Does work with vm_tid_ here?
Vyacheslav Egorov (Chromium)
2011/03/11 00:30:47
This looks really suspicious. vm_tgid_ is not a pt
ry
2011/03/11 01:02:00
Oops. With that I get crashes
Vitaly Repeshko
2011/03/11 01:08:46
So if it crashes because of a stale thread handle,
|
| + } |
| + |
| + void Sleep(SleepInterval full_or_half) { |
| + // Convert ms to us and subtract 100 us to compensate delays |
| + // occuring during signal delivery. |
| + useconds_t interval = sampler_->interval_ * 1000 - 100; |
| + if (full_or_half == HALF_INTERVAL) interval /= 2; |
| + int result = usleep(interval); |
| +#ifdef DEBUG |
| + if (result != 0 && errno != EINTR) { |
| + fprintf(stderr, |
| + "SignalSender usleep error; interval = %u, errno = %d\n", |
| + interval, |
| + errno); |
| + ASSERT(result == 0 || errno == EINTR); |
| + } |
| +#endif |
| + USE(result); |
| } |
| + Sampler* sampler_; |
| bool signal_handler_installed_; |
| struct sigaction old_signal_handler_; |
| - struct itimerval old_timer_value_; |
| + int vm_tgid_; |
| + bool signal_sender_launched_; |
| + pthread_t signal_sender_thread_; |
| + RuntimeProfilerRateLimiter rate_limiter_; |
| }; |
| +static void* SenderEntry(void* arg) { |
| + Sampler::PlatformData* data = |
| + reinterpret_cast<Sampler::PlatformData*>(arg); |
| + data->SignalSender(); |
| + return 0; |
| +} |
| + |
| + |
| Sampler::Sampler(int interval) |
| : interval_(interval), |
| profiling_(false), |
| active_(false), |
| samples_taken_(0) { |
| - data_ = new PlatformData(); |
| + data_ = new PlatformData(this); |
| } |
| Sampler::~Sampler() { |
| + ASSERT(!data_->signal_sender_launched_); |
| delete data_; |
| } |
| @@ -672,43 +737,53 @@ Sampler::~Sampler() { |
| void Sampler::Start() { |
| // There can only be one active sampler at the time on POSIX |
| // platforms. |
| - if (active_sampler_ != NULL) return; |
| + ASSERT(!IsActive()); |
| + vm_tid_ = GetThreadID(); |
| // Request profiling signals. |
| struct sigaction sa; |
| sa.sa_sigaction = ProfilerSignalHandler; |
| sigemptyset(&sa.sa_mask); |
| - sa.sa_flags = SA_SIGINFO; |
| - if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return; |
| - data_->signal_handler_installed_ = true; |
| - |
| - // Set the itimer to generate a tick for each interval. |
| - itimerval itimer; |
| - itimer.it_interval.tv_sec = interval_ / 1000; |
| - itimer.it_interval.tv_usec = (interval_ % 1000) * 1000; |
| - itimer.it_value.tv_sec = itimer.it_interval.tv_sec; |
| - itimer.it_value.tv_usec = itimer.it_interval.tv_usec; |
| - setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_); |
| + sa.sa_flags = SA_RESTART | SA_SIGINFO; |
| + data_->signal_handler_installed_ = |
| + sigaction(SIGPROF, &sa, &data_->old_signal_handler_) == 0; |
| + |
| + // Start a thread that sends SIGPROF signal to VM thread. |
| + // Sending the signal ourselves instead of relying on itimer provides |
| + // much better accuracy. |
| + SetActive(true); |
| + if (pthread_create( |
| + &data_->signal_sender_thread_, NULL, SenderEntry, data_) == 0) { |
| + data_->signal_sender_launched_ = true; |
| + } |
| // Set this sampler as the active sampler. |
| active_sampler_ = this; |
| - active_ = true; |
| } |
| void Sampler::Stop() { |
| + SetActive(false); |
| + |
| + // Wait for signal sender termination (it will exit after setting |
| + // active_ to false). |
| + if (data_->signal_sender_launched_) { |
| + Top::WakeUpRuntimeProfilerThreadBeforeShutdown(); |
| + pthread_join(data_->signal_sender_thread_, NULL); |
| + data_->signal_sender_launched_ = false; |
| + } |
| + |
| // Restore old signal handler |
| if (data_->signal_handler_installed_) { |
| - setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL); |
| sigaction(SIGPROF, &data_->old_signal_handler_, 0); |
| data_->signal_handler_installed_ = false; |
| } |
| // This sampler is no longer the active sampler. |
| active_sampler_ = NULL; |
| - active_ = false; |
| } |
| + |
| #endif // ENABLE_LOGGING_AND_PROFILING |
| } } // namespace v8::internal |