rtc::Thread::PostTask() added.
This method allows asynchronously posting tasks, in the form of functors to be invoked, on the thread represented by rtc::Thread. This CL removes PostMessageWithFunctor(), putting the implementation of it directly into rtc::Thread::PostTask(), and moves & updates the test coverage to thread_unittest.cc. Bug: webrtc:10294, webrtc:10293 Change-Id: Ic6cc3e2533a4f7aaff141aff28e9bb3908ee3c96 Reviewed-on: https://webrtc-review.googlesource.com/c/124701 Reviewed-by: Karl Wiberg <kwiberg@webrtc.org> Commit-Queue: Henrik Boström <hbos@webrtc.org> Cr-Commit-Position: refs/heads/master@{#26894}
This commit is contained in:

committed by
Commit Bot

parent
8f385e39fa
commit
ba4dcc3ed8
@ -671,5 +671,230 @@ TEST_F(GuardedAsyncInvokeTest, FlushWithIds) {
|
||||
EXPECT_TRUE(flag2.get());
|
||||
}
|
||||
|
||||
void ThreadIsCurrent(Thread* thread, bool* result, Event* event) {
|
||||
*result = thread->IsCurrent();
|
||||
event->Set();
|
||||
}
|
||||
|
||||
void WaitAndSetEvent(Event* wait_event, Event* set_event) {
|
||||
wait_event->Wait(Event::kForever);
|
||||
set_event->Set();
|
||||
}
|
||||
|
||||
// A functor that keeps track of the number of copies and moves.
|
||||
class LifeCycleFunctor {
|
||||
public:
|
||||
struct Stats {
|
||||
size_t copy_count = 0;
|
||||
size_t move_count = 0;
|
||||
};
|
||||
|
||||
LifeCycleFunctor(Stats* stats, Event* event) : stats_(stats), event_(event) {}
|
||||
LifeCycleFunctor(const LifeCycleFunctor& other) { *this = other; }
|
||||
LifeCycleFunctor(LifeCycleFunctor&& other) { *this = std::move(other); }
|
||||
|
||||
LifeCycleFunctor& operator=(const LifeCycleFunctor& other) {
|
||||
stats_ = other.stats_;
|
||||
event_ = other.event_;
|
||||
++stats_->copy_count;
|
||||
return *this;
|
||||
}
|
||||
|
||||
LifeCycleFunctor& operator=(LifeCycleFunctor&& other) {
|
||||
stats_ = other.stats_;
|
||||
event_ = other.event_;
|
||||
++stats_->move_count;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void operator()() { event_->Set(); }
|
||||
|
||||
private:
|
||||
Stats* stats_;
|
||||
Event* event_;
|
||||
};
|
||||
|
||||
// A functor that verifies the thread it was destroyed on.
|
||||
class DestructionFunctor {
|
||||
public:
|
||||
DestructionFunctor(Thread* thread, bool* thread_was_current, Event* event)
|
||||
: thread_(thread),
|
||||
thread_was_current_(thread_was_current),
|
||||
event_(event) {}
|
||||
~DestructionFunctor() {
|
||||
// Only signal the event if this was the functor that was invoked to avoid
|
||||
// the event being signaled due to the destruction of temporary/moved
|
||||
// versions of this object.
|
||||
if (was_invoked_) {
|
||||
*thread_was_current_ = thread_->IsCurrent();
|
||||
event_->Set();
|
||||
}
|
||||
}
|
||||
|
||||
void operator()() { was_invoked_ = true; }
|
||||
|
||||
private:
|
||||
Thread* thread_;
|
||||
bool* thread_was_current_;
|
||||
Event* event_;
|
||||
bool was_invoked_ = false;
|
||||
};
|
||||
|
||||
TEST(ThreadPostTaskTest, InvokesWithBind) {
|
||||
std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create());
|
||||
background_thread->Start();
|
||||
|
||||
Event event;
|
||||
background_thread->PostTask(RTC_FROM_HERE, Bind(&Event::Set, &event));
|
||||
event.Wait(Event::kForever);
|
||||
}
|
||||
|
||||
TEST(ThreadPostTaskTest, InvokesWithLambda) {
|
||||
std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create());
|
||||
background_thread->Start();
|
||||
|
||||
Event event;
|
||||
background_thread->PostTask(RTC_FROM_HERE, [&event] { event.Set(); });
|
||||
event.Wait(Event::kForever);
|
||||
}
|
||||
|
||||
TEST(ThreadPostTaskTest, InvokesWithCopiedFunctor) {
|
||||
std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create());
|
||||
background_thread->Start();
|
||||
|
||||
LifeCycleFunctor::Stats stats;
|
||||
Event event;
|
||||
LifeCycleFunctor functor(&stats, &event);
|
||||
background_thread->PostTask(RTC_FROM_HERE, functor);
|
||||
event.Wait(Event::kForever);
|
||||
|
||||
EXPECT_EQ(1u, stats.copy_count);
|
||||
EXPECT_EQ(0u, stats.move_count);
|
||||
}
|
||||
|
||||
TEST(ThreadPostTaskTest, InvokesWithMovedFunctor) {
|
||||
std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create());
|
||||
background_thread->Start();
|
||||
|
||||
LifeCycleFunctor::Stats stats;
|
||||
Event event;
|
||||
LifeCycleFunctor functor(&stats, &event);
|
||||
background_thread->PostTask(RTC_FROM_HERE, std::move(functor));
|
||||
event.Wait(Event::kForever);
|
||||
|
||||
EXPECT_EQ(0u, stats.copy_count);
|
||||
EXPECT_EQ(1u, stats.move_count);
|
||||
}
|
||||
|
||||
TEST(ThreadPostTaskTest, InvokesWithReferencedFunctorShouldCopy) {
|
||||
std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create());
|
||||
background_thread->Start();
|
||||
|
||||
LifeCycleFunctor::Stats stats;
|
||||
Event event;
|
||||
LifeCycleFunctor functor(&stats, &event);
|
||||
LifeCycleFunctor& functor_ref = functor;
|
||||
background_thread->PostTask(RTC_FROM_HERE, functor_ref);
|
||||
event.Wait(Event::kForever);
|
||||
|
||||
EXPECT_EQ(1u, stats.copy_count);
|
||||
EXPECT_EQ(0u, stats.move_count);
|
||||
}
|
||||
|
||||
TEST(ThreadPostTaskTest, InvokesWithCopiedFunctorDestroyedOnTargetThread) {
|
||||
std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create());
|
||||
background_thread->Start();
|
||||
|
||||
Event event;
|
||||
bool was_invoked_on_background_thread = false;
|
||||
DestructionFunctor functor(background_thread.get(),
|
||||
&was_invoked_on_background_thread, &event);
|
||||
background_thread->PostTask(RTC_FROM_HERE, functor);
|
||||
event.Wait(Event::kForever);
|
||||
|
||||
EXPECT_TRUE(was_invoked_on_background_thread);
|
||||
}
|
||||
|
||||
TEST(ThreadPostTaskTest, InvokesWithMovedFunctorDestroyedOnTargetThread) {
|
||||
std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create());
|
||||
background_thread->Start();
|
||||
|
||||
Event event;
|
||||
bool was_invoked_on_background_thread = false;
|
||||
DestructionFunctor functor(background_thread.get(),
|
||||
&was_invoked_on_background_thread, &event);
|
||||
background_thread->PostTask(RTC_FROM_HERE, std::move(functor));
|
||||
event.Wait(Event::kForever);
|
||||
|
||||
EXPECT_TRUE(was_invoked_on_background_thread);
|
||||
}
|
||||
|
||||
TEST(ThreadPostTaskTest,
|
||||
InvokesWithReferencedFunctorShouldCopyAndDestroyedOnTargetThread) {
|
||||
std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create());
|
||||
background_thread->Start();
|
||||
|
||||
Event event;
|
||||
bool was_invoked_on_background_thread = false;
|
||||
DestructionFunctor functor(background_thread.get(),
|
||||
&was_invoked_on_background_thread, &event);
|
||||
DestructionFunctor& functor_ref = functor;
|
||||
background_thread->PostTask(RTC_FROM_HERE, functor_ref);
|
||||
event.Wait(Event::kForever);
|
||||
|
||||
EXPECT_TRUE(was_invoked_on_background_thread);
|
||||
}
|
||||
|
||||
TEST(ThreadPostTaskTest, InvokesOnBackgroundThread) {
|
||||
std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create());
|
||||
background_thread->Start();
|
||||
|
||||
Event event;
|
||||
bool was_invoked_on_background_thread = false;
|
||||
background_thread->PostTask(RTC_FROM_HERE,
|
||||
Bind(&ThreadIsCurrent, background_thread.get(),
|
||||
&was_invoked_on_background_thread, &event));
|
||||
event.Wait(Event::kForever);
|
||||
|
||||
EXPECT_TRUE(was_invoked_on_background_thread);
|
||||
}
|
||||
|
||||
TEST(ThreadPostTaskTest, InvokesAsynchronously) {
|
||||
std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create());
|
||||
background_thread->Start();
|
||||
|
||||
// The first event ensures that SendSingleMessage() is not blocking this
|
||||
// thread. The second event ensures that the message is processed.
|
||||
Event event_set_by_test_thread;
|
||||
Event event_set_by_background_thread;
|
||||
background_thread->PostTask(RTC_FROM_HERE,
|
||||
Bind(&WaitAndSetEvent, &event_set_by_test_thread,
|
||||
&event_set_by_background_thread));
|
||||
event_set_by_test_thread.Set();
|
||||
event_set_by_background_thread.Wait(Event::kForever);
|
||||
}
|
||||
|
||||
TEST(ThreadPostTaskTest, InvokesInPostedOrder) {
|
||||
std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create());
|
||||
background_thread->Start();
|
||||
|
||||
Event first;
|
||||
Event second;
|
||||
Event third;
|
||||
Event fourth;
|
||||
|
||||
background_thread->PostTask(RTC_FROM_HERE,
|
||||
Bind(&WaitAndSetEvent, &first, &second));
|
||||
background_thread->PostTask(RTC_FROM_HERE,
|
||||
Bind(&WaitAndSetEvent, &second, &third));
|
||||
background_thread->PostTask(RTC_FROM_HERE,
|
||||
Bind(&WaitAndSetEvent, &third, &fourth));
|
||||
|
||||
// All tasks have been posted before the first one is unblocked.
|
||||
first.Set();
|
||||
// Only if the chain is invoked in posted order will the last event be set.
|
||||
fourth.Wait(Event::kForever);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace rtc
|
||||
|
Reference in New Issue
Block a user