From 2cfab040376679f7c49da92a541ee52e4add0d9a Mon Sep 17 00:00:00 2001 From: Robert Mustacchi Date: Fri, 1 Jul 2011 09:48:34 -0700 Subject: [PATCH] Fix solaris build (http://codereview.chromium.org/7282034/) --- deps/v8/src/platform-solaris.cc | 232 ++++++++++++++++++++------------ 1 file changed, 147 insertions(+), 85 deletions(-) diff --git a/deps/v8/src/platform-solaris.cc b/deps/v8/src/platform-solaris.cc index dd4bd5d7c5..bbd982c319 100644 --- a/deps/v8/src/platform-solaris.cc +++ b/deps/v8/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(TimeCurrentMillis()); srandom(static_cast(seed)); + limit_mutex = CreateMutex(); } @@ -145,6 +147,9 @@ static void* highest_ever_allocated = reinterpret_cast(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,172 @@ 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(); } - 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(context); mcontext_t& mcontext = ucontext->uc_mcontext; - sample->state = Top::current_vm_state(); + sample->state = isolate->current_vm_state(); sample->pc = reinterpret_cast
(mcontext.gregs[REG_PC]); sample->sp = reinterpret_cast
(mcontext.gregs[REG_SP]); sample->fp = reinterpret_cast
(mcontext.gregs[REG_FP]); - active_sampler_->SampleStack(sample); - active_sampler_->Tick(sample); + sampler->SampleStack(sample); + sampler->Tick(sample); } - class Sampler::PlatformData : public Malloced { + public: + PlatformData() : vm_tid_(GetThreadID()) {} + + pthread_t vm_tid() const { return vm_tid_; } + + private: + pthread_t vm_tid_; +}; + + +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 InstallSignalHandler() { + 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); + } + + static void RestoreSignalHandler() { + if (signal_handler_installed_) { + sigaction(SIGPROF, &old_signal_handler_, 0); + signal_handler_installed_ = false; + } + } + + static void AddActiveSampler(Sampler* sampler) { + ScopedLock lock(mutex_); + SamplerRegistry::AddActiveSampler(sampler); + if (instance_ == NULL) { + // Start a thread that will send SIGPROF signal to VM threads, + // when CPU profiling will be enabled. + 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; + RestoreSignalHandler(); + } } - void SignalSender() { - while (sampler_->IsActive()) { - if (rate_limiter_.SuspendIfNecessary()) continue; - if (sampler_->IsProfiling() && RuntimeProfiler::IsEnabled()) { - SendProfilingSignal(); + // Implement Thread::Run(). + virtual void Run() { + 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(); + if (cpu_profiling_enabled && !signal_handler_installed_) { + InstallSignalHandler(); + } else if (!cpu_profiling_enabled && signal_handler_installed_) { + RestoreSignalHandler(); + } + + // 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(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 +771,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(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 +795,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