Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3290)

Unified Diff: base/profiler/stack_sampling_profiler.cc

Issue 2680703004: Wait for sampling to complete before destructing. (Closed)
Patch Set: cleanup, comments, and fixes Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « base/profiler/stack_sampling_profiler.h ('k') | base/profiler/stack_sampling_profiler_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/profiler/stack_sampling_profiler.cc
diff --git a/base/profiler/stack_sampling_profiler.cc b/base/profiler/stack_sampling_profiler.cc
index ce898d4c07f7a797455419f1e7bd2e64fdf05581..91cc193f23d77dcf256578df0695a1e1bb48b47d 100644
--- a/base/profiler/stack_sampling_profiler.cc
+++ b/base/profiler/stack_sampling_profiler.cc
@@ -28,63 +28,6 @@ namespace base {
namespace {
-// AsyncRunner ----------------------------------------------------------------
-
-// Helper class to allow a profiler to be run completely asynchronously from the
-// initiator, without being concerned with the profiler's lifetime.
-class AsyncRunner {
- public:
- // Sets up a profiler and arranges for it to be deleted on its completed
- // callback.
- static void Run(PlatformThreadId thread_id,
- const StackSamplingProfiler::SamplingParams& params,
- const StackSamplingProfiler::CompletedCallback& callback);
-
- private:
- AsyncRunner();
-
- // Runs the callback and deletes the AsyncRunner instance. |profiles| is not
- // const& because it must be passed with std::move.
- static void RunCallbackAndDeleteInstance(
- std::unique_ptr<AsyncRunner> object_to_be_deleted,
- const StackSamplingProfiler::CompletedCallback& callback,
- scoped_refptr<SingleThreadTaskRunner> task_runner,
- StackSamplingProfiler::CallStackProfiles profiles);
-
- std::unique_ptr<StackSamplingProfiler> profiler_;
-
- DISALLOW_COPY_AND_ASSIGN(AsyncRunner);
-};
-
-// static
-void AsyncRunner::Run(
- PlatformThreadId thread_id,
- const StackSamplingProfiler::SamplingParams& params,
- const StackSamplingProfiler::CompletedCallback &callback) {
- std::unique_ptr<AsyncRunner> runner(new AsyncRunner);
- AsyncRunner* temp_ptr = runner.get();
- temp_ptr->profiler_.reset(
- new StackSamplingProfiler(thread_id, params,
- Bind(&AsyncRunner::RunCallbackAndDeleteInstance,
- Passed(&runner), callback,
- ThreadTaskRunnerHandle::Get())));
- // The callback won't be called until after Start(), so temp_ptr will still
- // be valid here.
- temp_ptr->profiler_->Start();
-}
-
-AsyncRunner::AsyncRunner() {}
-
-void AsyncRunner::RunCallbackAndDeleteInstance(
- std::unique_ptr<AsyncRunner> object_to_be_deleted,
- const StackSamplingProfiler::CompletedCallback& callback,
- scoped_refptr<SingleThreadTaskRunner> task_runner,
- StackSamplingProfiler::CallStackProfiles profiles) {
- callback.Run(std::move(profiles));
- // Delete the instance on the original calling thread.
- task_runner->DeleteSoon(FROM_HERE, object_to_be_deleted.release());
-}
-
void ChangeAtomicFlags(subtle::Atomic32* flags,
subtle::Atomic32 set,
subtle::Atomic32 clear) {
@@ -216,8 +159,9 @@ class StackSamplingProfiler::SamplingThread : public Thread {
// Removes an active collection based on its ID, forcing it to run its
// callback if any data has been collected. This can be called externally
- // from any thread.
- void Remove(int id);
+ // from any thread. The |done| event, if not null, will be signaled upon
+ // completion. |done| must live until after it has been signaled.
+ void Remove(int id, WaitableEvent* done);
// Removes all active collections and stops the underlying thread.
void Shutdown();
@@ -255,7 +199,7 @@ class StackSamplingProfiler::SamplingThread : public Thread {
// These methods are tasks that get posted to the internal message queue.
void AddCollectionTask(std::unique_ptr<CollectionContext> collection_ptr);
- void RemoveCollectionTask(int id);
+ void RemoveCollectionTask(int id, WaitableEvent* done);
void PerformCollectionTask(int id);
void ShutdownTask();
@@ -320,16 +264,24 @@ int StackSamplingProfiler::SamplingThread::Add(
return id;
}
-void StackSamplingProfiler::SamplingThread::Remove(int id) {
+void StackSamplingProfiler::SamplingThread::Remove(int id,
+ WaitableEvent* done) {
scoped_refptr<SingleThreadTaskRunner> task_runner = GetTaskRunner();
- if (!task_runner)
- return; // Everything has already stopped.
+ if (task_runner) {
+ // This can fail if the thread were to exit between acquisition of the task
+ // runner above and the call below. Because there may be something waiting
+ // for a signal on the |done| event, return only if the task was success-
+ // fully posted.
+ if (task_runner->PostTask(FROM_HERE,
+ Bind(&SamplingThread::RemoveCollectionTask,
+ Unretained(this), id, Unretained(done)))) {
+ return;
+ }
+ }
- // This can fail if the thread were to exit between acquisition of the task
- // runner above and the call below. In that case, however, everything has
- // stopped so there's no need to try to stop it.
- task_runner->PostTask(FROM_HERE, Bind(&SamplingThread::RemoveCollectionTask,
- Unretained(this), id));
+ // The sampling thread has already exited so signal the event here.
+ if (done)
+ done->Signal();
}
void StackSamplingProfiler::SamplingThread::Shutdown() {
@@ -514,13 +466,17 @@ void StackSamplingProfiler::SamplingThread::AddCollectionTask(
collection->params.initial_delay);
}
-void StackSamplingProfiler::SamplingThread::RemoveCollectionTask(int id) {
+void StackSamplingProfiler::SamplingThread::RemoveCollectionTask(
+ int id,
+ WaitableEvent* done) {
auto found = active_collections_.find(id);
- if (found == active_collections_.end())
- return;
+ if (found != active_collections_.end()) {
+ FinishCollection(found->second.get());
+ CheckForIdle();
+ }
- FinishCollection(found->second.get());
- CheckForIdle();
+ if (done)
+ done->Signal();
}
void StackSamplingProfiler::SamplingThread::PerformCollectionTask(int id) {
@@ -658,31 +614,10 @@ StackSamplingProfiler::StackSamplingProfiler(
}
StackSamplingProfiler::~StackSamplingProfiler() {
- Stop();
-
-#if !defined(OS_WIN)
- // This is to prevent use of this object on non-Windows builds until such
- // time as the following race condition is addressed:
- // Thread A creates a local (stack) StackSamplingProfiler.
- // Sampling is initiated against thread A ("A samples A").
- // The StackSamplingProfiler is destructed and thread A exits.
- // Sampling continues briefly until the async Stop() gets through.
- // Another thread with the same ID replaces the first one.
- // Sampling access the new thread and Bad Things(tm) happen.
- // Windows is immune to this because the thread handle held internally
- // prevents re-use of the thread-ID but this may not be the case on other
- // platforms.
- NOTREACHED();
-#endif
-}
-
-// static
-void StackSamplingProfiler::StartAndRunAsync(
- PlatformThreadId thread_id,
- const SamplingParams& params,
- const CompletedCallback& callback) {
- CHECK(ThreadTaskRunnerHandle::Get());
- AsyncRunner::Run(thread_id, params, callback);
+ WaitableEvent done(WaitableEvent::ResetPolicy::MANUAL,
+ WaitableEvent::InitialState::NOT_SIGNALED);
+ Stop(&done);
+ done.Wait();
}
void StackSamplingProfiler::Start() {
@@ -698,8 +633,8 @@ void StackSamplingProfiler::Start() {
std::move(native_sampler_)));
}
-void StackSamplingProfiler::Stop() {
- SamplingThread::GetInstance()->Remove(collection_id_);
+void StackSamplingProfiler::Stop(WaitableEvent* done) {
+ SamplingThread::GetInstance()->Remove(collection_id_, done);
}
// static
« no previous file with comments | « base/profiler/stack_sampling_profiler.h ('k') | base/profiler/stack_sampling_profiler_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698