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 WorkerOperationsController::~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 Workerbool 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 WorkerOperationsController::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 Workervoid 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 WorkerOperationsController::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 Workervoid 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