blob: e2b61a920ba86f3d570792404858b424ad889aa1 [file] [log] [blame]
bcwhitea1569442016-08-10 12:10:03 +09001// Copyright 2016 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#include "base/debug/activity_tracker.h"
6
7#include <memory>
8
9#include "base/bind.h"
Peter Kasting24efe5e2018-02-24 09:03:01 +090010#include "base/bind_helpers.h"
bcwhitea1569442016-08-10 12:10:03 +090011#include "base/files/file.h"
12#include "base/files/file_util.h"
13#include "base/files/memory_mapped_file.h"
14#include "base/files/scoped_temp_dir.h"
15#include "base/memory/ptr_util.h"
16#include "base/pending_task.h"
bcwhite83c487b2016-09-03 01:38:27 +090017#include "base/rand_util.h"
bcwhitea1569442016-08-10 12:10:03 +090018#include "base/synchronization/condition_variable.h"
19#include "base/synchronization/lock.h"
20#include "base/synchronization/spin_wait.h"
bcwhite83c487b2016-09-03 01:38:27 +090021#include "base/threading/platform_thread.h"
bcwhitea1569442016-08-10 12:10:03 +090022#include "base/threading/simple_thread.h"
23#include "base/time/time.h"
24#include "testing/gtest/include/gtest/gtest.h"
25
26namespace base {
27namespace debug {
28
29namespace {
30
31class TestActivityTracker : public ThreadActivityTracker {
32 public:
33 TestActivityTracker(std::unique_ptr<char[]> memory, size_t mem_size)
34 : ThreadActivityTracker(memset(memory.get(), 0, mem_size), mem_size),
35 mem_segment_(std::move(memory)) {}
36
Chris Watkinsd155d9f2017-11-29 16:16:38 +090037 ~TestActivityTracker() override = default;
bcwhitea1569442016-08-10 12:10:03 +090038
39 private:
40 std::unique_ptr<char[]> mem_segment_;
41};
42
43} // namespace
44
45
46class ActivityTrackerTest : public testing::Test {
47 public:
bcwhite74902752016-11-16 02:41:56 +090048 const int kMemorySize = 1 << 20; // 1MiB
bcwhitea1569442016-08-10 12:10:03 +090049 const int kStackSize = 1 << 10; // 1KiB
50
bcwhite74902752016-11-16 02:41:56 +090051 using ActivityId = ThreadActivityTracker::ActivityId;
52
Chris Watkinsd155d9f2017-11-29 16:16:38 +090053 ActivityTrackerTest() = default;
bcwhitea1569442016-08-10 12:10:03 +090054
55 ~ActivityTrackerTest() override {
56 GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get();
57 if (global_tracker) {
58 global_tracker->ReleaseTrackerForCurrentThreadForTesting();
59 delete global_tracker;
60 }
61 }
62
63 std::unique_ptr<ThreadActivityTracker> CreateActivityTracker() {
64 std::unique_ptr<char[]> memory(new char[kStackSize]);
Jeremy Romancd0c4672017-08-17 08:27:24 +090065 return std::make_unique<TestActivityTracker>(std::move(memory), kStackSize);
bcwhitea1569442016-08-10 12:10:03 +090066 }
67
68 size_t GetGlobalActiveTrackerCount() {
69 GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get();
70 if (!global_tracker)
71 return 0;
72 return global_tracker->thread_tracker_count_.load(
73 std::memory_order_relaxed);
74 }
75
76 size_t GetGlobalInactiveTrackerCount() {
77 GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get();
78 if (!global_tracker)
79 return 0;
thestig475b2532017-05-25 06:57:51 +090080 AutoLock autolock(global_tracker->thread_tracker_allocator_lock_);
bcwhitee26c2242016-10-14 08:49:14 +090081 return global_tracker->thread_tracker_allocator_.cache_used();
bcwhitea1569442016-08-10 12:10:03 +090082 }
83
bcwhite74902752016-11-16 02:41:56 +090084 size_t GetGlobalUserDataMemoryCacheUsed() {
85 return GlobalActivityTracker::Get()->user_data_allocator_.cache_used();
86 }
87
bcwhite45cf1ef2017-03-17 03:41:12 +090088 void HandleProcessExit(int64_t id,
89 int64_t stamp,
90 int code,
91 GlobalActivityTracker::ProcessPhase phase,
92 std::string&& command,
93 ActivityUserData::Snapshot&& data) {
bcwhite6bd84ae2017-05-23 22:09:20 +090094 exit_id_ = id;
95 exit_stamp_ = stamp;
96 exit_code_ = code;
97 exit_phase_ = phase;
98 exit_command_ = std::move(command);
99 exit_data_ = std::move(data);
bcwhite45cf1ef2017-03-17 03:41:12 +0900100 }
101
bcwhite6bd84ae2017-05-23 22:09:20 +0900102 int64_t exit_id_ = 0;
103 int64_t exit_stamp_;
104 int exit_code_;
105 GlobalActivityTracker::ProcessPhase exit_phase_;
106 std::string exit_command_;
107 ActivityUserData::Snapshot exit_data_;
bcwhitea1569442016-08-10 12:10:03 +0900108};
109
bcwhite74902752016-11-16 02:41:56 +0900110TEST_F(ActivityTrackerTest, UserDataTest) {
111 char buffer[256];
112 memset(buffer, 0, sizeof(buffer));
113 ActivityUserData data(buffer, sizeof(buffer));
bcwhite45cf1ef2017-03-17 03:41:12 +0900114 size_t space = sizeof(buffer) - sizeof(ActivityUserData::MemoryHeader);
bcwhitea12d3ef2017-03-08 08:30:41 +0900115 ASSERT_EQ(space, data.available_);
bcwhite74902752016-11-16 02:41:56 +0900116
117 data.SetInt("foo", 1);
bcwhite45cf1ef2017-03-17 03:41:12 +0900118 space -= 24;
119 ASSERT_EQ(space, data.available_);
bcwhite74902752016-11-16 02:41:56 +0900120
121 data.SetUint("b", 1U); // Small names fit beside header in a word.
bcwhite45cf1ef2017-03-17 03:41:12 +0900122 space -= 16;
123 ASSERT_EQ(space, data.available_);
bcwhite74902752016-11-16 02:41:56 +0900124
125 data.Set("c", buffer, 10);
bcwhite45cf1ef2017-03-17 03:41:12 +0900126 space -= 24;
127 ASSERT_EQ(space, data.available_);
bcwhite74902752016-11-16 02:41:56 +0900128
129 data.SetString("dear john", "it's been fun");
bcwhite45cf1ef2017-03-17 03:41:12 +0900130 space -= 32;
131 ASSERT_EQ(space, data.available_);
bcwhite74902752016-11-16 02:41:56 +0900132
133 data.Set("c", buffer, 20);
bcwhite45cf1ef2017-03-17 03:41:12 +0900134 ASSERT_EQ(space, data.available_);
bcwhite74902752016-11-16 02:41:56 +0900135
136 data.SetString("dear john", "but we're done together");
bcwhite45cf1ef2017-03-17 03:41:12 +0900137 ASSERT_EQ(space, data.available_);
bcwhite74902752016-11-16 02:41:56 +0900138
139 data.SetString("dear john", "bye");
bcwhite45cf1ef2017-03-17 03:41:12 +0900140 ASSERT_EQ(space, data.available_);
bcwhite74902752016-11-16 02:41:56 +0900141
142 data.SetChar("d", 'x');
bcwhite45cf1ef2017-03-17 03:41:12 +0900143 space -= 8;
144 ASSERT_EQ(space, data.available_);
bcwhite2baebb12016-12-09 12:37:56 +0900145
146 data.SetBool("ee", true);
bcwhite45cf1ef2017-03-17 03:41:12 +0900147 space -= 16;
148 ASSERT_EQ(space, data.available_);
bcwhitea12d3ef2017-03-08 08:30:41 +0900149
150 data.SetString("f", "");
bcwhite45cf1ef2017-03-17 03:41:12 +0900151 space -= 8;
152 ASSERT_EQ(space, data.available_);
bcwhite74902752016-11-16 02:41:56 +0900153}
154
bcwhitea1569442016-08-10 12:10:03 +0900155TEST_F(ActivityTrackerTest, PushPopTest) {
156 std::unique_ptr<ThreadActivityTracker> tracker = CreateActivityTracker();
bcwhite2baebb12016-12-09 12:37:56 +0900157 ThreadActivityTracker::Snapshot snapshot;
bcwhitea1569442016-08-10 12:10:03 +0900158
bcwhite2baebb12016-12-09 12:37:56 +0900159 ASSERT_TRUE(tracker->CreateSnapshot(&snapshot));
bcwhitea1569442016-08-10 12:10:03 +0900160 ASSERT_EQ(0U, snapshot.activity_stack_depth);
161 ASSERT_EQ(0U, snapshot.activity_stack.size());
162
163 char origin1;
bcwhite74902752016-11-16 02:41:56 +0900164 ActivityId id1 = tracker->PushActivity(&origin1, Activity::ACT_TASK,
165 ActivityData::ForTask(11));
bcwhite2baebb12016-12-09 12:37:56 +0900166 ASSERT_TRUE(tracker->CreateSnapshot(&snapshot));
bcwhitea1569442016-08-10 12:10:03 +0900167 ASSERT_EQ(1U, snapshot.activity_stack_depth);
168 ASSERT_EQ(1U, snapshot.activity_stack.size());
169 EXPECT_NE(0, snapshot.activity_stack[0].time_internal);
bcwhitedc0d87c2016-08-12 09:04:13 +0900170 EXPECT_EQ(Activity::ACT_TASK, snapshot.activity_stack[0].activity_type);
bcwhitea1569442016-08-10 12:10:03 +0900171 EXPECT_EQ(reinterpret_cast<uintptr_t>(&origin1),
172 snapshot.activity_stack[0].origin_address);
173 EXPECT_EQ(11U, snapshot.activity_stack[0].data.task.sequence_id);
174
175 char origin2;
176 char lock2;
bcwhite74902752016-11-16 02:41:56 +0900177 ActivityId id2 = tracker->PushActivity(&origin2, Activity::ACT_LOCK,
178 ActivityData::ForLock(&lock2));
bcwhite2baebb12016-12-09 12:37:56 +0900179 ASSERT_TRUE(tracker->CreateSnapshot(&snapshot));
bcwhitea1569442016-08-10 12:10:03 +0900180 ASSERT_EQ(2U, snapshot.activity_stack_depth);
181 ASSERT_EQ(2U, snapshot.activity_stack.size());
182 EXPECT_LE(snapshot.activity_stack[0].time_internal,
183 snapshot.activity_stack[1].time_internal);
bcwhitedc0d87c2016-08-12 09:04:13 +0900184 EXPECT_EQ(Activity::ACT_LOCK, snapshot.activity_stack[1].activity_type);
bcwhitea1569442016-08-10 12:10:03 +0900185 EXPECT_EQ(reinterpret_cast<uintptr_t>(&origin2),
186 snapshot.activity_stack[1].origin_address);
187 EXPECT_EQ(reinterpret_cast<uintptr_t>(&lock2),
188 snapshot.activity_stack[1].data.lock.lock_address);
189
bcwhite74902752016-11-16 02:41:56 +0900190 tracker->PopActivity(id2);
bcwhite2baebb12016-12-09 12:37:56 +0900191 ASSERT_TRUE(tracker->CreateSnapshot(&snapshot));
bcwhitea1569442016-08-10 12:10:03 +0900192 ASSERT_EQ(1U, snapshot.activity_stack_depth);
193 ASSERT_EQ(1U, snapshot.activity_stack.size());
bcwhitedc0d87c2016-08-12 09:04:13 +0900194 EXPECT_EQ(Activity::ACT_TASK, snapshot.activity_stack[0].activity_type);
bcwhitea1569442016-08-10 12:10:03 +0900195 EXPECT_EQ(reinterpret_cast<uintptr_t>(&origin1),
196 snapshot.activity_stack[0].origin_address);
197 EXPECT_EQ(11U, snapshot.activity_stack[0].data.task.sequence_id);
198
bcwhite74902752016-11-16 02:41:56 +0900199 tracker->PopActivity(id1);
bcwhite2baebb12016-12-09 12:37:56 +0900200 ASSERT_TRUE(tracker->CreateSnapshot(&snapshot));
bcwhitea1569442016-08-10 12:10:03 +0900201 ASSERT_EQ(0U, snapshot.activity_stack_depth);
202 ASSERT_EQ(0U, snapshot.activity_stack.size());
203}
204
205TEST_F(ActivityTrackerTest, ScopedTaskTest) {
bcwhite0aa1f8c2017-04-01 01:21:53 +0900206 GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0);
bcwhitea1569442016-08-10 12:10:03 +0900207
208 ThreadActivityTracker* tracker =
209 GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread();
bcwhite2baebb12016-12-09 12:37:56 +0900210 ThreadActivityTracker::Snapshot snapshot;
bcwhite74902752016-11-16 02:41:56 +0900211 ASSERT_EQ(0U, GetGlobalUserDataMemoryCacheUsed());
bcwhitea1569442016-08-10 12:10:03 +0900212
bcwhite2baebb12016-12-09 12:37:56 +0900213 ASSERT_TRUE(tracker->CreateSnapshot(&snapshot));
bcwhitea1569442016-08-10 12:10:03 +0900214 ASSERT_EQ(0U, snapshot.activity_stack_depth);
215 ASSERT_EQ(0U, snapshot.activity_stack.size());
216
217 {
Peter Kasting24efe5e2018-02-24 09:03:01 +0900218 PendingTask task1(FROM_HERE, DoNothing());
bcwhitea1569442016-08-10 12:10:03 +0900219 ScopedTaskRunActivity activity1(task1);
bcwhite74902752016-11-16 02:41:56 +0900220 ActivityUserData& user_data1 = activity1.user_data();
221 (void)user_data1; // Tell compiler it's been used.
bcwhitea1569442016-08-10 12:10:03 +0900222
bcwhite2baebb12016-12-09 12:37:56 +0900223 ASSERT_TRUE(tracker->CreateSnapshot(&snapshot));
bcwhitea1569442016-08-10 12:10:03 +0900224 ASSERT_EQ(1U, snapshot.activity_stack_depth);
225 ASSERT_EQ(1U, snapshot.activity_stack.size());
bcwhitedc0d87c2016-08-12 09:04:13 +0900226 EXPECT_EQ(Activity::ACT_TASK, snapshot.activity_stack[0].activity_type);
bcwhitea1569442016-08-10 12:10:03 +0900227
228 {
Peter Kasting24efe5e2018-02-24 09:03:01 +0900229 PendingTask task2(FROM_HERE, DoNothing());
bcwhitea1569442016-08-10 12:10:03 +0900230 ScopedTaskRunActivity activity2(task2);
bcwhite74902752016-11-16 02:41:56 +0900231 ActivityUserData& user_data2 = activity2.user_data();
232 (void)user_data2; // Tell compiler it's been used.
bcwhitea1569442016-08-10 12:10:03 +0900233
bcwhite2baebb12016-12-09 12:37:56 +0900234 ASSERT_TRUE(tracker->CreateSnapshot(&snapshot));
bcwhitea1569442016-08-10 12:10:03 +0900235 ASSERT_EQ(2U, snapshot.activity_stack_depth);
236 ASSERT_EQ(2U, snapshot.activity_stack.size());
bcwhitedc0d87c2016-08-12 09:04:13 +0900237 EXPECT_EQ(Activity::ACT_TASK, snapshot.activity_stack[1].activity_type);
bcwhitea1569442016-08-10 12:10:03 +0900238 }
239
bcwhite2baebb12016-12-09 12:37:56 +0900240 ASSERT_TRUE(tracker->CreateSnapshot(&snapshot));
bcwhitea1569442016-08-10 12:10:03 +0900241 ASSERT_EQ(1U, snapshot.activity_stack_depth);
242 ASSERT_EQ(1U, snapshot.activity_stack.size());
bcwhitedc0d87c2016-08-12 09:04:13 +0900243 EXPECT_EQ(Activity::ACT_TASK, snapshot.activity_stack[0].activity_type);
bcwhitea1569442016-08-10 12:10:03 +0900244 }
245
bcwhite2baebb12016-12-09 12:37:56 +0900246 ASSERT_TRUE(tracker->CreateSnapshot(&snapshot));
bcwhitea1569442016-08-10 12:10:03 +0900247 ASSERT_EQ(0U, snapshot.activity_stack_depth);
248 ASSERT_EQ(0U, snapshot.activity_stack.size());
bcwhite74902752016-11-16 02:41:56 +0900249 ASSERT_EQ(2U, GetGlobalUserDataMemoryCacheUsed());
bcwhitea1569442016-08-10 12:10:03 +0900250}
251
Brian White43d72ee2017-10-26 06:44:03 +0900252namespace {
253
254class SimpleLockThread : public SimpleThread {
255 public:
256 SimpleLockThread(const std::string& name, Lock* lock)
257 : SimpleThread(name, Options()),
258 lock_(lock),
259 data_changed_(false),
260 is_running_(false) {}
261
Chris Watkinsd155d9f2017-11-29 16:16:38 +0900262 ~SimpleLockThread() override = default;
Brian White43d72ee2017-10-26 06:44:03 +0900263
264 void Run() override {
265 ThreadActivityTracker* tracker =
266 GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread();
Brian White74b52d22017-11-24 01:53:24 +0900267 uint32_t pre_version = tracker->GetDataVersionForTesting();
Brian White43d72ee2017-10-26 06:44:03 +0900268
269 is_running_.store(true, std::memory_order_relaxed);
270 lock_->Acquire();
Brian White74b52d22017-11-24 01:53:24 +0900271 data_changed_ = tracker->GetDataVersionForTesting() != pre_version;
Brian White43d72ee2017-10-26 06:44:03 +0900272 lock_->Release();
273 is_running_.store(false, std::memory_order_relaxed);
274 }
275
276 bool IsRunning() { return is_running_.load(std::memory_order_relaxed); }
277
278 bool WasDataChanged() { return data_changed_; };
279
280 private:
281 Lock* lock_;
282 bool data_changed_;
283 std::atomic<bool> is_running_;
284
285 DISALLOW_COPY_AND_ASSIGN(SimpleLockThread);
286};
287
288} // namespace
289
290TEST_F(ActivityTrackerTest, LockTest) {
291 GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0);
292
293 ThreadActivityTracker* tracker =
294 GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread();
295 ThreadActivityTracker::Snapshot snapshot;
296 ASSERT_EQ(0U, GetGlobalUserDataMemoryCacheUsed());
297
298 Lock lock;
Brian White74b52d22017-11-24 01:53:24 +0900299 uint32_t pre_version = tracker->GetDataVersionForTesting();
Brian White43d72ee2017-10-26 06:44:03 +0900300
301 // Check no activity when only "trying" a lock.
302 EXPECT_TRUE(lock.Try());
Brian White74b52d22017-11-24 01:53:24 +0900303 EXPECT_EQ(pre_version, tracker->GetDataVersionForTesting());
Brian White43d72ee2017-10-26 06:44:03 +0900304 lock.Release();
Brian White74b52d22017-11-24 01:53:24 +0900305 EXPECT_EQ(pre_version, tracker->GetDataVersionForTesting());
Brian White43d72ee2017-10-26 06:44:03 +0900306
307 // Check no activity when acquiring a free lock.
308 SimpleLockThread t1("locker1", &lock);
309 t1.Start();
310 t1.Join();
311 EXPECT_FALSE(t1.WasDataChanged());
312
313 // Check that activity is recorded when acquring a busy lock.
314 SimpleLockThread t2("locker2", &lock);
315 lock.Acquire();
316 t2.Start();
317 while (!t2.IsRunning())
318 PlatformThread::Sleep(TimeDelta::FromMilliseconds(10));
319 // t2 can't join until the lock is released but have to give time for t2 to
320 // actually block on the lock before releasing it or the results will not
321 // be correct.
322 PlatformThread::Sleep(TimeDelta::FromMilliseconds(200));
323 lock.Release();
324 // Now the results will be valid.
325 t2.Join();
326 EXPECT_TRUE(t2.WasDataChanged());
327}
328
bcwhite79603d92017-03-24 22:24:39 +0900329TEST_F(ActivityTrackerTest, ExceptionTest) {
bcwhite0aa1f8c2017-04-01 01:21:53 +0900330 GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0);
bcwhite79603d92017-03-24 22:24:39 +0900331 GlobalActivityTracker* global = GlobalActivityTracker::Get();
332
333 ThreadActivityTracker* tracker =
334 GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread();
335 ThreadActivityTracker::Snapshot snapshot;
336 ASSERT_EQ(0U, GetGlobalUserDataMemoryCacheUsed());
337
338 ASSERT_TRUE(tracker->CreateSnapshot(&snapshot));
339 ASSERT_EQ(0U, snapshot.last_exception.activity_type);
340
341 char origin;
342 global->RecordException(&origin, 42);
343
344 ASSERT_TRUE(tracker->CreateSnapshot(&snapshot));
345 EXPECT_EQ(Activity::ACT_EXCEPTION, snapshot.last_exception.activity_type);
346 EXPECT_EQ(reinterpret_cast<uintptr_t>(&origin),
347 snapshot.last_exception.origin_address);
348 EXPECT_EQ(42U, snapshot.last_exception.data.exception.code);
349}
350
bcwhitea1569442016-08-10 12:10:03 +0900351TEST_F(ActivityTrackerTest, CreateWithFileTest) {
352 const char temp_name[] = "CreateWithFileTest";
353 ScopedTempDir temp_dir;
354 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
vabr31978e92016-09-08 18:26:27 +0900355 FilePath temp_file = temp_dir.GetPath().AppendASCII(temp_name);
bcwhitea1569442016-08-10 12:10:03 +0900356 const size_t temp_size = 64 << 10; // 64 KiB
357
358 // Create a global tracker on a new file.
359 ASSERT_FALSE(PathExists(temp_file));
360 GlobalActivityTracker::CreateWithFile(temp_file, temp_size, 0, "foo", 3);
361 GlobalActivityTracker* global = GlobalActivityTracker::Get();
362 EXPECT_EQ(std::string("foo"), global->allocator()->Name());
363 global->ReleaseTrackerForCurrentThreadForTesting();
364 delete global;
365
366 // Create a global tracker over an existing file, replacing it. If the
367 // replacement doesn't work, the name will remain as it was first created.
368 ASSERT_TRUE(PathExists(temp_file));
369 GlobalActivityTracker::CreateWithFile(temp_file, temp_size, 0, "bar", 3);
370 global = GlobalActivityTracker::Get();
371 EXPECT_EQ(std::string("bar"), global->allocator()->Name());
372 global->ReleaseTrackerForCurrentThreadForTesting();
373 delete global;
374}
375
376
377// GlobalActivityTracker tests below.
378
bcwhite45cf1ef2017-03-17 03:41:12 +0900379TEST_F(ActivityTrackerTest, BasicTest) {
bcwhite0aa1f8c2017-04-01 01:21:53 +0900380 GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0);
bcwhite45cf1ef2017-03-17 03:41:12 +0900381 GlobalActivityTracker* global = GlobalActivityTracker::Get();
382
383 // Ensure the data repositories have backing store, indicated by non-zero ID.
384 EXPECT_NE(0U, global->process_data().id());
bcwhite45cf1ef2017-03-17 03:41:12 +0900385}
386
thestig475b2532017-05-25 06:57:51 +0900387namespace {
388
bcwhitea1569442016-08-10 12:10:03 +0900389class SimpleActivityThread : public SimpleThread {
390 public:
391 SimpleActivityThread(const std::string& name,
392 const void* origin,
bcwhitedc0d87c2016-08-12 09:04:13 +0900393 Activity::Type activity,
394 const ActivityData& data)
bcwhitea1569442016-08-10 12:10:03 +0900395 : SimpleThread(name, Options()),
396 origin_(origin),
397 activity_(activity),
398 data_(data),
thestig475b2532017-05-25 06:57:51 +0900399 ready_(false),
400 exit_(false),
bcwhitea1569442016-08-10 12:10:03 +0900401 exit_condition_(&lock_) {}
402
Chris Watkinsd155d9f2017-11-29 16:16:38 +0900403 ~SimpleActivityThread() override = default;
bcwhitea1569442016-08-10 12:10:03 +0900404
405 void Run() override {
bcwhite74902752016-11-16 02:41:56 +0900406 ThreadActivityTracker::ActivityId id =
407 GlobalActivityTracker::Get()
408 ->GetOrCreateTrackerForCurrentThread()
409 ->PushActivity(origin_, activity_, data_);
bcwhitea1569442016-08-10 12:10:03 +0900410
411 {
412 AutoLock auto_lock(lock_);
thestig475b2532017-05-25 06:57:51 +0900413 ready_.store(true, std::memory_order_release);
414 while (!exit_.load(std::memory_order_relaxed))
bcwhitea1569442016-08-10 12:10:03 +0900415 exit_condition_.Wait();
416 }
417
bcwhite74902752016-11-16 02:41:56 +0900418 GlobalActivityTracker::Get()->GetTrackerForCurrentThread()->PopActivity(id);
bcwhitea1569442016-08-10 12:10:03 +0900419 }
420
421 void Exit() {
422 AutoLock auto_lock(lock_);
thestig475b2532017-05-25 06:57:51 +0900423 exit_.store(true, std::memory_order_relaxed);
bcwhitea1569442016-08-10 12:10:03 +0900424 exit_condition_.Signal();
425 }
426
427 void WaitReady() {
thestig475b2532017-05-25 06:57:51 +0900428 SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(ready_.load(std::memory_order_acquire));
bcwhitea1569442016-08-10 12:10:03 +0900429 }
430
431 private:
432 const void* origin_;
bcwhitedc0d87c2016-08-12 09:04:13 +0900433 Activity::Type activity_;
434 ActivityData data_;
bcwhitea1569442016-08-10 12:10:03 +0900435
thestig475b2532017-05-25 06:57:51 +0900436 std::atomic<bool> ready_;
437 std::atomic<bool> exit_;
bcwhitea1569442016-08-10 12:10:03 +0900438 Lock lock_;
439 ConditionVariable exit_condition_;
440
441 DISALLOW_COPY_AND_ASSIGN(SimpleActivityThread);
442};
443
thestig475b2532017-05-25 06:57:51 +0900444} // namespace
445
bcwhitea1569442016-08-10 12:10:03 +0900446TEST_F(ActivityTrackerTest, ThreadDeathTest) {
bcwhite0aa1f8c2017-04-01 01:21:53 +0900447 GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0);
bcwhitea1569442016-08-10 12:10:03 +0900448 GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread();
449 const size_t starting_active = GetGlobalActiveTrackerCount();
450 const size_t starting_inactive = GetGlobalInactiveTrackerCount();
451
bcwhitedc0d87c2016-08-12 09:04:13 +0900452 SimpleActivityThread t1("t1", nullptr, Activity::ACT_TASK,
453 ActivityData::ForTask(11));
bcwhitea1569442016-08-10 12:10:03 +0900454 t1.Start();
455 t1.WaitReady();
456 EXPECT_EQ(starting_active + 1, GetGlobalActiveTrackerCount());
457 EXPECT_EQ(starting_inactive, GetGlobalInactiveTrackerCount());
458
459 t1.Exit();
460 t1.Join();
461 EXPECT_EQ(starting_active, GetGlobalActiveTrackerCount());
462 EXPECT_EQ(starting_inactive + 1, GetGlobalInactiveTrackerCount());
463
464 // Start another thread and ensure it re-uses the existing memory.
465
bcwhitedc0d87c2016-08-12 09:04:13 +0900466 SimpleActivityThread t2("t2", nullptr, Activity::ACT_TASK,
467 ActivityData::ForTask(22));
bcwhitea1569442016-08-10 12:10:03 +0900468 t2.Start();
469 t2.WaitReady();
470 EXPECT_EQ(starting_active + 1, GetGlobalActiveTrackerCount());
471 EXPECT_EQ(starting_inactive, GetGlobalInactiveTrackerCount());
472
473 t2.Exit();
474 t2.Join();
475 EXPECT_EQ(starting_active, GetGlobalActiveTrackerCount());
476 EXPECT_EQ(starting_inactive + 1, GetGlobalInactiveTrackerCount());
477}
478
bcwhite6bd84ae2017-05-23 22:09:20 +0900479TEST_F(ActivityTrackerTest, ProcessDeathTest) {
bcwhite45cf1ef2017-03-17 03:41:12 +0900480 // This doesn't actually create and destroy a process. Instead, it uses for-
481 // testing interfaces to simulate data created by other processes.
scottmgab603032017-05-24 12:45:58 +0900482 const int64_t other_process_id = GetCurrentProcId() + 1;
bcwhite45cf1ef2017-03-17 03:41:12 +0900483
bcwhite0aa1f8c2017-04-01 01:21:53 +0900484 GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0);
bcwhite45cf1ef2017-03-17 03:41:12 +0900485 GlobalActivityTracker* global = GlobalActivityTracker::Get();
486 ThreadActivityTracker* thread = global->GetOrCreateTrackerForCurrentThread();
487
488 // Get callbacks for process exit.
489 global->SetProcessExitCallback(
490 Bind(&ActivityTrackerTest::HandleProcessExit, Unretained(this)));
491
492 // Pretend than another process has started.
493 global->RecordProcessLaunch(other_process_id, FILE_PATH_LITERAL("foo --bar"));
494
495 // Do some activities.
Peter Kasting24efe5e2018-02-24 09:03:01 +0900496 PendingTask task(FROM_HERE, DoNothing());
bcwhite45cf1ef2017-03-17 03:41:12 +0900497 ScopedTaskRunActivity activity(task);
498 ActivityUserData& user_data = activity.user_data();
499 ASSERT_NE(0U, user_data.id());
500
501 // Get the memory-allocator references to that data.
502 PersistentMemoryAllocator::Reference proc_data_ref =
503 global->allocator()->GetAsReference(
504 global->process_data().GetBaseAddress(),
505 GlobalActivityTracker::kTypeIdProcessDataRecord);
506 ASSERT_TRUE(proc_data_ref);
507 PersistentMemoryAllocator::Reference tracker_ref =
508 global->allocator()->GetAsReference(
509 thread->GetBaseAddress(),
510 GlobalActivityTracker::kTypeIdActivityTracker);
511 ASSERT_TRUE(tracker_ref);
512 PersistentMemoryAllocator::Reference user_data_ref =
513 global->allocator()->GetAsReference(
514 user_data.GetBaseAddress(),
515 GlobalActivityTracker::kTypeIdUserDataRecord);
516 ASSERT_TRUE(user_data_ref);
517
518 // Make a copy of the thread-tracker state so it can be restored later.
519 const size_t tracker_size = global->allocator()->GetAllocSize(tracker_ref);
520 std::unique_ptr<char[]> tracker_copy(new char[tracker_size]);
521 memcpy(tracker_copy.get(), thread->GetBaseAddress(), tracker_size);
522
bcwhite6bd84ae2017-05-23 22:09:20 +0900523 // Change the objects to appear to be owned by another process. Use a "past"
524 // time so that exit-time is always later than create-time.
525 const int64_t past_stamp = Time::Now().ToInternalValue() - 1;
bcwhite0aa1f8c2017-04-01 01:21:53 +0900526 int64_t owning_id;
bcwhite45cf1ef2017-03-17 03:41:12 +0900527 int64_t stamp;
528 ASSERT_TRUE(ActivityUserData::GetOwningProcessId(
529 global->process_data().GetBaseAddress(), &owning_id, &stamp));
530 EXPECT_NE(other_process_id, owning_id);
531 ASSERT_TRUE(ThreadActivityTracker::GetOwningProcessId(
532 thread->GetBaseAddress(), &owning_id, &stamp));
533 EXPECT_NE(other_process_id, owning_id);
534 ASSERT_TRUE(ActivityUserData::GetOwningProcessId(user_data.GetBaseAddress(),
535 &owning_id, &stamp));
536 EXPECT_NE(other_process_id, owning_id);
bcwhite6bd84ae2017-05-23 22:09:20 +0900537 global->process_data().SetOwningProcessIdForTesting(other_process_id,
538 past_stamp);
539 thread->SetOwningProcessIdForTesting(other_process_id, past_stamp);
540 user_data.SetOwningProcessIdForTesting(other_process_id, past_stamp);
bcwhite45cf1ef2017-03-17 03:41:12 +0900541 ASSERT_TRUE(ActivityUserData::GetOwningProcessId(
542 global->process_data().GetBaseAddress(), &owning_id, &stamp));
543 EXPECT_EQ(other_process_id, owning_id);
544 ASSERT_TRUE(ThreadActivityTracker::GetOwningProcessId(
545 thread->GetBaseAddress(), &owning_id, &stamp));
546 EXPECT_EQ(other_process_id, owning_id);
547 ASSERT_TRUE(ActivityUserData::GetOwningProcessId(user_data.GetBaseAddress(),
548 &owning_id, &stamp));
549 EXPECT_EQ(other_process_id, owning_id);
550
551 // Check that process exit will perform callback and free the allocations.
bcwhite6bd84ae2017-05-23 22:09:20 +0900552 ASSERT_EQ(0, exit_id_);
bcwhite45cf1ef2017-03-17 03:41:12 +0900553 ASSERT_EQ(GlobalActivityTracker::kTypeIdProcessDataRecord,
554 global->allocator()->GetType(proc_data_ref));
555 ASSERT_EQ(GlobalActivityTracker::kTypeIdActivityTracker,
556 global->allocator()->GetType(tracker_ref));
557 ASSERT_EQ(GlobalActivityTracker::kTypeIdUserDataRecord,
558 global->allocator()->GetType(user_data_ref));
559 global->RecordProcessExit(other_process_id, 0);
bcwhite6bd84ae2017-05-23 22:09:20 +0900560 EXPECT_EQ(other_process_id, exit_id_);
561 EXPECT_EQ("foo --bar", exit_command_);
bcwhite45cf1ef2017-03-17 03:41:12 +0900562 EXPECT_EQ(GlobalActivityTracker::kTypeIdProcessDataRecordFree,
563 global->allocator()->GetType(proc_data_ref));
564 EXPECT_EQ(GlobalActivityTracker::kTypeIdActivityTrackerFree,
565 global->allocator()->GetType(tracker_ref));
566 EXPECT_EQ(GlobalActivityTracker::kTypeIdUserDataRecordFree,
567 global->allocator()->GetType(user_data_ref));
568
569 // Restore memory contents and types so things don't crash when doing real
570 // process clean-up.
571 memcpy(const_cast<void*>(thread->GetBaseAddress()), tracker_copy.get(),
572 tracker_size);
573 global->allocator()->ChangeType(
574 proc_data_ref, GlobalActivityTracker::kTypeIdProcessDataRecord,
575 GlobalActivityTracker::kTypeIdUserDataRecordFree, false);
576 global->allocator()->ChangeType(
577 tracker_ref, GlobalActivityTracker::kTypeIdActivityTracker,
578 GlobalActivityTracker::kTypeIdActivityTrackerFree, false);
579 global->allocator()->ChangeType(
580 user_data_ref, GlobalActivityTracker::kTypeIdUserDataRecord,
581 GlobalActivityTracker::kTypeIdUserDataRecordFree, false);
582}
583
bcwhitea1569442016-08-10 12:10:03 +0900584} // namespace debug
585} // namespace base