| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 | // Copyright 2018 The Chromium Authors. All rights reserved.// Use of this source code is governed by a BSD-style license that can be// found in the LICENSE file.#ifndef BASE_TASK_COMMON_OPERATIONS_CONTROLLER_H_#define BASE_TASK_COMMON_OPERATIONS_CONTROLLER_H_#include <atomic>#include <cstdint>#include "base/synchronization/waitable_event.h"namespace base {namespace internal {// A lock-free thread-safe controller to manage critical multi-threaded// operations without locks.//// The controller is used to determine if operations are allowed, and to keep// track of how many are currently active. Users will call TryBeginOperation()// before starting such operations. If the call succeeds the user can run the// operation and the controller will keep track of it until the user signals// that the operation is completed. No operations are allowed before// StartAcceptingOperations() is called, or after// ShutdownAndWaitForZeroOperations() is called.//// There is no explicit way of telling the controller when an operation is// completed, instead for convenience TryBeginOperation() will return a RAII// like object that will do so on destruction.//// For example://// OperationsController controller_;//// void SetUp() {//   controller_.StartAcceptingOperations();// }//// void TearDown() {//   controller_.ShutdownAndWaitForZeroOperations();// }//// void MaybeRunOperation() {//   auto operation_token = controller_.TryBeginOperation();//   if (operation_token) {//     Process();//   }// }//// This class is thread-safe.// But note that StartAcceptingOperations can never be called after// ShutdownAndWaitForZeroOperations.class BASE_EXPORT OperationsController { public:  // The owner of an OperationToken which evaluates to true can safely perform  // an operation while being certain it happens-after  // StartAcceptingOperations() and happens-before  // ShutdownAndWaitForZeroOperations(). Releasing this OperationToken  // relinquishes this right.  //  // This class is thread-safe  class OperationToken {   public:    ~OperationToken() {      if (outer_)        outer_->DecrementBy(1);    }    OperationToken(const OperationToken&) = delete;    OperationToken(OperationToken&& other) {      this->outer_ = other.outer_;      other.outer_ = nullptr;    }    operator bool() const { return !!outer_; }   private:    friend class OperationsController;    explicit OperationToken(OperationsController* outer) : outer_(outer) {}    OperationsController* outer_;  };  OperationsController();  // Users must call ShutdownAndWaitForZeroOperations() before destroying an  // instance of this class if StartAcceptingOperations() was called.  ~OperationsController();  OperationsController(const OperationsController&) = delete;  OperationsController& operator=(const OperationsController&) = delete;  // Starts to accept operations (before this point TryBeginOperation() returns  // an invalid token). Returns true if an attempt to perform an operation was  // made and denied before StartAcceptingOperations() was called. Can be called  // at most once, never after ShutdownAndWaitForZeroOperations().  bool StartAcceptingOperations();  // Returns a RAII like object that implicitly converts to true if operations  // are allowed i.e. if this call happens-after StartAcceptingOperations() and  // happens-before Shutdown(), otherwise the object will convert to false. On  // successful return, this OperationsController will keep track of the  // operation until the returned object goes out of scope.  OperationToken TryBeginOperation();  // Prevents further calls to TryBeginOperation() from succeeding and waits for  // all the ongoing operations to complete.  //  // Attention: Can only be called once.  void ShutdownAndWaitForZeroOperations(); private:  // Atomic representation of the state of this class. We use the upper 2 bits  // to keep track of flag like values and the remainder bits are used as a  // counter. The 2 flags are used to represent 3 different states:  //  // State                   | AcceptOperations Bit | ShuttingDown Bit  // --------------------------------------------------------------  // kRejectingOperations    | 0                    | 0  // kAcceptingOperations    | 1                    | 0  // kShuttingDown           | *                    | 1  //  // The counter keeps track of the rejected operations when we are in  // the kRejectingOperations state, the number of inflight operations  // otherwise. If the count reaches zero and we are in the shutting down state  // |shutdown_complete_| will be signaled.  static constexpr uint32_t kShuttingDownBitMask = uint32_t{1} << 31;  static constexpr uint32_t kAcceptingOperationsBitMask = uint32_t{1} << 30;  static constexpr uint32_t kFlagsBitMask =      (kShuttingDownBitMask | kAcceptingOperationsBitMask);  static constexpr uint32_t kCountBitMask = ~kFlagsBitMask;  enum class State {    kRejectingOperations,    kAcceptingOperations,    kShuttingDown,  };  // Helper methods for the bit fiddling. Pass a |state_and_count_| value to  // extract state or count out of it.  static uint32_t ExtractCount(uint32_t value) { return value & kCountBitMask; }  static State ExtractState(uint32_t value);  // Decrements the counter by |n| and signals |shutdown_complete_| if needed.  void DecrementBy(uint32_t n);  std::atomic<uint32_t> state_and_count_{0};  WaitableEvent shutdown_complete_;};}  // namespace internal}  // namespace base#endif  // BASE_TASK_COMMON_OPERATIONS_CONTROLLER_H_
 |