1 // Copyright 2019 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/task/sequence_manager/work_deduplicator.h" 6 7 #include <ostream> 8 #include <utility> 9 #include "base/check_op.h" 10 11 namespace base { 12 namespace sequence_manager { 13 namespace internal { 14 WorkDeduplicator(scoped_refptr<const AssociatedThreadId> associated_thread)15WorkDeduplicator::WorkDeduplicator( 16 scoped_refptr<const AssociatedThreadId> associated_thread) 17 : associated_thread_(std::move(associated_thread)) {} 18 19 WorkDeduplicator::~WorkDeduplicator() = default; 20 BindToCurrentThread()21WorkDeduplicator::ShouldScheduleWork WorkDeduplicator::BindToCurrentThread() { 22 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker); 23 int previous_flags = state_.fetch_or(kBoundFlag); 24 DCHECK_EQ(previous_flags & kBoundFlag, 0) << "Can't bind twice!"; 25 return previous_flags & kPendingDoWorkFlag 26 ? ShouldScheduleWork::kScheduleImmediate 27 : ShouldScheduleWork::kNotNeeded; 28 } 29 OnWorkRequested()30WorkDeduplicator::ShouldScheduleWork WorkDeduplicator::OnWorkRequested() { 31 // Set kPendingDoWorkFlag and return true if we were previously kIdle. 32 return state_.fetch_or(kPendingDoWorkFlag) == State::kIdle 33 ? ShouldScheduleWork::kScheduleImmediate 34 : ShouldScheduleWork::kNotNeeded; 35 } 36 OnDelayedWorkRequested() const37WorkDeduplicator::ShouldScheduleWork WorkDeduplicator::OnDelayedWorkRequested() 38 const { 39 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker); 40 // This must be called on the associated thread or this read is racy. 41 return state_.load() == State::kIdle ? ShouldScheduleWork::kScheduleImmediate 42 : ShouldScheduleWork::kNotNeeded; 43 } 44 OnWorkStarted()45void WorkDeduplicator::OnWorkStarted() { 46 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker); 47 DCHECK_EQ(state_.load() & kBoundFlag, kBoundFlag); 48 // Clear kPendingDoWorkFlag and mark us as in a DoWork. 49 state_.store(State::kInDoWork); 50 } 51 WillCheckForMoreWork()52void WorkDeduplicator::WillCheckForMoreWork() { 53 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker); 54 DCHECK_EQ(state_.load() & kBoundFlag, kBoundFlag); 55 // Clear kPendingDoWorkFlag if it was set. 56 state_.store(State::kInDoWork); 57 } 58 DidCheckForMoreWork(NextTask next_task)59WorkDeduplicator::ShouldScheduleWork WorkDeduplicator::DidCheckForMoreWork( 60 NextTask next_task) { 61 DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker); 62 DCHECK_EQ(state_.load() & kBoundFlag, kBoundFlag); 63 if (next_task == NextTask::kIsImmediate) { 64 state_.store(State::kDoWorkPending); 65 return ShouldScheduleWork::kScheduleImmediate; 66 } 67 // If |next_task| is not immediate, there's still a possibility that 68 // OnWorkRequested() was invoked racily from another thread just after this 69 // thread determined that the next task wasn't immediate. In that case, that 70 // other thread relies on us to return kScheduleImmediate. 71 return (state_.fetch_and(~kInDoWorkFlag) & kPendingDoWorkFlag) 72 ? ShouldScheduleWork::kScheduleImmediate 73 : ShouldScheduleWork::kNotNeeded; 74 } 75 76 } // namespace internal 77 } // namespace sequence_manager 78 } // namespace base 79