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

Side by Side Diff: base/debug/activity_tracker.cc

Issue 2249683003: Fix some TSAN problems in Activity Tracker/Analyzer. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fixed compile problem 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
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/debug/activity_tracker.h" 5 #include "base/debug/activity_tracker.h"
6 6
7 #include "base/debug/stack_trace.h" 7 #include "base/debug/stack_trace.h"
8 #include "base/files/file.h" 8 #include "base/files/file.h"
9 #include "base/files/file_path.h" 9 #include "base/files/file_path.h"
10 #include "base/files/memory_mapped_file.h" 10 #include "base/files/memory_mapped_file.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/memory/ptr_util.h" 12 #include "base/memory/ptr_util.h"
13 #include "base/metrics/field_trial.h" 13 #include "base/metrics/field_trial.h"
14 #include "base/metrics/histogram_macros.h" 14 #include "base/metrics/histogram_macros.h"
15 #include "base/pending_task.h" 15 #include "base/pending_task.h"
16 #include "base/process/process.h" 16 #include "base/process/process.h"
17 #include "base/process/process_handle.h" 17 #include "base/process/process_handle.h"
18 #include "base/stl_util.h" 18 #include "base/stl_util.h"
19 #include "base/strings/string_util.h" 19 #include "base/strings/string_util.h"
20 #include "base/threading/platform_thread.h" 20 #include "base/threading/platform_thread.h"
21 21
22 namespace base { 22 namespace base {
23 namespace debug { 23 namespace debug {
24 24
25 namespace { 25 namespace {
26 26
27 // A number that identifies the memory as having been initialized. It's 27 // A number that identifies the memory as having been initialized. It's
28 // arbitrary but happens to be the first 8 bytes of SHA1(ThreadActivityTracker). 28 // arbitrary but happens to be the first 4 bytes of SHA1(ThreadActivityTracker).
29 // A version number is added on so that major structure changes won't try to 29 // A version number is added on so that major structure changes won't try to
30 // read an older version (since the cookie won't match). 30 // read an older version (since the cookie won't match).
31 const uint64_t kHeaderCookie = 0xC0029B240D4A3092ULL + 1; // v1 31 const uint32_t kHeaderCookie = 0xC0029B24UL + 2; // v2
32 32
33 // The minimum depth a stack should support. 33 // The minimum depth a stack should support.
34 const int kMinStackDepth = 2; 34 const int kMinStackDepth = 2;
35 35
36 union ThreadRef { 36 union ThreadRef {
37 int64_t as_id; 37 int64_t as_id;
38 #if defined(OS_WIN) 38 #if defined(OS_WIN)
39 // On Windows, the handle itself is often a pseudo-handle with a common 39 // On Windows, the handle itself is often a pseudo-handle with a common
40 // value meaning "this thread" and so the thread-id is used. The former 40 // value meaning "this thread" and so the thread-id is used. The former
41 // can be converted to a thread-id with a system call. 41 // can be converted to a thread-id with a system call.
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 94
95 ActivitySnapshot::ActivitySnapshot() {} 95 ActivitySnapshot::ActivitySnapshot() {}
96 ActivitySnapshot::~ActivitySnapshot() {} 96 ActivitySnapshot::~ActivitySnapshot() {}
97 97
98 98
99 // This information is kept for every thread that is tracked. It is filled 99 // This information is kept for every thread that is tracked. It is filled
100 // the very first time the thread is seen. All fields must be of exact sizes 100 // the very first time the thread is seen. All fields must be of exact sizes
101 // so there is no issue moving between 32 and 64-bit builds. 101 // so there is no issue moving between 32 and 64-bit builds.
102 struct ThreadActivityTracker::Header { 102 struct ThreadActivityTracker::Header {
103 // This unique number indicates a valid initialization of the memory. 103 // This unique number indicates a valid initialization of the memory.
104 uint64_t cookie; 104 std::atomic<uint32_t> cookie;
105 uint32_t reserved; // pad out to 64 bits
105 106
106 // The process-id and thread-id (thread_ref.as_id) to which this data belongs. 107 // The process-id and thread-id (thread_ref.as_id) to which this data belongs.
107 // These identifiers are not guaranteed to mean anything but are unique, in 108 // These identifiers are not guaranteed to mean anything but are unique, in
108 // combination, among all active trackers. It would be nice to always have 109 // combination, among all active trackers. It would be nice to always have
109 // the process_id be a 64-bit value but the necessity of having it atomic 110 // the process_id be a 64-bit value but the necessity of having it atomic
110 // (for the memory barriers it provides) limits it to the natural word size 111 // (for the memory barriers it provides) limits it to the natural word size
111 // of the machine. 112 // of the machine.
112 #ifdef ARCH_CPU_64_BITS 113 #ifdef ARCH_CPU_64_BITS
113 std::atomic<int64_t> process_id; 114 std::atomic<int64_t> process_id;
114 #else 115 #else
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
175 sizeof(header_->thread_ref) == sizeof(header_->thread_ref.as_id), 176 sizeof(header_->thread_ref) == sizeof(header_->thread_ref.as_id),
176 "PlatformThreadHandle::Handle is too big to hold in 64-bit ID"); 177 "PlatformThreadHandle::Handle is too big to hold in 64-bit ID");
177 178
178 // Ensure that the alignment of Activity.data is properly aligned to a 179 // Ensure that the alignment of Activity.data is properly aligned to a
179 // 64-bit boundary so there are no interoperability-issues across cpu 180 // 64-bit boundary so there are no interoperability-issues across cpu
180 // architectures. 181 // architectures.
181 static_assert(offsetof(Activity, data) % sizeof(uint64_t) == 0, 182 static_assert(offsetof(Activity, data) % sizeof(uint64_t) == 0,
182 "ActivityData.data is not 64-bit aligned"); 183 "ActivityData.data is not 64-bit aligned");
183 184
184 // Provided memory should either be completely initialized or all zeros. 185 // Provided memory should either be completely initialized or all zeros.
185 if (header_->cookie == 0) { 186 if (header_->cookie.load(std::memory_order_relaxed) == 0) {
186 // This is a new file. Double-check other fields and then initialize. 187 // This is a new file. Double-check other fields and then initialize.
187 DCHECK_EQ(0, header_->process_id.load(std::memory_order_relaxed)); 188 DCHECK_EQ(0, header_->process_id.load(std::memory_order_relaxed));
188 DCHECK_EQ(0, header_->thread_ref.as_id); 189 DCHECK_EQ(0, header_->thread_ref.as_id);
189 DCHECK_EQ(0, header_->start_time); 190 DCHECK_EQ(0, header_->start_time);
190 DCHECK_EQ(0, header_->start_ticks); 191 DCHECK_EQ(0, header_->start_ticks);
191 DCHECK_EQ(0U, header_->stack_slots); 192 DCHECK_EQ(0U, header_->stack_slots);
192 DCHECK_EQ(0U, header_->current_depth.load(std::memory_order_relaxed)); 193 DCHECK_EQ(0U, header_->current_depth.load(std::memory_order_relaxed));
193 DCHECK_EQ(0U, header_->stack_unchanged.load(std::memory_order_relaxed)); 194 DCHECK_EQ(0U, header_->stack_unchanged.load(std::memory_order_relaxed));
194 DCHECK_EQ(0, stack_[0].time_internal); 195 DCHECK_EQ(0, stack_[0].time_internal);
195 DCHECK_EQ(0U, stack_[0].origin_address); 196 DCHECK_EQ(0U, stack_[0].origin_address);
196 DCHECK_EQ(0U, stack_[0].call_stack[0]); 197 DCHECK_EQ(0U, stack_[0].call_stack[0]);
197 DCHECK_EQ(0U, stack_[0].data.task.sequence_id); 198 DCHECK_EQ(0U, stack_[0].data.task.sequence_id);
198 199
199 #if defined(OS_WIN) 200 #if defined(OS_WIN)
200 header_->thread_ref.as_tid = PlatformThread::CurrentId(); 201 header_->thread_ref.as_tid = PlatformThread::CurrentId();
201 #elif defined(OS_POSIX) 202 #elif defined(OS_POSIX)
202 header_->thread_ref.as_handle = 203 header_->thread_ref.as_handle =
203 PlatformThread::CurrentHandle().platform_handle(); 204 PlatformThread::CurrentHandle().platform_handle();
204 #endif 205 #endif
206 header_->process_id.store(GetCurrentProcId(), std::memory_order_relaxed);
207
205 header_->start_time = base::Time::Now().ToInternalValue(); 208 header_->start_time = base::Time::Now().ToInternalValue();
206 header_->start_ticks = base::TimeTicks::Now().ToInternalValue(); 209 header_->start_ticks = base::TimeTicks::Now().ToInternalValue();
207 header_->stack_slots = stack_slots_; 210 header_->stack_slots = stack_slots_;
208 strlcpy(header_->thread_name, PlatformThread::GetName(), 211 strlcpy(header_->thread_name, PlatformThread::GetName(),
209 sizeof(header_->thread_name)); 212 sizeof(header_->thread_name));
210 header_->cookie = kHeaderCookie;
211 213
212 // This is done last so as to guarantee that everything above is "released" 214 // This is done last so as to guarantee that everything above is "released"
213 // by the time this value gets written. 215 // by the time this value gets written.
214 header_->process_id.store(GetCurrentProcId(), std::memory_order_release); 216 header_->cookie.store(kHeaderCookie, std::memory_order_release);
215 217
216 valid_ = true; 218 valid_ = true;
217 DCHECK(IsValid()); 219 DCHECK(IsValid());
218 } else { 220 } else {
219 // This is a file with existing data. Perform basic consistency checks. 221 // This is a file with existing data. Perform basic consistency checks.
220 valid_ = true; 222 valid_ = true;
221 valid_ = IsValid(); 223 valid_ = IsValid();
222 } 224 }
223 } 225 }
224 226
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
298 // The stack has shrunk meaning that some other thread trying to copy the 300 // The stack has shrunk meaning that some other thread trying to copy the
299 // contents for reporting purposes could get bad data. That thread would 301 // contents for reporting purposes could get bad data. That thread would
300 // have written a non-zero value into |stack_unchanged|; clearing it here 302 // have written a non-zero value into |stack_unchanged|; clearing it here
301 // will let that thread detect that something did change. This needs to 303 // will let that thread detect that something did change. This needs to
302 // happen after the atomic |depth| operation above so a "release" store 304 // happen after the atomic |depth| operation above so a "release" store
303 // is required. 305 // is required.
304 header_->stack_unchanged.store(0, std::memory_order_release); 306 header_->stack_unchanged.store(0, std::memory_order_release);
305 } 307 }
306 308
307 bool ThreadActivityTracker::IsValid() const { 309 bool ThreadActivityTracker::IsValid() const {
308 if (header_->cookie != kHeaderCookie || 310 if (header_->cookie.load(std::memory_order_acquire) != kHeaderCookie ||
309 header_->process_id.load(std::memory_order_relaxed) == 0 || 311 header_->process_id.load(std::memory_order_relaxed) == 0 ||
310 header_->thread_ref.as_id == 0 || 312 header_->thread_ref.as_id == 0 ||
311 header_->start_time == 0 || 313 header_->start_time == 0 ||
312 header_->start_ticks == 0 || 314 header_->start_ticks == 0 ||
313 header_->stack_slots != stack_slots_ || 315 header_->stack_slots != stack_slots_ ||
314 header_->thread_name[sizeof(header_->thread_name) - 1] != '\0') { 316 header_->thread_name[sizeof(header_->thread_name) - 1] != '\0') {
315 return false; 317 return false;
316 } 318 }
317 319
318 return valid_; 320 return valid_;
(...skipping 449 matching lines...) Expand 10 before | Expand all | Expand 10 after
768 const base::Process* process) 770 const base::Process* process)
769 : GlobalActivityTracker::ScopedThreadActivity( 771 : GlobalActivityTracker::ScopedThreadActivity(
770 nullptr, 772 nullptr,
771 Activity::ACT_PROCESS_WAIT, 773 Activity::ACT_PROCESS_WAIT,
772 ActivityData::ForProcess(process->Pid()), 774 ActivityData::ForProcess(process->Pid()),
773 /*lock_allowed=*/true) {} 775 /*lock_allowed=*/true) {}
774 #endif 776 #endif
775 777
776 } // namespace debug 778 } // namespace debug
777 } // namespace base 779 } // namespace base
OLDNEW
« base/debug/activity_analyzer_unittest.cc ('K') | « base/debug/activity_analyzer_unittest.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698