Chromium Code Reviews| Index: src/platform-solaris.cc |
| diff --git a/src/platform-solaris.cc b/src/platform-solaris.cc |
| index dd4bd5d7c560f3b191ebaad036a3483fed7d27eb..cc1a4fb7ce3fa20d80ac7a0f126b059d8555b10c 100644 |
| --- a/src/platform-solaris.cc |
| +++ b/src/platform-solaris.cc |
| @@ -88,6 +88,7 @@ double ceiling(double x) { |
| } |
| +static Mutex* limit_mutex = NULL; |
| void OS::Setup() { |
| // Seed the random number generator. |
| // Convert the current time to a 64-bit integer first, before converting it |
| @@ -96,6 +97,7 @@ void OS::Setup() { |
| // call this setup code within the same millisecond. |
| uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); |
| srandom(static_cast<unsigned int>(seed)); |
| + limit_mutex = CreateMutex(); |
| } |
| @@ -145,6 +147,9 @@ static void* highest_ever_allocated = reinterpret_cast<void*>(0); |
| static void UpdateAllocatedSpaceLimits(void* address, int size) { |
| + ASSERT(limit_mutex != NULL); |
| + ScopedLock lock(limit_mutex); |
| + |
| lowest_ever_allocated = Min(lowest_ever_allocated, address); |
| highest_ever_allocated = |
| Max(highest_ever_allocated, |
| @@ -407,7 +412,6 @@ static void* ThreadEntry(void* arg) { |
| // one) so we initialize it here too. |
| thread->data()->thread_ = pthread_self(); |
| ASSERT(thread->data()->thread_ != kNoThread); |
| - Thread::SetThreadLocal(Isolate::isolate_key(), thread->isolate()); |
| thread->Run(); |
| return NULL; |
| } |
| @@ -587,78 +591,162 @@ Semaphore* OS::CreateSemaphore(int count) { |
| #ifdef ENABLE_LOGGING_AND_PROFILING |
| -static Sampler* active_sampler_ = NULL; |
| -static pthread_t vm_tid_ = 0; |
| - |
| - |
| static pthread_t GetThreadID() { |
| return pthread_self(); |
| } |
| +class Sampler::PlatformData : public Malloced { |
| + public: |
| + PlatformData() : vm_tid_(GetThreadID()) {} |
| + |
| + pthread_t vm_tid() const { return vm_tid_; } |
| + |
| + private: |
| + pthread_t vm_tid_; |
| +}; |
| + |
| 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_ != GetThreadID()) return; |
| + Isolate* isolate = Isolate::UncheckedCurrent(); |
| + if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) { |
| + // We require a fully initialized and entered isolate. |
| + return; |
| + } |
| + if (v8::Locker::IsActive() && |
| + !isolate->thread_manager()->IsLockedByCurrentThread()) { |
| + return; |
| + } |
| + |
| + Sampler* sampler = isolate->logger()->sampler(); |
| + if (sampler == NULL || !sampler->IsActive()) return; |
| TickSample sample_obj; |
| - TickSample* sample = CpuProfiler::TickSampleEvent(); |
| + TickSample* sample = CpuProfiler::TickSampleEvent(isolate); |
| 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; |
| - sample->state = Top::current_vm_state(); |
| + sample->state = isolate->current_vm_state(); |
| sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_PC]); |
| sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_SP]); |
| sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_FP]); |
| - active_sampler_->SampleStack(sample); |
| - active_sampler_->Tick(sample); |
| + sampler->SampleStack(sample); |
| + sampler->Tick(sample); |
| } |
| - |
| -class Sampler::PlatformData : public Malloced { |
| +class SignalSender : public Thread { |
| public: |
| enum SleepInterval { |
| - FULL_INTERVAL, |
| - HALF_INTERVAL |
| + HALF_INTERVAL, |
| + FULL_INTERVAL |
| }; |
| - explicit PlatformData(Sampler* sampler) |
| - : sampler_(sampler), |
| - signal_handler_installed_(false), |
| - vm_tgid_(getpid()), |
| - signal_sender_launched_(false) { |
| + explicit SignalSender(int interval) |
| + : Thread("SignalSender"), |
| + interval_(interval) {} |
| + |
| + static void AddActiveSampler(Sampler* sampler) { |
| + ScopedLock lock(mutex_); |
| + SamplerRegistry::AddActiveSampler(sampler); |
| + if (instance_ == NULL) { |
| + // Install a signal handler. |
| + struct sigaction sa; |
| + sa.sa_sigaction = ProfilerSignalHandler; |
| + sigemptyset(&sa.sa_mask); |
| + sa.sa_flags = SA_RESTART | SA_SIGINFO; |
| + signal_handler_installed_ = |
| + (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0); |
| + |
| + // Start a thread that sends SIGPROF signal to VM threads. |
| + instance_ = new SignalSender(sampler->interval()); |
| + instance_->Start(); |
| + } else { |
| + ASSERT(instance_->interval_ == sampler->interval()); |
| + } |
| + } |
| + |
| + static void RemoveActiveSampler(Sampler* sampler) { |
| + ScopedLock lock(mutex_); |
| + SamplerRegistry::RemoveActiveSampler(sampler); |
| + if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) { |
| + RuntimeProfiler::WakeUpRuntimeProfilerThreadBeforeShutdown(); |
| + instance_->Join(); |
| + delete instance_; |
| + instance_ = NULL; |
| + |
| + // Restore the old signal handler. |
| + if (signal_handler_installed_) { |
| + sigaction(SIGPROF, &old_signal_handler_, 0); |
| + signal_handler_installed_ = false; |
| + } |
| + } |
| } |
| - void SignalSender() { |
| - while (sampler_->IsActive()) { |
| - if (rate_limiter_.SuspendIfNecessary()) continue; |
| - if (sampler_->IsProfiling() && RuntimeProfiler::IsEnabled()) { |
| - SendProfilingSignal(); |
| + // Implement Thread::Run(). |
| + virtual void Run() { |
|
Mads Ager (chromium)
2011/06/30 07:20:46
The Run method has not been updated to completely
|
| + SamplerRegistry::State state; |
| + while ((state = SamplerRegistry::GetState()) != |
| + SamplerRegistry::HAS_NO_SAMPLERS) { |
| + bool cpu_profiling_enabled = |
| + (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS); |
| + bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled(); |
| + // When CPU profiling is enabled both JavaScript and C++ code is |
| + // profiled. We must not suspend. |
| + if (!cpu_profiling_enabled) { |
| + if (rate_limiter_.SuspendIfNecessary()) continue; |
| + } |
| + if (cpu_profiling_enabled && runtime_profiler_enabled) { |
| + if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) { |
| + return; |
| + } |
| Sleep(HALF_INTERVAL); |
| - RuntimeProfiler::NotifyTick(); |
| + if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) { |
| + return; |
| + } |
| Sleep(HALF_INTERVAL); |
| } else { |
| - if (sampler_->IsProfiling()) SendProfilingSignal(); |
| - if (RuntimeProfiler::IsEnabled()) RuntimeProfiler::NotifyTick(); |
| + if (cpu_profiling_enabled) { |
| + if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, |
| + this)) { |
| + return; |
| + } |
| + } |
| + if (runtime_profiler_enabled) { |
| + if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, |
| + NULL)) { |
| + return; |
| + } |
| + } |
| Sleep(FULL_INTERVAL); |
| } |
| } |
| } |
| - void SendProfilingSignal() { |
| + static void DoCpuProfile(Sampler* sampler, void* raw_sender) { |
| + if (!sampler->IsProfiling()) return; |
| + SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender); |
| + sender->SendProfilingSignal(sampler->platform_data()->vm_tid()); |
| + } |
| + |
| + static void DoRuntimeProfile(Sampler* sampler, void* ignored) { |
| + if (!sampler->isolate()->IsInitialized()) return; |
| + sampler->isolate()->runtime_profiler()->NotifyTick(); |
| + } |
| + |
| + void SendProfilingSignal(pthread_t tid) { |
| if (!signal_handler_installed_) return; |
| - pthread_kill(vm_tid_, SIGPROF); |
| + pthread_kill(tid, SIGPROF); |
| } |
| 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; |
| + useconds_t interval = interval_ * 1000 - 100; |
| if (full_or_half == HALF_INTERVAL) interval /= 2; |
| int result = usleep(interval); |
| #ifdef DEBUG |
| @@ -673,22 +761,22 @@ class Sampler::PlatformData : public Malloced { |
| USE(result); |
| } |
| - Sampler* sampler_; |
| - bool signal_handler_installed_; |
| - struct sigaction old_signal_handler_; |
| - int vm_tgid_; |
| - bool signal_sender_launched_; |
| - pthread_t signal_sender_thread_; |
| + const int interval_; |
| RuntimeProfilerRateLimiter rate_limiter_; |
| -}; |
| + // Protects the process wide state below. |
| + static Mutex* mutex_; |
| + static SignalSender* instance_; |
| + static bool signal_handler_installed_; |
| + static struct sigaction old_signal_handler_; |
| -static void* SenderEntry(void* arg) { |
| - Sampler::PlatformData* data = |
| - reinterpret_cast<Sampler::PlatformData*>(arg); |
| - data->SignalSender(); |
| - return 0; |
| -} |
| + DISALLOW_COPY_AND_ASSIGN(SignalSender); |
| +}; |
| + |
| +Mutex* SignalSender::mutex_ = OS::CreateMutex(); |
| +SignalSender* SignalSender::instance_ = NULL; |
| +struct sigaction SignalSender::old_signal_handler_; |
| +bool SignalSender::signal_handler_installed_ = false; |
| Sampler::Sampler(Isolate* isolate, int interval) |
| @@ -697,63 +785,27 @@ Sampler::Sampler(Isolate* isolate, int interval) |
| profiling_(false), |
| active_(false), |
| samples_taken_(0) { |
| - data_ = new PlatformData(this); |
| + data_ = new PlatformData; |
| } |
| Sampler::~Sampler() { |
| - ASSERT(!data_->signal_sender_launched_); |
| + ASSERT(!IsActive()); |
| delete data_; |
| } |
| void Sampler::Start() { |
| - // There can only be one active sampler at the time on POSIX |
| - // platforms. |
| ASSERT(!IsActive()); |
| - vm_tid_ = GetThreadID(); |
| - |
| - // Request profiling signals. |
| - struct sigaction sa; |
| - sa.sa_sigaction = ProfilerSignalHandler; |
| - sigemptyset(&sa.sa_mask); |
| - 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; |
| + SignalSender::AddActiveSampler(this); |
| } |
| void Sampler::Stop() { |
| + ASSERT(IsActive()); |
| + SignalSender::RemoveActiveSampler(this); |
| 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_) { |
| - sigaction(SIGPROF, &data_->old_signal_handler_, 0); |
| - data_->signal_handler_installed_ = false; |
| - } |
| - |
| - // This sampler is no longer the active sampler. |
| - active_sampler_ = NULL; |
| } |
| #endif // ENABLE_LOGGING_AND_PROFILING |