| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/task_scheduler/task_tracker.h" | 5 #include "base/task_scheduler/task_tracker.h" |
| 6 | 6 |
| 7 #include <limits> | 7 #include <limits> |
| 8 | 8 |
| 9 #include "base/atomicops.h" | 9 #include "base/atomicops.h" |
| 10 #include "base/callback.h" | 10 #include "base/callback.h" |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 | 34 |
| 35 void RecordNumBlockShutdownTasksPostedDuringShutdown( | 35 void RecordNumBlockShutdownTasksPostedDuringShutdown( |
| 36 HistogramBase::Sample value) { | 36 HistogramBase::Sample value) { |
| 37 UMA_HISTOGRAM_CUSTOM_COUNTS( | 37 UMA_HISTOGRAM_CUSTOM_COUNTS( |
| 38 "TaskScheduler.BlockShutdownTasksPostedDuringShutdown", value, 1, | 38 "TaskScheduler.BlockShutdownTasksPostedDuringShutdown", value, 1, |
| 39 kMaxBlockShutdownTasksPostedDuringShutdown, 50); | 39 kMaxBlockShutdownTasksPostedDuringShutdown, 50); |
| 40 } | 40 } |
| 41 | 41 |
| 42 } // namespace | 42 } // namespace |
| 43 | 43 |
| 44 // Atomic internal state used by TaskTracker. Sequential consistency shouldn't |
| 45 // be assumed from these calls (i.e. a thread reading |
| 46 // |HasShutdownStarted() == true| isn't guaranteed to see all writes made before |
| 47 // |StartShutdown()| on the thread that invoked it). |
| 44 class TaskTracker::State { | 48 class TaskTracker::State { |
| 45 public: | 49 public: |
| 46 State() = default; | 50 State() = default; |
| 47 | 51 |
| 48 // Sets a flag indicating that shutdown has started. Returns true if there are | 52 // Sets a flag indicating that shutdown has started. Returns true if there are |
| 49 // tasks blocking shutdown. Can only be called once. | 53 // tasks blocking shutdown. Can only be called once. |
| 50 bool StartShutdown() { | 54 bool StartShutdown() { |
| 51 const auto new_value = | 55 const auto new_value = |
| 52 subtle::Barrier_AtomicIncrement(&bits_, kShutdownHasStartedMask); | 56 subtle::NoBarrier_AtomicIncrement(&bits_, kShutdownHasStartedMask); |
| 53 | 57 |
| 54 // Check that the "shutdown has started" bit isn't zero. This would happen | 58 // Check that the "shutdown has started" bit isn't zero. This would happen |
| 55 // if it was incremented twice. | 59 // if it was incremented twice. |
| 56 DCHECK(new_value & kShutdownHasStartedMask); | 60 DCHECK(new_value & kShutdownHasStartedMask); |
| 57 | 61 |
| 58 const auto num_tasks_blocking_shutdown = | 62 const auto num_tasks_blocking_shutdown = |
| 59 new_value >> kNumTasksBlockingShutdownBitOffset; | 63 new_value >> kNumTasksBlockingShutdownBitOffset; |
| 60 return num_tasks_blocking_shutdown != 0; | 64 return num_tasks_blocking_shutdown != 0; |
| 61 } | 65 } |
| 62 | 66 |
| 63 // Returns true if shutdown has started. | 67 // Returns true if shutdown has started. |
| 64 bool HasShutdownStarted() const { | 68 bool HasShutdownStarted() const { |
| 65 return subtle::Acquire_Load(&bits_) & kShutdownHasStartedMask; | 69 return subtle::NoBarrier_Load(&bits_) & kShutdownHasStartedMask; |
| 66 } | 70 } |
| 67 | 71 |
| 68 // Returns true if there are tasks blocking shutdown. | 72 // Returns true if there are tasks blocking shutdown. |
| 69 bool AreTasksBlockingShutdown() const { | 73 bool AreTasksBlockingShutdown() const { |
| 70 const auto num_tasks_blocking_shutdown = | 74 const auto num_tasks_blocking_shutdown = |
| 71 subtle::Acquire_Load(&bits_) >> kNumTasksBlockingShutdownBitOffset; | 75 subtle::NoBarrier_Load(&bits_) >> kNumTasksBlockingShutdownBitOffset; |
| 72 DCHECK_GE(num_tasks_blocking_shutdown, 0); | 76 DCHECK_GE(num_tasks_blocking_shutdown, 0); |
| 73 return num_tasks_blocking_shutdown != 0; | 77 return num_tasks_blocking_shutdown != 0; |
| 74 } | 78 } |
| 75 | 79 |
| 76 // Increments the number of tasks blocking shutdown. Returns true if shutdown | 80 // Increments the number of tasks blocking shutdown. Returns true if shutdown |
| 77 // has started. | 81 // has started. |
| 78 bool IncrementNumTasksBlockingShutdown() { | 82 bool IncrementNumTasksBlockingShutdown() { |
| 79 #if DCHECK_IS_ON() | 83 #if DCHECK_IS_ON() |
| 80 // Verify that no overflow will occur. | 84 // Verify that no overflow will occur. |
| 81 const auto num_tasks_blocking_shutdown = | 85 const auto num_tasks_blocking_shutdown = |
| 82 subtle::Acquire_Load(&bits_) >> kNumTasksBlockingShutdownBitOffset; | 86 subtle::NoBarrier_Load(&bits_) >> kNumTasksBlockingShutdownBitOffset; |
| 83 DCHECK_LT(num_tasks_blocking_shutdown, | 87 DCHECK_LT(num_tasks_blocking_shutdown, |
| 84 std::numeric_limits<subtle::Atomic32>::max() - | 88 std::numeric_limits<subtle::Atomic32>::max() - |
| 85 kNumTasksBlockingShutdownIncrement); | 89 kNumTasksBlockingShutdownIncrement); |
| 86 #endif | 90 #endif |
| 87 | 91 |
| 88 const auto new_bits = subtle::Barrier_AtomicIncrement( | 92 const auto new_bits = subtle::NoBarrier_AtomicIncrement( |
| 89 &bits_, kNumTasksBlockingShutdownIncrement); | 93 &bits_, kNumTasksBlockingShutdownIncrement); |
| 90 return new_bits & kShutdownHasStartedMask; | 94 return new_bits & kShutdownHasStartedMask; |
| 91 } | 95 } |
| 92 | 96 |
| 93 // Decrements the number of tasks blocking shutdown. Returns true if shutdown | 97 // Decrements the number of tasks blocking shutdown. Returns true if shutdown |
| 94 // has started and the number of tasks blocking shutdown becomes zero. | 98 // has started and the number of tasks blocking shutdown becomes zero. |
| 95 bool DecrementNumTasksBlockingShutdown() { | 99 bool DecrementNumTasksBlockingShutdown() { |
| 96 const auto new_bits = subtle::Barrier_AtomicIncrement( | 100 const auto new_bits = subtle::NoBarrier_AtomicIncrement( |
| 97 &bits_, -kNumTasksBlockingShutdownIncrement); | 101 &bits_, -kNumTasksBlockingShutdownIncrement); |
| 98 const bool shutdown_has_started = new_bits & kShutdownHasStartedMask; | 102 const bool shutdown_has_started = new_bits & kShutdownHasStartedMask; |
| 99 const auto num_tasks_blocking_shutdown = | 103 const auto num_tasks_blocking_shutdown = |
| 100 new_bits >> kNumTasksBlockingShutdownBitOffset; | 104 new_bits >> kNumTasksBlockingShutdownBitOffset; |
| 101 DCHECK_GE(num_tasks_blocking_shutdown, 0); | 105 DCHECK_GE(num_tasks_blocking_shutdown, 0); |
| 102 return shutdown_has_started && num_tasks_blocking_shutdown == 0; | 106 return shutdown_has_started && num_tasks_blocking_shutdown == 0; |
| 103 } | 107 } |
| 104 | 108 |
| 105 private: | 109 private: |
| 106 static constexpr subtle::Atomic32 kShutdownHasStartedMask = 1; | 110 static constexpr subtle::Atomic32 kShutdownHasStartedMask = 1; |
| 107 static constexpr subtle::Atomic32 kNumTasksBlockingShutdownBitOffset = 1; | 111 static constexpr subtle::Atomic32 kNumTasksBlockingShutdownBitOffset = 1; |
| 108 static constexpr subtle::Atomic32 kNumTasksBlockingShutdownIncrement = | 112 static constexpr subtle::Atomic32 kNumTasksBlockingShutdownIncrement = |
| 109 1 << kNumTasksBlockingShutdownBitOffset; | 113 1 << kNumTasksBlockingShutdownBitOffset; |
| 110 | 114 |
| 111 // The LSB indicates whether shutdown has started. The other bits count the | 115 // The LSB indicates whether shutdown has started. The other bits count the |
| 112 // number of tasks blocking shutdown. | 116 // number of tasks blocking shutdown. |
| 117 // No barriers are required to read/write |bits_| as this class is only used |
| 118 // as an atomic state checker, it doesn't provide sequential consistency |
| 119 // guarantees w.r.t. external state. Sequencing of the TaskTracker::State |
| 120 // operations themselves is guaranteed by the AtomicIncrement RMW (read- |
| 121 // modify-write) semantics however. For example, if two threads are racing to |
| 122 // call IncrementNumTasksBlockingShutdown() and StartShutdown() respectively, |
| 123 // either the first thread will win and the StartShutdown() call will see the |
| 124 // blocking task or the second thread will win and |
| 125 // IncrementNumTasksBlockingShutdown() will know that shutdown has started. |
| 113 subtle::Atomic32 bits_ = 0; | 126 subtle::Atomic32 bits_ = 0; |
| 114 | 127 |
| 115 DISALLOW_COPY_AND_ASSIGN(State); | 128 DISALLOW_COPY_AND_ASSIGN(State); |
| 116 }; | 129 }; |
| 117 | 130 |
| 118 TaskTracker::TaskTracker() : state_(new State) {} | 131 TaskTracker::TaskTracker() : state_(new State) {} |
| 119 TaskTracker::~TaskTracker() = default; | 132 TaskTracker::~TaskTracker() = default; |
| 120 | 133 |
| 121 void TaskTracker::Shutdown() { | 134 void TaskTracker::Shutdown() { |
| 122 { | 135 { |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 330 | 343 |
| 331 // This method can only be called after shutdown has started. | 344 // This method can only be called after shutdown has started. |
| 332 DCHECK(state_->HasShutdownStarted()); | 345 DCHECK(state_->HasShutdownStarted()); |
| 333 DCHECK(shutdown_event_); | 346 DCHECK(shutdown_event_); |
| 334 | 347 |
| 335 shutdown_event_->Signal(); | 348 shutdown_event_->Signal(); |
| 336 } | 349 } |
| 337 | 350 |
| 338 } // namespace internal | 351 } // namespace internal |
| 339 } // namespace base | 352 } // namespace base |
| OLD | NEW |