xref: /aosp_15_r20/external/cronet/base/task/sequence_manager/work_deduplicator.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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)15 WorkDeduplicator::WorkDeduplicator(
16     scoped_refptr<const AssociatedThreadId> associated_thread)
17     : associated_thread_(std::move(associated_thread)) {}
18 
19 WorkDeduplicator::~WorkDeduplicator() = default;
20 
BindToCurrentThread()21 WorkDeduplicator::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()30 WorkDeduplicator::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() const37 WorkDeduplicator::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()45 void 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()52 void 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)59 WorkDeduplicator::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