diff --git a/test/time_controller/simulated_thread.cc b/test/time_controller/simulated_thread.cc index 8d82ebd604..937fe3207e 100644 --- a/test/time_controller/simulated_thread.cc +++ b/test/time_controller/simulated_thread.cc @@ -81,8 +81,11 @@ void SimulatedThread::Send(const rtc::Location& posted_from, if (IsCurrent()) { msg.phandler->OnMessage(&msg); } else { + TaskQueueBase* yielding_from = TaskQueueBase::Current(); + handler_->StartYield(yielding_from); CurrentThreadSetter set_current(this); msg.phandler->OnMessage(&msg); + handler_->StopYield(yielding_from); } } diff --git a/test/time_controller/simulated_time_controller.cc b/test/time_controller/simulated_time_controller.cc index d3bc66a6e8..a81083b4fb 100644 --- a/test/time_controller/simulated_time_controller.cc +++ b/test/time_controller/simulated_time_controller.cc @@ -160,6 +160,15 @@ void SimulatedTimeControllerImpl::Unregister(SimulatedSequenceRunner* runner) { RTC_CHECK(removed); RemoveByValue(&ready_runners_, runner); } + +void SimulatedTimeControllerImpl::StartYield(TaskQueueBase* yielding_from) { + auto inserted = yielded_.insert(yielding_from); + RTC_DCHECK(inserted.second); +} + +void SimulatedTimeControllerImpl::StopYield(TaskQueueBase* yielding_from) { + yielded_.erase(yielding_from); +} } // namespace sim_time_impl GlobalSimulatedTimeController::GlobalSimulatedTimeController( diff --git a/test/time_controller/simulated_time_controller.h b/test/time_controller/simulated_time_controller.h index 783edb25d7..758f90989e 100644 --- a/test/time_controller/simulated_time_controller.h +++ b/test/time_controller/simulated_time_controller.h @@ -79,6 +79,11 @@ class SimulatedTimeControllerImpl : public TaskQueueFactory, // Removes |runner| from |runners_|. void Unregister(SimulatedSequenceRunner* runner); + // Indicates that |yielding_from| is not ready to run. + void StartYield(TaskQueueBase* yielding_from); + // Indicates that processing can be continued on |yielding_from|. + void StopYield(TaskQueueBase* yielding_from); + private: const rtc::PlatformThreadId thread_id_; const std::unique_ptr dummy_thread_ = rtc::Thread::Create(); diff --git a/test/time_controller/simulated_time_controller_unittest.cc b/test/time_controller/simulated_time_controller_unittest.cc index 469d2d7482..2fe4bd2df2 100644 --- a/test/time_controller/simulated_time_controller_unittest.cc +++ b/test/time_controller/simulated_time_controller_unittest.cc @@ -18,6 +18,8 @@ #include "test/gmock.h" #include "test/gtest.h" +#include "rtc_base/event.h" + // NOTE: Since these tests rely on real time behavior, they will be flaky // if run on heavily loaded systems. namespace webrtc { @@ -124,4 +126,27 @@ TEST(SimulatedTimeControllerTest, DelayTaskRunOnTime) { time_simulation.AdvanceTime(TimeDelta::ms(10)); EXPECT_TRUE(delay_task_executed); } + +TEST(SimulatedTimeControllerTest, ThreadYeildsOnInvoke) { + GlobalSimulatedTimeController sim(kStartTime); + auto main_thread = sim.GetMainThread(); + auto t2 = sim.CreateThread("thread", nullptr); + bool task_has_run = false; + // Posting a task to the main thread, this should not run until AdvanceTime is + // called. + main_thread->PostTask(RTC_FROM_HERE, [&] { task_has_run = true; }); + t2->Invoke(RTC_FROM_HERE, [] { + rtc::Event yield_event; + // Wait() triggers YieldExecution() which will runs message processing on + // all threads that are not in the yielded set. + + yield_event.Wait(0); + }); + // Since we are doing an invoke from the main thread, we don't expect the main + // thread message loop to be processed. + EXPECT_FALSE(task_has_run); + sim.AdvanceTime(TimeDelta::seconds(1)); + ASSERT_TRUE(task_has_run); +} + } // namespace webrtc