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