Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(402)

Side by Side Diff: base/task_scheduler/task_tracker.cc

Issue 2235283002: Fix incorrect memory barrier usage I previously asked to be introduced. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/task_scheduler/task_tracker.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
OLDNEW
« no previous file with comments | « base/task_scheduler/task_tracker.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698