summaryrefslogtreecommitdiff
path: root/base
diff options
context:
space:
mode:
authorChris Hamilton <chrisha@chromium.org>2019-04-25 01:59:51 +0900
committerQijiang Fan <fqj@google.com>2020-06-05 12:52:28 +0900
commit771db1ae2264de322782d1829cc148bec8aaf475 (patch)
tree77ebfa08d8b2e8fb2ee8bdd7f27beedecdef78fa /base
parentdc0f741af5cc6e6695ba4712f621260fe665cbd3 (diff)
downloadlibchrome-771db1ae2264de322782d1829cc148bec8aaf475.tar.gz
Add IPC handler program counter to PendingTask and TaskAnnotator.
This adds an additional "always present" task backtrace frame that will correspond to the program counter of an IPC handler. This is always nullptr for now, but a further CL will instrument the generated IPC dispatch functions. BUG=950668 Change-Id: I45074c4961d157b0ef34b4313ddc04d271917f93 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1579271 Reviewed-by: François Doray <fdoray@chromium.org> Commit-Queue: Chris Hamilton <chrisha@chromium.org> Cr-Commit-Position: refs/heads/master@{#653621} CrOS-Libchrome-Original-Commit: 60dcc26b91b1d20e5bacc738db0ee60922024a8e
Diffstat (limited to 'base')
-rw-r--r--base/pending_task.h10
-rw-r--r--base/task/common/task_annotator.cc85
-rw-r--r--base/task/common/task_annotator.h19
-rw-r--r--base/task/common/task_annotator_unittest.cc134
4 files changed, 189 insertions, 59 deletions
diff --git a/base/pending_task.h b/base/pending_task.h
index e7b7c80169..45ed675249 100644
--- a/base/pending_task.h
+++ b/base/pending_task.h
@@ -58,6 +58,16 @@ struct BASE_EXPORT PendingTask {
static constexpr size_t kTaskBacktraceLength = 4;
std::array<const void*, kTaskBacktraceLength> task_backtrace = {};
+ // The context of the IPC message that was being handled when this task was
+ // posted. This is a program counter that is set within the scope of an IPC
+ // handler and when symbolized uniquely identifies the message being
+ // processed. This property is also propagated from one PendingTask to the
+ // next. For example, if pending task A was posted while handling an IPC,
+ // and pending task B was posted from within pending task A, then pending task
+ // B will inherit the |ipc_program_counter| of pending task A. In some sense
+ // this can be interpreted as a "root" task backtrace frame.
+ const void* ipc_program_counter = nullptr;
+
// Secondary sort key for run time.
int sequence_num = 0;
diff --git a/base/task/common/task_annotator.cc b/base/task/common/task_annotator.cc
index 76294de194..b5b0873947 100644
--- a/base/task/common/task_annotator.cc
+++ b/base/task/common/task_annotator.cc
@@ -8,6 +8,7 @@
#include "base/debug/activity_tracker.h"
#include "base/debug/alias.h"
+#include "base/memory/ptr_util.h"
#include "base/no_destructor.h"
#include "base/pending_task.h"
#include "base/threading/thread_local.h"
@@ -19,19 +20,36 @@ namespace {
TaskAnnotator::ObserverForTesting* g_task_annotator_observer = nullptr;
+// Information about the context in which a PendingTask is currently being
+// executed.
+struct TaskAnnotatorThreadInfo {
+ // The pending task currently being executed.
+ const PendingTask* pending_task = nullptr;
+ // The pending task that was being executed when the |ipc_program_counter|
+ // was set. This is used to detect a nested message loop, in which case the
+ // global IPC decoration should not be applied.
+ const PendingTask* ipc_message_handler_task = nullptr;
+ // The program counter of the currently executing IPC message handler, if
+ // there is one.
+ const void* ipc_program_counter = nullptr;
+};
+
// Returns the TLS slot that stores the PendingTask currently in progress on
// each thread. Used to allow creating a breadcrumb of program counters on the
// stack to help identify a task's origin in crashes.
-ThreadLocalPointer<const PendingTask>* GetTLSForCurrentPendingTask() {
- static NoDestructor<ThreadLocalPointer<const PendingTask>>
- tls_for_current_pending_task;
- return tls_for_current_pending_task.get();
+TaskAnnotatorThreadInfo* GetTLSForCurrentPendingTask() {
+ static NoDestructor<ThreadLocalOwnedPointer<TaskAnnotatorThreadInfo>>
+ instance;
+ if (!instance->Get())
+ instance->Set(WrapUnique(new TaskAnnotatorThreadInfo));
+ auto* tls_info = instance->Get();
+ return tls_info;
}
} // namespace
const PendingTask* TaskAnnotator::CurrentTaskForThread() {
- return GetTLSForCurrentPendingTask()->Get();
+ return GetTLSForCurrentPendingTask()->pending_task;
}
TaskAnnotator::TaskAnnotator() = default;
@@ -55,9 +73,21 @@ void TaskAnnotator::WillQueueTask(const char* trace_event_name,
if (pending_task->task_backtrace[0])
return;
- const PendingTask* parent_task = GetTLSForCurrentPendingTask()->Get();
+ // Inherit the currently executing IPC handler context only if not in a nested
+ // message loop.
+ const auto* tls_info = GetTLSForCurrentPendingTask();
+ if (tls_info->ipc_message_handler_task == tls_info->pending_task)
+ pending_task->ipc_program_counter = tls_info->ipc_program_counter;
+
+ const auto* parent_task = tls_info->pending_task;
if (!parent_task)
return;
+
+ // If an IPC message handler context wasn't explicitly set, then inherit the
+ // context from the parent task.
+ if (!pending_task->ipc_program_counter)
+ pending_task->ipc_program_counter = parent_task->ipc_program_counter;
+
pending_task->task_backtrace[0] = parent_task->posted_from.program_counter();
std::copy(parent_task->task_backtrace.begin(),
parent_task->task_backtrace.end() - 1,
@@ -78,17 +108,21 @@ void TaskAnnotator::RunTask(const char* trace_event_name,
TRACE_DISABLED_BY_DEFAULT("toplevel.flow"), trace_event_name,
TRACE_ID_MANGLE(GetTaskTraceID(*pending_task)), TRACE_EVENT_FLAG_FLOW_IN);
- // Before running the task, store the task backtrace with the chain of
- // PostTasks that resulted in this call and deliberately alias it to ensure
- // it is on the stack if the task crashes. Be careful not to assume that the
- // variable itself will have the expected value when displayed by the
+ // Before running the task, store the IPC context and the task backtrace with
+ // the chain of PostTasks that resulted in this call and deliberately alias it
+ // to ensure it is on the stack if the task crashes. Be careful not to assume
+ // that the variable itself will have the expected value when displayed by the
// optimizer in an optimized build. Look at a memory dump of the stack.
static constexpr int kStackTaskTraceSnapshotSize =
- PendingTask::kTaskBacktraceLength + 3;
+ PendingTask::kTaskBacktraceLength + 4;
std::array<const void*, kStackTaskTraceSnapshotSize> task_backtrace;
// Store a marker to locate |task_backtrace| content easily on a memory
- // dump.
+ // dump. The layout is as follows:
+ //
+ // +------------ +----+---------+-----+-----------+--------+-------------+
+ // | Head Marker | PC | frame 0 | ... | frame N-1 | IPC PC | Tail Marker |
+ // +------------ +----+---------+-----+-----------+--------+-------------+
//
// Markers glossary (compliments of wez):
// cool code,do it dude!
@@ -101,19 +135,19 @@ void TaskAnnotator::RunTask(const char* trace_event_name,
task_backtrace[1] = pending_task->posted_from.program_counter();
std::copy(pending_task->task_backtrace.begin(),
pending_task->task_backtrace.end(), task_backtrace.begin() + 2);
+ task_backtrace[kStackTaskTraceSnapshotSize - 2] =
+ pending_task->ipc_program_counter;
debug::Alias(&task_backtrace);
- ThreadLocalPointer<const PendingTask>* tls_for_current_pending_task =
- GetTLSForCurrentPendingTask();
- const PendingTask* previous_pending_task =
- tls_for_current_pending_task->Get();
- tls_for_current_pending_task->Set(pending_task);
+ auto* tls_info = GetTLSForCurrentPendingTask();
+ const auto* previous_pending_task = tls_info->pending_task;
+ tls_info->pending_task = pending_task;
if (g_task_annotator_observer)
g_task_annotator_observer->BeforeRunTask(pending_task);
std::move(pending_task->task).Run();
- tls_for_current_pending_task->Set(previous_pending_task);
+ tls_info->pending_task = previous_pending_task;
}
uint64_t TaskAnnotator::GetTaskTraceID(const PendingTask& task) const {
@@ -133,4 +167,19 @@ void TaskAnnotator::ClearObserverForTesting() {
g_task_annotator_observer = nullptr;
}
+TaskAnnotator::ScopedSetIpcProgramCounter::ScopedSetIpcProgramCounter(
+ const void* program_counter) {
+ auto* tls_info = GetTLSForCurrentPendingTask();
+ old_ipc_message_handler_task_ = tls_info->ipc_message_handler_task;
+ old_ipc_program_counter_ = tls_info->ipc_program_counter;
+ tls_info->ipc_message_handler_task = tls_info->pending_task;
+ tls_info->ipc_program_counter = program_counter;
+}
+
+TaskAnnotator::ScopedSetIpcProgramCounter::~ScopedSetIpcProgramCounter() {
+ auto* tls_info = GetTLSForCurrentPendingTask();
+ tls_info->ipc_message_handler_task = old_ipc_message_handler_task_;
+ tls_info->ipc_program_counter = old_ipc_program_counter_;
+}
+
} // namespace base
diff --git a/base/task/common/task_annotator.h b/base/task/common/task_annotator.h
index 4a19cdfd00..654ce984a4 100644
--- a/base/task/common/task_annotator.h
+++ b/base/task/common/task_annotator.h
@@ -14,7 +14,8 @@ namespace base {
struct PendingTask;
// Implements common debug annotations for posted tasks. This includes data
-// such as task origins, queueing durations and memory usage.
+// such as task origins, IPC message contexts, queueing durations and memory
+// usage.
class BASE_EXPORT TaskAnnotator {
public:
class ObserverForTesting {
@@ -24,6 +25,10 @@ class BASE_EXPORT TaskAnnotator {
virtual void BeforeRunTask(const PendingTask* pending_task) = 0;
};
+ // This is used to set the |ipc_program_counter| field for PendingTasks. It is
+ // intended to be used only from within generated IPC handler dispatch code.
+ class ScopedSetIpcProgramCounter;
+
static const PendingTask* CurrentTaskForThread();
TaskAnnotator();
@@ -59,6 +64,18 @@ class BASE_EXPORT TaskAnnotator {
DISALLOW_COPY_AND_ASSIGN(TaskAnnotator);
};
+class BASE_EXPORT TaskAnnotator::ScopedSetIpcProgramCounter {
+ public:
+ explicit ScopedSetIpcProgramCounter(const void* program_counter);
+ ~ScopedSetIpcProgramCounter();
+
+ private:
+ const PendingTask* old_ipc_message_handler_task_ = nullptr;
+ const void* old_ipc_program_counter_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedSetIpcProgramCounter);
+};
+
} // namespace base
#endif // BASE_TASK_COMMON_TASK_ANNOTATOR_H_
diff --git a/base/task/common/task_annotator_unittest.cc b/base/task/common/task_annotator_unittest.cc
index 901ab54ec4..b2b6440951 100644
--- a/base/task/common/task_annotator_unittest.cc
+++ b/base/task/common/task_annotator_unittest.cc
@@ -17,6 +17,7 @@
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "base/task/post_task.h"
+#include "base/test/bind_test_util.h"
#include "base/test/scoped_task_environment.h"
#include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -61,6 +62,7 @@ class TaskAnnotatorBacktraceIntegrationTest
AutoLock auto_lock(on_before_run_task_lock_);
last_posted_from_ = pending_task->posted_from;
last_task_backtrace_ = pending_task->task_backtrace;
+ last_ipc_pc_ = pending_task->ipc_program_counter;
}
void SetUp() override { TaskAnnotator::RegisterObserverForTesting(this); }
@@ -71,6 +73,7 @@ class TaskAnnotatorBacktraceIntegrationTest
const Location& posted_from,
const Location& next_from_here,
const ExpectedTrace& expected_trace,
+ const void* expected_ipc_pc,
OnceClosure task) {
SCOPED_TRACE(StringPrintf("Callback Depth: %zu", expected_trace.size()));
@@ -82,10 +85,24 @@ class TaskAnnotatorBacktraceIntegrationTest
else
EXPECT_EQ(nullptr, last_task_backtrace_[i]);
}
+ EXPECT_EQ(expected_ipc_pc, last_ipc_pc_);
task_runner->PostTask(next_from_here, std::move(task));
}
+ void VerifyTraceAndPostWithIpcContext(
+ const scoped_refptr<SequencedTaskRunner>& task_runner,
+ const Location& posted_from,
+ const Location& next_from_here,
+ const ExpectedTrace& expected_trace,
+ const void* expected_ipc_pc,
+ OnceClosure task,
+ const void* new_ipc_pc) {
+ TaskAnnotator::ScopedSetIpcProgramCounter scoped_ipc_pc(new_ipc_pc);
+ VerifyTraceAndPost(task_runner, posted_from, next_from_here, expected_trace,
+ expected_ipc_pc, std::move(task));
+ }
+
// Same as VerifyTraceAndPost() with the exception that it also posts a task
// that will prevent |task| from running until |wait_before_next_task| is
// signaled.
@@ -94,6 +111,7 @@ class TaskAnnotatorBacktraceIntegrationTest
const Location& posted_from,
const Location& next_from_here,
const ExpectedTrace& expected_trace,
+ const void* expected_ipc_pc,
OnceClosure task,
WaitableEvent* wait_before_next_task) {
DCHECK(wait_before_next_task);
@@ -107,7 +125,7 @@ class TaskAnnotatorBacktraceIntegrationTest
FROM_HERE,
BindOnce(&WaitableEvent::Wait, Unretained(wait_before_next_task)));
VerifyTraceAndPost(task_runner, posted_from, next_from_here, expected_trace,
- std::move(task));
+ expected_ipc_pc, std::move(task));
}
protected:
@@ -128,12 +146,15 @@ class TaskAnnotatorBacktraceIntegrationTest
std::array<const void*, PendingTask::kTaskBacktraceLength>
last_task_backtrace_ = {};
+ const void* last_ipc_pc_ = nullptr;
+
DISALLOW_COPY_AND_ASSIGN(TaskAnnotatorBacktraceIntegrationTest);
};
// Ensure the task backtrace populates correctly.
TEST_F(TaskAnnotatorBacktraceIntegrationTest, SingleThreadedSimple) {
test::ScopedTaskEnvironment scoped_task_environment;
+ const void* dummy_ipc_pc = &dummy_ipc_pc;
const Location location0 = FROM_HERE;
const Location location1 = FROM_HERE;
const Location location2 = FROM_HERE;
@@ -143,6 +164,9 @@ TEST_F(TaskAnnotatorBacktraceIntegrationTest, SingleThreadedSimple) {
RunLoop run_loop;
+ // Task 0 executes with no IPC context. Task 1 executes under an explicitly
+ // set IPC context, and tasks 2-5 inherit that context.
+
// Task 5 has tasks 4/3/2/1 as parents (task 0 isn't visible as only the
// last 4 parents are kept).
OnceClosure task5 = BindOnce(
@@ -150,7 +174,7 @@ TEST_F(TaskAnnotatorBacktraceIntegrationTest, SingleThreadedSimple) {
Unretained(this), ThreadTaskRunnerHandle::Get(), location5, FROM_HERE,
ExpectedTrace({location4.program_counter(), location3.program_counter(),
location2.program_counter(), location1.program_counter()}),
- run_loop.QuitClosure());
+ dummy_ipc_pc, run_loop.QuitClosure());
// Task i=4/3/2/1/0 have tasks [0,i) as parents.
OnceClosure task4 = BindOnce(
@@ -158,26 +182,27 @@ TEST_F(TaskAnnotatorBacktraceIntegrationTest, SingleThreadedSimple) {
Unretained(this), ThreadTaskRunnerHandle::Get(), location4, location5,
ExpectedTrace({location3.program_counter(), location2.program_counter(),
location1.program_counter(), location0.program_counter()}),
- std::move(task5));
+ dummy_ipc_pc, std::move(task5));
OnceClosure task3 = BindOnce(
&TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
Unretained(this), ThreadTaskRunnerHandle::Get(), location3, location4,
ExpectedTrace({location2.program_counter(), location1.program_counter(),
location0.program_counter()}),
- std::move(task4));
+ dummy_ipc_pc, std::move(task4));
OnceClosure task2 = BindOnce(
&TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
Unretained(this), ThreadTaskRunnerHandle::Get(), location2, location3,
ExpectedTrace({location1.program_counter(), location0.program_counter()}),
- std::move(task3));
+ dummy_ipc_pc, std::move(task3));
OnceClosure task1 = BindOnce(
- &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
+ &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPostWithIpcContext,
Unretained(this), ThreadTaskRunnerHandle::Get(), location1, location2,
- ExpectedTrace({location0.program_counter()}), std::move(task2));
+ ExpectedTrace({location0.program_counter()}), nullptr, std::move(task2),
+ dummy_ipc_pc);
OnceClosure task0 =
BindOnce(&TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
Unretained(this), ThreadTaskRunnerHandle::Get(), location0,
- location1, ExpectedTrace({}), std::move(task1));
+ location1, ExpectedTrace({}), nullptr, std::move(task1));
ThreadTaskRunnerHandle::Get()->PostTask(location0, std::move(task0));
@@ -224,6 +249,15 @@ TEST_F(TaskAnnotatorBacktraceIntegrationTest, MultipleThreads) {
// \ \ /
// C: Wait........ TC0 /
+ // IPC contexts:
+ // TA0 and TA1 execute with no IPC context.
+ // TB0L is the first task to execute with an explicit IPC context.
+ // TB0F inherits no context.
+ // TC0 is posted with a new IPC context from TB0L.
+ // TA2 inherits that IPC context.
+ const void* dummy_ipc_pc0 = &dummy_ipc_pc0;
+ const void* dummy_ipc_pc1 = &dummy_ipc_pc1;
+
// On task runner c, post a task back to main thread that verifies its trace
// and terminates after one more self-post.
OnceClosure task_a2 = BindOnce(
@@ -232,14 +266,14 @@ TEST_F(TaskAnnotatorBacktraceIntegrationTest, MultipleThreads) {
ExpectedTrace(
{location_c0.program_counter(), location_b0.program_counter(),
location_a1.program_counter(), location_a0.program_counter()}),
- run_loop.QuitClosure());
- OnceClosure task_c0 =
- BindOnce(&TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
- Unretained(this), main_thread_a, location_c0, location_a2,
- ExpectedTrace({location_b0.program_counter(),
- location_a1.program_counter(),
- location_a0.program_counter()}),
- std::move(task_a2));
+ dummy_ipc_pc1, run_loop.QuitClosure());
+ OnceClosure task_c0 = BindOnce(
+ &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPostWithIpcContext,
+ Unretained(this), main_thread_a, location_c0, location_a2,
+ ExpectedTrace({location_b0.program_counter(),
+ location_a1.program_counter(),
+ location_a0.program_counter()}),
+ nullptr, std::move(task_a2), dummy_ipc_pc1);
// On task runner b run two tasks that conceptually come from the same
// location (managed via RunTwo().) One will post back to task runner b and
@@ -251,24 +285,25 @@ TEST_F(TaskAnnotatorBacktraceIntegrationTest, MultipleThreads) {
Unretained(this), task_runner_c, location_b0, location_c0,
ExpectedTrace(
{location_a1.program_counter(), location_a0.program_counter()}),
- std::move(task_c0), &lock_step);
- OnceClosure task_b0_local =
- BindOnce(&TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
- Unretained(this), task_runner_b, location_b0, location_b1,
- ExpectedTrace({location_a1.program_counter(),
- location_a0.program_counter()}),
- BindOnce(&WaitableEvent::Signal, Unretained(&lock_step)));
+ nullptr, std::move(task_c0), &lock_step);
+ OnceClosure task_b0_local = BindOnce(
+ &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPostWithIpcContext,
+ Unretained(this), task_runner_b, location_b0, location_b1,
+ ExpectedTrace(
+ {location_a1.program_counter(), location_a0.program_counter()}),
+ nullptr, BindOnce(&WaitableEvent::Signal, Unretained(&lock_step)),
+ dummy_ipc_pc0);
OnceClosure task_a1 =
BindOnce(&TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
Unretained(this), task_runner_b, location_a1, location_b0,
- ExpectedTrace({location_a0.program_counter()}),
+ ExpectedTrace({location_a0.program_counter()}), nullptr,
BindOnce(&TaskAnnotatorBacktraceIntegrationTest::RunTwo,
std::move(task_b0_local), std::move(task_b0_fork)));
OnceClosure task_a0 =
BindOnce(&TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
Unretained(this), main_thread_a, location_a0, location_a1,
- ExpectedTrace({}), std::move(task_a1));
+ ExpectedTrace({}), nullptr, std::move(task_a1));
main_thread_a->PostTask(location_a0, std::move(task_a0));
@@ -278,6 +313,9 @@ TEST_F(TaskAnnotatorBacktraceIntegrationTest, MultipleThreads) {
// Ensure nesting doesn't break the chain.
TEST_F(TaskAnnotatorBacktraceIntegrationTest, SingleThreadedNested) {
test::ScopedTaskEnvironment scoped_task_environment;
+ const void* dummy_ipc_pc = &dummy_ipc_pc;
+ const void* dummy_ipc_pc1 = &dummy_ipc_pc1;
+ const void* dummy_ipc_pc2 = &dummy_ipc_pc2;
const Location location0 = FROM_HERE;
const Location location1 = FROM_HERE;
const Location location2 = FROM_HERE;
@@ -307,6 +345,10 @@ TEST_F(TaskAnnotatorBacktraceIntegrationTest, SingleThreadedNested) {
// tls_for_current_pending_task->Set(nullptr);
// at the end of TaskAnnotator::RunTask() makes this test fail.
+ // This test also validates the IPC contexts are propagated appropriately, and
+ // then a context in an outer loop does not color tasks posted from a nested
+ // loop.
+
RunLoop nested_run_loop1(RunLoop::Type::kNestableTasksAllowed);
// Expectations are the same as in SingleThreadedSimple test despite the
@@ -317,19 +359,19 @@ TEST_F(TaskAnnotatorBacktraceIntegrationTest, SingleThreadedNested) {
Unretained(this), ThreadTaskRunnerHandle::Get(), location5, FROM_HERE,
ExpectedTrace({location4.program_counter(), location3.program_counter(),
location2.program_counter(), location1.program_counter()}),
- run_loop.QuitClosure());
+ dummy_ipc_pc, run_loop.QuitClosure());
OnceClosure task4 = BindOnce(
&TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
Unretained(this), ThreadTaskRunnerHandle::Get(), location4, location5,
ExpectedTrace({location3.program_counter(), location2.program_counter(),
location1.program_counter(), location0.program_counter()}),
- std::move(task5));
+ dummy_ipc_pc, std::move(task5));
OnceClosure task3 = BindOnce(
&TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
Unretained(this), ThreadTaskRunnerHandle::Get(), location3, location4,
ExpectedTrace({location2.program_counter(), location1.program_counter(),
location0.program_counter()}),
- std::move(task4));
+ dummy_ipc_pc, std::move(task4));
OnceClosure run_task_3_then_quit_nested_loop1 =
BindOnce(&TaskAnnotatorBacktraceIntegrationTest::RunTwo, std::move(task3),
@@ -339,29 +381,41 @@ TEST_F(TaskAnnotatorBacktraceIntegrationTest, SingleThreadedNested) {
&TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
Unretained(this), ThreadTaskRunnerHandle::Get(), location2, location3,
ExpectedTrace({location1.program_counter(), location0.program_counter()}),
- std::move(run_task_3_then_quit_nested_loop1));
+ dummy_ipc_pc, std::move(run_task_3_then_quit_nested_loop1));
// Task 1 is custom. It enters another nested RunLoop, has it do work and exit
// before posting the next task. This confirms that |task1| is restored as the
// current task before posting |task2| after returning from the nested loop.
RunLoop nested_run_loop2(RunLoop::Type::kNestableTasksAllowed);
OnceClosure task1 = BindOnce(
- [](RunLoop* nested_run_loop, const Location& location2,
- OnceClosure task2) {
- ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, DoNothing());
- nested_run_loop->RunUntilIdle();
+ BindLambdaForTesting([dummy_ipc_pc1](RunLoop* nested_run_loop,
+ const Location& location2,
+ OnceClosure task2) {
+ {
+ // Run the nested message loop with an explicitly set IPC context.
+ // This context should not leak out of the inner loop and color the
+ // tasks in the outer loop.
+ TaskAnnotator::ScopedSetIpcProgramCounter scoped_ipc_pc(
+ dummy_ipc_pc1);
+ ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, DoNothing());
+ nested_run_loop->RunUntilIdle();
+ }
ThreadTaskRunnerHandle::Get()->PostTask(location2, std::move(task2));
- },
+ }),
Unretained(&nested_run_loop2), location2, std::move(task2));
- OnceClosure task0 =
- BindOnce(&TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPost,
- Unretained(this), ThreadTaskRunnerHandle::Get(), location0,
- location1, ExpectedTrace({}), std::move(task1));
+ OnceClosure task0 = BindOnce(
+ &TaskAnnotatorBacktraceIntegrationTest::VerifyTraceAndPostWithIpcContext,
+ Unretained(this), ThreadTaskRunnerHandle::Get(), location0, location1,
+ ExpectedTrace({}), nullptr, std::move(task1), dummy_ipc_pc);
ThreadTaskRunnerHandle::Get()->PostTask(location0, std::move(task0));
- ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, BindOnce(&RunLoop::Run, Unretained(&nested_run_loop1)));
+
+ {
+ TaskAnnotator::ScopedSetIpcProgramCounter scoped_ipc_pc(dummy_ipc_pc2);
+ ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, BindOnce(&RunLoop::Run, Unretained(&nested_run_loop1)));
+ }
run_loop.Run();
}