summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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();
}