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

Unified Diff: base/task_scheduler/scheduler_worker.cc

Issue 2692863012: SchedulerWorker Refcounting for Destruction in Production (Closed)
Patch Set: CR Feedback 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
Index: base/task_scheduler/scheduler_worker.cc
diff --git a/base/task_scheduler/scheduler_worker.cc b/base/task_scheduler/scheduler_worker.cc
index 1d6cfee84775207f3338e3b21316d4e8ec0794ad..cc9119441d5538ccd87b906d28e0d68139f390c7 100644
--- a/base/task_scheduler/scheduler_worker.cc
+++ b/base/task_scheduler/scheduler_worker.cc
@@ -25,8 +25,8 @@ class SchedulerWorker::Thread : public PlatformThread::Delegate {
public:
~Thread() override = default;
- static std::unique_ptr<Thread> Create(SchedulerWorker* outer) {
- std::unique_ptr<Thread> thread(new Thread(outer));
+ static std::unique_ptr<Thread> Create(scoped_refptr<SchedulerWorker> outer) {
+ std::unique_ptr<Thread> thread(new Thread(std::move(outer)));
thread->Initialize();
if (thread->thread_handle_.is_null())
return nullptr;
@@ -38,7 +38,7 @@ class SchedulerWorker::Thread : public PlatformThread::Delegate {
// Set if this thread was detached.
std::unique_ptr<Thread> detached_thread;
- outer_->delegate_->OnMainEntry(outer_);
+ outer_->delegate_->OnMainEntry(outer_.get());
// A SchedulerWorker starts out waiting for work.
WaitForWork();
@@ -51,8 +51,7 @@ class SchedulerWorker::Thread : public PlatformThread::Delegate {
}
#endif
- while (!outer_->task_tracker_->IsShutdownComplete() &&
- !outer_->should_exit_for_testing_.IsSet()) {
+ while (!outer_->ShouldExit()) {
DCHECK(outer_);
#if defined(OS_MACOSX)
@@ -62,10 +61,11 @@ class SchedulerWorker::Thread : public PlatformThread::Delegate {
UpdateThreadPriority(GetDesiredThreadPriority());
// Get the sequence containing the next task to execute.
- scoped_refptr<Sequence> sequence = outer_->delegate_->GetWork(outer_);
+ scoped_refptr<Sequence> sequence =
+ outer_->delegate_->GetWork(outer_.get());
if (!sequence) {
- if (outer_->delegate_->CanDetach(outer_)) {
- detached_thread = outer_->Detach();
+ if (outer_->delegate_->CanDetach(outer_.get())) {
+ detached_thread = outer_->DetachThreadObject(DetachNotify::DELEGATE);
if (detached_thread) {
outer_ = nullptr;
DCHECK_EQ(detached_thread.get(), this);
@@ -106,6 +106,9 @@ class SchedulerWorker::Thread : public PlatformThread::Delegate {
// stuck forever.
DCHECK(!detached_thread || !IsWakeUpPending()) <<
"This thread was detached and woken up at the same time.";
+
+ if (!detached_thread)
gab 2017/02/17 21:38:35 Add comment
robliao 2017/02/17 22:04:30 Done.
+ detached_thread = outer_->DetachThreadObject(DetachNotify::SILENT);
}
void Join() { PlatformThread::Join(thread_handle_); }
@@ -115,8 +118,8 @@ class SchedulerWorker::Thread : public PlatformThread::Delegate {
bool IsWakeUpPending() { return wake_up_event_.IsSignaled(); }
private:
- Thread(SchedulerWorker* outer)
- : outer_(outer),
+ Thread(scoped_refptr<SchedulerWorker> outer)
+ : outer_(std::move(outer)),
wake_up_event_(WaitableEvent::ResetPolicy::MANUAL,
WaitableEvent::InitialState::NOT_SIGNALED),
current_thread_priority_(GetDesiredThreadPriority()) {
@@ -175,7 +178,7 @@ class SchedulerWorker::Thread : public PlatformThread::Delegate {
PlatformThreadHandle thread_handle_;
- SchedulerWorker* outer_;
+ scoped_refptr<SchedulerWorker> outer_;
// Event signaled to wake up this thread.
WaitableEvent wake_up_event_;
@@ -187,15 +190,15 @@ class SchedulerWorker::Thread : public PlatformThread::Delegate {
DISALLOW_COPY_AND_ASSIGN(Thread);
};
-std::unique_ptr<SchedulerWorker> SchedulerWorker::Create(
+scoped_refptr<SchedulerWorker> SchedulerWorker::Create(
ThreadPriority priority_hint,
std::unique_ptr<Delegate> delegate,
TaskTracker* task_tracker,
InitialState initial_state,
SchedulerBackwardCompatibility backward_compatibility) {
- auto worker =
- WrapUnique(new SchedulerWorker(priority_hint, std::move(delegate),
- task_tracker, backward_compatibility));
+ scoped_refptr<SchedulerWorker> worker(
+ new SchedulerWorker(priority_hint, std::move(delegate), task_tracker,
+ backward_compatibility));
// Creation happens before any other thread can reference this one, so no
// synchronization is necessary.
if (initial_state == SchedulerWorker::InitialState::ALIVE) {
@@ -208,17 +211,10 @@ std::unique_ptr<SchedulerWorker> SchedulerWorker::Create(
return worker;
}
-SchedulerWorker::~SchedulerWorker() {
- // It is unexpected for |thread_| to be alive and for SchedulerWorker to
- // destroy since SchedulerWorker owns the delegate needed by |thread_|.
- // For testing, this generally means JoinForTesting was not called.
- DCHECK(!thread_);
-}
-
void SchedulerWorker::WakeUp() {
AutoSchedulerLock auto_lock(thread_lock_);
- DCHECK(!should_exit_for_testing_.IsSet());
+ DCHECK(!join_called_for_testing_.IsSet());
if (!thread_)
CreateThreadAssertSynchronized();
@@ -228,8 +224,8 @@ void SchedulerWorker::WakeUp() {
}
void SchedulerWorker::JoinForTesting() {
- DCHECK(!should_exit_for_testing_.IsSet());
- should_exit_for_testing_.Set();
+ DCHECK(!join_called_for_testing_.IsSet());
+ join_called_for_testing_.Set();
std::unique_ptr<Thread> thread;
@@ -238,7 +234,7 @@ void SchedulerWorker::JoinForTesting() {
if (thread_) {
// Make sure the thread is awake. It will see that
- // |should_exit_for_testing_| is set and exit shortly after.
+ // |join_called_for_testing_| is set and exit shortly after.
thread_->WakeUp();
thread = std::move(thread_);
}
@@ -253,6 +249,15 @@ bool SchedulerWorker::ThreadAliveForTesting() const {
return !!thread_;
}
+void SchedulerWorker::Cleanup() {
+ AutoSchedulerLock auto_lock(thread_lock_);
+ DCHECK(!should_exit_);
+ if (thread_) {
+ should_exit_ = true;
+ thread_->WakeUp();
+ }
+}
+
SchedulerWorker::SchedulerWorker(
ThreadPriority priority_hint,
std::unique_ptr<Delegate> delegate,
@@ -270,12 +275,20 @@ SchedulerWorker::SchedulerWorker(
DCHECK(task_tracker_);
}
-std::unique_ptr<SchedulerWorker::Thread> SchedulerWorker::Detach() {
+SchedulerWorker::~SchedulerWorker() {
+ // It is unexpected for |thread_| to be alive and for SchedulerWorker to
+ // destroy since SchedulerWorker owns the delegate needed by |thread_|.
+ // For testing, this generally means JoinForTesting was not called.
+ DCHECK(!thread_);
+}
+
+std::unique_ptr<SchedulerWorker::Thread> SchedulerWorker::DetachThreadObject(
+ DetachNotify detach_notify) {
AutoSchedulerLock auto_lock(thread_lock_);
// Do not detach if the thread is being joined.
if (!thread_) {
- DCHECK(should_exit_for_testing_.IsSet());
+ DCHECK(join_called_for_testing_.IsSet());
return nullptr;
}
@@ -285,9 +298,11 @@ std::unique_ptr<SchedulerWorker::Thread> SchedulerWorker::Detach() {
if (thread_->IsWakeUpPending())
return nullptr;
- // Call OnDetach() within the scope of |thread_lock_| to prevent the delegate
- // from being used concurrently from an old and a new thread.
- delegate_->OnDetach();
+ if (detach_notify == DetachNotify::DELEGATE) {
+ // Call OnDetach() within the scope of |thread_lock_| to prevent the
+ // delegate from being used concurrently from an old and a new thread.
+ delegate_->OnDetach();
+ }
return std::move(thread_);
}
@@ -301,5 +316,15 @@ void SchedulerWorker::CreateThreadAssertSynchronized() {
CreateThread();
}
+bool SchedulerWorker::ShouldExit() {
+ bool should_exit =
+ task_tracker_->IsShutdownComplete() || join_called_for_testing_.IsSet();
+ if (should_exit)
+ return true;
+
+ AutoSchedulerLock auto_lock(thread_lock_);
+ return should_exit_;
+}
+
} // namespace internal
} // namespace base

Powered by Google App Engine
This is Rietveld 408576698