| Index: src/platform-freebsd.cc
|
| ===================================================================
|
| --- src/platform-freebsd.cc (revision 7178)
|
| +++ src/platform-freebsd.cc (working copy)
|
| @@ -42,6 +42,7 @@
|
| #include <sys/stat.h> // open
|
| #include <sys/fcntl.h> // open
|
| #include <unistd.h> // getpagesize
|
| +// If you don't have execinfo.h then you need devel/libexecinfo from ports.
|
| #include <execinfo.h> // backtrace, backtrace_symbols
|
| #include <strings.h> // index
|
| #include <errno.h>
|
| @@ -526,6 +527,16 @@
|
| return result;
|
| }
|
|
|
| + virtual bool TryLock() {
|
| + int result = pthread_mutex_trylock(&mutex_);
|
| + // Return false if the lock is busy and locking failed.
|
| + if (result == EBUSY) {
|
| + return false;
|
| + }
|
| + ASSERT(result == 0); // Verify no other errors.
|
| + return true;
|
| + }
|
| +
|
| private:
|
| pthread_mutex_t mutex_; // Pthread mutex for POSIX platforms.
|
| };
|
| @@ -595,60 +606,124 @@
|
| #ifdef ENABLE_LOGGING_AND_PROFILING
|
|
|
| static Sampler* active_sampler_ = NULL;
|
| +static pthread_t vm_tid_ = NULL;
|
|
|
| +
|
| +static pthread_t GetThreadID() {
|
| + pthread_t thread_id = pthread_self();
|
| + return thread_id;
|
| +}
|
| +
|
| +
|
| +class Sampler::PlatformData : public Malloced {
|
| + public:
|
| + enum SleepInterval {
|
| + FULL_INTERVAL,
|
| + HALF_INTERVAL
|
| + };
|
| +
|
| + PlatformData(Sampler* sampler)
|
| + : sampler_(sampler),
|
| + signal_handler_installed_(false),
|
| + signal_sender_launched_(false) {
|
| + }
|
| +
|
| + void SignalSender() {
|
| + while (sampler_->IsActive()) {
|
| + if (rate_limiter_.SuspendIfNecessary()) continue;
|
| + if (sampler_->IsProfiling() && RuntimeProfiler::IsEnabled()) {
|
| + Sleep(FULL_INTERVAL);
|
| + RuntimeProfiler::NotifyTick();
|
| + } else {
|
| + if (RuntimeProfiler::IsEnabled()) RuntimeProfiler::NotifyTick();
|
| + Sleep(FULL_INTERVAL);
|
| + }
|
| + }
|
| + }
|
| +
|
| + 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_;
|
| + bool signal_sender_launched_;
|
| + pthread_t signal_sender_thread_;
|
| + RuntimeProfilerRateLimiter rate_limiter_;
|
| +};
|
| +
|
| +
|
| static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
|
| USE(info);
|
| if (signal != SIGPROF) return;
|
| if (active_sampler_ == NULL) return;
|
| + if (!active_sampler_->IsActive()) {
|
| + // Restore old signal handler
|
| + Sampler::PlatformData* data = active_sampler_->data();
|
| + if (data->signal_handler_installed_) {
|
| + sigaction(SIGPROF, &data->old_signal_handler_, 0);
|
| + data->signal_handler_installed_ = false;
|
| + }
|
| + return;
|
| + }
|
|
|
| - TickSample sample;
|
| -
|
| - // We always sample the VM state.
|
| - sample.state = VMState::current_state();
|
| -
|
| - // If profiling, we extract the current pc and sp.
|
| - if (active_sampler_->IsProfiling()) {
|
| - // Extracting the sample from the context is extremely machine dependent.
|
| - ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
|
| - mcontext_t& mcontext = ucontext->uc_mcontext;
|
| + if (vm_tid_ != GetThreadID()) return;
|
| +
|
| + TickSample sample_obj;
|
| + TickSample* sample = CpuProfiler::TickSampleEvent();
|
| + if (sample == NULL) sample = &sample_obj;
|
| +
|
| + // Extracting the sample from the context is extremely machine dependent.
|
| + ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
|
| + mcontext_t& mcontext = ucontext->uc_mcontext;
|
| #if V8_HOST_ARCH_IA32
|
| - sample.pc = reinterpret_cast<Address>(mcontext.mc_eip);
|
| - sample.sp = reinterpret_cast<Address>(mcontext.mc_esp);
|
| - sample.fp = reinterpret_cast<Address>(mcontext.mc_ebp);
|
| + sample->pc = reinterpret_cast<Address>(mcontext.mc_eip);
|
| + sample->sp = reinterpret_cast<Address>(mcontext.mc_esp);
|
| + sample->fp = reinterpret_cast<Address>(mcontext.mc_ebp);
|
| #elif V8_HOST_ARCH_X64
|
| - sample.pc = reinterpret_cast<Address>(mcontext.mc_rip);
|
| - sample.sp = reinterpret_cast<Address>(mcontext.mc_rsp);
|
| - sample.fp = reinterpret_cast<Address>(mcontext.mc_rbp);
|
| + sample->pc = reinterpret_cast<Address>(mcontext.mc_rip);
|
| + sample->sp = reinterpret_cast<Address>(mcontext.mc_rsp);
|
| + sample->fp = reinterpret_cast<Address>(mcontext.mc_rbp);
|
| #elif V8_HOST_ARCH_ARM
|
| - sample.pc = reinterpret_cast<Address>(mcontext.mc_r15);
|
| - sample.sp = reinterpret_cast<Address>(mcontext.mc_r13);
|
| - sample.fp = reinterpret_cast<Address>(mcontext.mc_r11);
|
| + sample->pc = reinterpret_cast<Address>(mcontext.mc_r15);
|
| + sample->sp = reinterpret_cast<Address>(mcontext.mc_r13);
|
| + sample->fp = reinterpret_cast<Address>(mcontext.mc_r11);
|
| #endif
|
| - active_sampler_->SampleStack(&sample);
|
| - }
|
| -
|
| - active_sampler_->Tick(&sample);
|
| + active_sampler_->SampleStack(sample);
|
| + active_sampler_->Tick(sample);
|
| }
|
|
|
|
|
| -class Sampler::PlatformData : public Malloced {
|
| - public:
|
| - PlatformData() {
|
| - signal_handler_installed_ = false;
|
| - }
|
| +static void* SenderEntry(void* arg) {
|
| + Sampler::PlatformData* data =
|
| + reinterpret_cast<Sampler::PlatformData*>(arg);
|
| + data->SignalSender();
|
| + return 0;
|
| +}
|
|
|
| - bool signal_handler_installed_;
|
| - struct sigaction old_signal_handler_;
|
| - struct itimerval old_timer_value_;
|
| -};
|
|
|
| -
|
| Sampler::Sampler(int interval)
|
| : interval_(interval),
|
| profiling_(false),
|
| active_(false),
|
| samples_taken_(0) {
|
| - data_ = new PlatformData();
|
| + data_ = new PlatformData(this);
|
| }
|
|
|
|
|
| @@ -660,7 +735,8 @@
|
| 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;
|
| @@ -680,21 +756,30 @@
|
|
|
| // Set this sampler as the active sampler.
|
| active_sampler_ = this;
|
| - active_ = true;
|
| + SetActive(true);
|
| +
|
| + // There's no way to send a signal to a thread on FreeBSD, but we can
|
| + // start a thread that uses the stack guard to interrupt the JS thread.
|
| + if (pthread_create(
|
| + &data_->signal_sender_thread_, NULL, SenderEntry, data_) == 0) {
|
| + data_->signal_sender_launched_ = true;
|
| + }
|
| }
|
|
|
|
|
| void Sampler::Stop() {
|
| - // 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;
|
| + 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;
|
| }
|
|
|
| - // This sampler is no longer the active sampler.
|
| - active_sampler_ = NULL;
|
| - active_ = false;
|
| }
|
|
|
| #endif // ENABLE_LOGGING_AND_PROFILING
|
|
|