xref: /aosp_15_r20/external/cronet/base/task/common/operations_controller.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2018 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "base/task/common/operations_controller.h"
6*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h"
7*6777b538SAndroid Build Coastguard Worker #include "base/synchronization/waitable_event.h"
8*6777b538SAndroid Build Coastguard Worker 
9*6777b538SAndroid Build Coastguard Worker #include <ostream>
10*6777b538SAndroid Build Coastguard Worker 
11*6777b538SAndroid Build Coastguard Worker namespace base {
12*6777b538SAndroid Build Coastguard Worker namespace internal {
13*6777b538SAndroid Build Coastguard Worker 
14*6777b538SAndroid Build Coastguard Worker OperationsController::OperationsController() = default;
15*6777b538SAndroid Build Coastguard Worker 
~OperationsController()16*6777b538SAndroid Build Coastguard Worker OperationsController::~OperationsController() {
17*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
18*6777b538SAndroid Build Coastguard Worker   // An OperationsController may only be deleted when it was either not
19*6777b538SAndroid Build Coastguard Worker   // accepting operations or after it was shutdown and there are no in flight
20*6777b538SAndroid Build Coastguard Worker   // attempts to perform operations.
21*6777b538SAndroid Build Coastguard Worker   auto value = state_and_count_.load();
22*6777b538SAndroid Build Coastguard Worker   DCHECK(
23*6777b538SAndroid Build Coastguard Worker       ExtractState(value) == State::kRejectingOperations ||
24*6777b538SAndroid Build Coastguard Worker       (ExtractState(value) == State::kShuttingDown && ExtractCount(value) == 0))
25*6777b538SAndroid Build Coastguard Worker       << value;
26*6777b538SAndroid Build Coastguard Worker #endif
27*6777b538SAndroid Build Coastguard Worker }
28*6777b538SAndroid Build Coastguard Worker 
StartAcceptingOperations()29*6777b538SAndroid Build Coastguard Worker bool OperationsController::StartAcceptingOperations() {
30*6777b538SAndroid Build Coastguard Worker   // Release semantics are required to ensure that all memory accesses made on
31*6777b538SAndroid Build Coastguard Worker   // this thread happen-before any others done on a thread which is later
32*6777b538SAndroid Build Coastguard Worker   // allowed to perform an operation.
33*6777b538SAndroid Build Coastguard Worker   auto prev_value = state_and_count_.fetch_or(kAcceptingOperationsBitMask,
34*6777b538SAndroid Build Coastguard Worker                                               std::memory_order_release);
35*6777b538SAndroid Build Coastguard Worker 
36*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(ExtractState(prev_value), State::kRejectingOperations);
37*6777b538SAndroid Build Coastguard Worker   // The count is the number of rejected operations, unwind them now.
38*6777b538SAndroid Build Coastguard Worker   auto num_rejected = ExtractCount(prev_value);
39*6777b538SAndroid Build Coastguard Worker   DecrementBy(num_rejected);
40*6777b538SAndroid Build Coastguard Worker   return num_rejected != 0;
41*6777b538SAndroid Build Coastguard Worker }
42*6777b538SAndroid Build Coastguard Worker 
TryBeginOperation()43*6777b538SAndroid Build Coastguard Worker OperationsController::OperationToken OperationsController::TryBeginOperation() {
44*6777b538SAndroid Build Coastguard Worker   // Acquire semantics are required to ensure that a thread which is allowed to
45*6777b538SAndroid Build Coastguard Worker   // perform an operation sees all the memory side-effects that happened-before
46*6777b538SAndroid Build Coastguard Worker   // StartAcceptingOperations(). They're also required so that no operations on
47*6777b538SAndroid Build Coastguard Worker   // this thread (e.g. the operation itself) can be reordered before this one.
48*6777b538SAndroid Build Coastguard Worker   auto prev_value = state_and_count_.fetch_add(1, std::memory_order_acquire);
49*6777b538SAndroid Build Coastguard Worker 
50*6777b538SAndroid Build Coastguard Worker   switch (ExtractState(prev_value)) {
51*6777b538SAndroid Build Coastguard Worker     case State::kRejectingOperations:
52*6777b538SAndroid Build Coastguard Worker       return OperationToken(nullptr);
53*6777b538SAndroid Build Coastguard Worker     case State::kAcceptingOperations:
54*6777b538SAndroid Build Coastguard Worker       return OperationToken(this);
55*6777b538SAndroid Build Coastguard Worker     case State::kShuttingDown:
56*6777b538SAndroid Build Coastguard Worker       DecrementBy(1);
57*6777b538SAndroid Build Coastguard Worker       return OperationToken(nullptr);
58*6777b538SAndroid Build Coastguard Worker   }
59*6777b538SAndroid Build Coastguard Worker }
60*6777b538SAndroid Build Coastguard Worker 
ShutdownAndWaitForZeroOperations()61*6777b538SAndroid Build Coastguard Worker void OperationsController::ShutdownAndWaitForZeroOperations() {
62*6777b538SAndroid Build Coastguard Worker   // Acquire semantics are required to guarantee that all memory side-effects
63*6777b538SAndroid Build Coastguard Worker   // made by other threads that were allowed to perform operations are
64*6777b538SAndroid Build Coastguard Worker   // synchronized with this thread before it returns from this method.
65*6777b538SAndroid Build Coastguard Worker   auto prev_value = state_and_count_.fetch_or(kShuttingDownBitMask,
66*6777b538SAndroid Build Coastguard Worker                                               std::memory_order_acquire);
67*6777b538SAndroid Build Coastguard Worker 
68*6777b538SAndroid Build Coastguard Worker   switch (ExtractState(prev_value)) {
69*6777b538SAndroid Build Coastguard Worker     case State::kRejectingOperations:
70*6777b538SAndroid Build Coastguard Worker       // The count is the number of rejected operations, unwind them now.
71*6777b538SAndroid Build Coastguard Worker       DecrementBy(ExtractCount(prev_value));
72*6777b538SAndroid Build Coastguard Worker       break;
73*6777b538SAndroid Build Coastguard Worker     case State::kAcceptingOperations:
74*6777b538SAndroid Build Coastguard Worker       if (ExtractCount(prev_value) != 0) {
75*6777b538SAndroid Build Coastguard Worker         shutdown_complete_.Wait();
76*6777b538SAndroid Build Coastguard Worker       }
77*6777b538SAndroid Build Coastguard Worker       break;
78*6777b538SAndroid Build Coastguard Worker     case State::kShuttingDown:
79*6777b538SAndroid Build Coastguard Worker       DCHECK(false) << "Multiple calls to ShutdownAndWaitForZeroOperations()";
80*6777b538SAndroid Build Coastguard Worker       break;
81*6777b538SAndroid Build Coastguard Worker   }
82*6777b538SAndroid Build Coastguard Worker }
83*6777b538SAndroid Build Coastguard Worker 
84*6777b538SAndroid Build Coastguard Worker // static
ExtractState(uint32_t value)85*6777b538SAndroid Build Coastguard Worker OperationsController::State OperationsController::ExtractState(uint32_t value) {
86*6777b538SAndroid Build Coastguard Worker   if (value & kShuttingDownBitMask) {
87*6777b538SAndroid Build Coastguard Worker     return State::kShuttingDown;
88*6777b538SAndroid Build Coastguard Worker   } else if (value & kAcceptingOperationsBitMask) {
89*6777b538SAndroid Build Coastguard Worker     return State::kAcceptingOperations;
90*6777b538SAndroid Build Coastguard Worker   } else {
91*6777b538SAndroid Build Coastguard Worker     return State::kRejectingOperations;
92*6777b538SAndroid Build Coastguard Worker   }
93*6777b538SAndroid Build Coastguard Worker }
94*6777b538SAndroid Build Coastguard Worker 
DecrementBy(uint32_t n)95*6777b538SAndroid Build Coastguard Worker void OperationsController::DecrementBy(uint32_t n) {
96*6777b538SAndroid Build Coastguard Worker   // Release semantics are required to ensure that no operation on the current
97*6777b538SAndroid Build Coastguard Worker   // thread (e.g. the operation itself) can be reordered after this one.
98*6777b538SAndroid Build Coastguard Worker   auto prev_value = state_and_count_.fetch_sub(n, std::memory_order_release);
99*6777b538SAndroid Build Coastguard Worker   DCHECK_LE(n, ExtractCount(prev_value)) << "Decrement underflow";
100*6777b538SAndroid Build Coastguard Worker 
101*6777b538SAndroid Build Coastguard Worker   if (ExtractState(prev_value) == State::kShuttingDown &&
102*6777b538SAndroid Build Coastguard Worker       ExtractCount(prev_value) == n) {
103*6777b538SAndroid Build Coastguard Worker     shutdown_complete_.Signal();
104*6777b538SAndroid Build Coastguard Worker   }
105*6777b538SAndroid Build Coastguard Worker }
106*6777b538SAndroid Build Coastguard Worker 
107*6777b538SAndroid Build Coastguard Worker }  // namespace internal
108*6777b538SAndroid Build Coastguard Worker }  // namespace base
109