Home | History | Annotate | Download | only in threading
      1 // Copyright 2017 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef BASE_THREADING_SCOPED_BLOCKING_CALL_H
      6 #define BASE_THREADING_SCOPED_BLOCKING_CALL_H
      7 
      8 #include "base/base_export.h"
      9 #include "base/logging.h"
     10 
     11 namespace base {
     12 
     13 // BlockingType indicates the likelihood that a blocking call will actually
     14 // block.
     15 enum class BlockingType {
     16   // The call might block (e.g. file I/O that might hit in memory cache).
     17   MAY_BLOCK,
     18   // The call will definitely block (e.g. cache already checked and now pinging
     19   // server synchronously).
     20   WILL_BLOCK
     21 };
     22 
     23 namespace internal {
     24 class BlockingObserver;
     25 }
     26 
     27 // This class must be instantiated in every scope where a blocking call is made.
     28 // CPU usage should be minimal within that scope. //base APIs that block
     29 // instantiate their own ScopedBlockingCall; it is not necessary to instantiate
     30 // another ScopedBlockingCall in the scope where these APIs are used.
     31 //
     32 // Good:
     33 //   Data data;
     34 //   {
     35 //     ScopedBlockingCall scoped_blocking_call(BlockingType::WILL_BLOCK);
     36 //     data = GetDataFromNetwork();
     37 //   }
     38 //   CPUIntensiveProcessing(data);
     39 //
     40 // Bad:
     41 //   ScopedBlockingCall scoped_blocking_call(BlockingType::WILL_BLOCK);
     42 //   Data data = GetDataFromNetwork();
     43 //   CPUIntensiveProcessing(data);  // CPU usage within a ScopedBlockingCall.
     44 //
     45 // Good:
     46 //   Data a;
     47 //   Data b;
     48 //   {
     49 //     ScopedBlockingCall scoped_blocking_call(BlockingType::MAY_BLOCK);
     50 //     a = GetDataFromMemoryCacheOrNetwork();
     51 //     b = GetDataFromMemoryCacheOrNetwork();
     52 //   }
     53 //   CPUIntensiveProcessing(a);
     54 //   CPUIntensiveProcessing(b);
     55 //
     56 // Bad:
     57 //   ScopedBlockingCall scoped_blocking_call(BlockingType::MAY_BLOCK);
     58 //   Data a = GetDataFromMemoryCacheOrNetwork();
     59 //   Data b = GetDataFromMemoryCacheOrNetwork();
     60 //   CPUIntensiveProcessing(a);  // CPU usage within a ScopedBlockingCall.
     61 //   CPUIntensiveProcessing(b);  // CPU usage within a ScopedBlockingCall.
     62 //
     63 // Good:
     64 //   base::WaitableEvent waitable_event(...);
     65 //   waitable_event.Wait();
     66 //
     67 // Bad:
     68 //  base::WaitableEvent waitable_event(...);
     69 //  ScopedBlockingCall scoped_blocking_call(BlockingType::WILL_BLOCK);
     70 //  waitable_event.Wait();  // Wait() instantiates its own ScopedBlockingCall.
     71 //
     72 // When a ScopedBlockingCall is instantiated from a TaskScheduler parallel or
     73 // sequenced task, the thread pool size is incremented to compensate for the
     74 // blocked thread (more or less aggressively depending on BlockingType).
     75 class BASE_EXPORT ScopedBlockingCall {
     76  public:
     77   ScopedBlockingCall(BlockingType blocking_type);
     78   ~ScopedBlockingCall();
     79 
     80  private:
     81   internal::BlockingObserver* const blocking_observer_;
     82 
     83   // Previous ScopedBlockingCall instantiated on this thread.
     84   ScopedBlockingCall* const previous_scoped_blocking_call_;
     85 
     86   // Whether the BlockingType of the current thread was WILL_BLOCK after this
     87   // ScopedBlockingCall was instantiated.
     88   const bool is_will_block_;
     89 
     90   DISALLOW_COPY_AND_ASSIGN(ScopedBlockingCall);
     91 };
     92 
     93 namespace internal {
     94 
     95 // Interface for an observer to be informed when a thread enters or exits
     96 // the scope of ScopedBlockingCall objects.
     97 class BASE_EXPORT BlockingObserver {
     98  public:
     99   virtual ~BlockingObserver() = default;
    100 
    101   // Invoked when a ScopedBlockingCall is instantiated on the observed thread
    102   // where there wasn't an existing ScopedBlockingCall.
    103   virtual void BlockingStarted(BlockingType blocking_type) = 0;
    104 
    105   // Invoked when a WILL_BLOCK ScopedBlockingCall is instantiated on the
    106   // observed thread where there was a MAY_BLOCK ScopedBlockingCall but not a
    107   // WILL_BLOCK ScopedBlockingCall.
    108   virtual void BlockingTypeUpgraded() = 0;
    109 
    110   // Invoked when the last ScopedBlockingCall on the observed thread is
    111   // destroyed.
    112   virtual void BlockingEnded() = 0;
    113 };
    114 
    115 // Registers |blocking_observer| on the current thread. It is invalid to call
    116 // this on a thread where there is an active ScopedBlockingCall.
    117 BASE_EXPORT void SetBlockingObserverForCurrentThread(
    118     BlockingObserver* blocking_observer);
    119 
    120 BASE_EXPORT void ClearBlockingObserverForTesting();
    121 
    122 // Unregisters the |blocking_observer| on the current thread within its scope.
    123 // Used in TaskScheduler tests to prevent calls to //base sync primitives from
    124 // affecting the thread pool capacity.
    125 class BASE_EXPORT ScopedClearBlockingObserverForTesting {
    126  public:
    127   ScopedClearBlockingObserverForTesting();
    128   ~ScopedClearBlockingObserverForTesting();
    129 
    130  private:
    131   BlockingObserver* const blocking_observer_;
    132 
    133   DISALLOW_COPY_AND_ASSIGN(ScopedClearBlockingObserverForTesting);
    134 };
    135 
    136 }  // namespace internal
    137 
    138 }  // namespace base
    139 
    140 #endif  // BASE_THREADING_SCOPED_BLOCKING_CALL_H
    141