From 771db1ae2264de322782d1829cc148bec8aaf475 Mon Sep 17 00:00:00 2001 From: Chris Hamilton Date: Thu, 25 Apr 2019 01:59:51 +0900 Subject: Add IPC handler program counter to PendingTask and TaskAnnotator. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Commit-Queue: Chris Hamilton Cr-Commit-Position: refs/heads/master@{#653621} CrOS-Libchrome-Original-Commit: 60dcc26b91b1d20e5bacc738db0ee60922024a8e --- base/pending_task.h | 10 +++ base/task/common/task_annotator.cc | 85 ++++++++++++++---- base/task/common/task_annotator.h | 19 +++- base/task/common/task_annotator_unittest.cc | 134 +++++++++++++++++++--------- 4 files changed, 189 insertions(+), 59 deletions(-) (limited to 'base') 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 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* GetTLSForCurrentPendingTask() { - static NoDestructor> - tls_for_current_pending_task; - return tls_for_current_pending_task.get(); +TaskAnnotatorThreadInfo* GetTLSForCurrentPendingTask() { + static NoDestructor> + 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 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* 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& 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 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(); } -- cgit v1.2.3