Add rtc::Thread::PostDelayedTask
Earlier, rtc::Thread::PostTask was added as a convenient
alternative to MessageHandlers. This CL additionally adds support
for posting delayed tasks in a similar manner.
Bug: webrtc:10294
Change-Id: I0957b59ca2133a882c980bd2ad109fa03d701a16
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/161740
Commit-Queue: Steve Anton <steveanton@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30069}
diff --git a/rtc_base/thread.cc b/rtc_base/thread.cc
index 90be695..7335af7 100644
--- a/rtc_base/thread.cc
+++ b/rtc_base/thread.cc
@@ -63,6 +63,24 @@
#endif
namespace rtc {
+namespace {
+
+class MessageHandlerWithTask final : public MessageHandler {
+ public:
+ MessageHandlerWithTask() = default;
+
+ void OnMessage(Message* msg) override {
+ static_cast<rtc_thread_internal::MessageLikeTask*>(msg->pdata)->Run();
+ delete msg->pdata;
+ }
+
+ private:
+ ~MessageHandlerWithTask() override {}
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(MessageHandlerWithTask);
+};
+
+} // namespace
ThreadManager* ThreadManager::Instance() {
static ThreadManager* const thread_manager = new ThreadManager();
@@ -612,6 +630,13 @@
#endif
}
+// static
+MessageHandler* Thread::GetPostTaskMessageHandler() {
+ // Allocate at first call, never deallocate.
+ static MessageHandler* handler = new MessageHandlerWithTask;
+ return handler;
+}
+
AutoThread::AutoThread()
: Thread(SocketServer::CreateDefault(), /*do_init=*/false) {
if (!ThreadManager::Instance()->CurrentThread()) {
diff --git a/rtc_base/thread.h b/rtc_base/thread.h
index f433bab..fb40a54 100644
--- a/rtc_base/thread.h
+++ b/rtc_base/thread.h
@@ -64,21 +64,6 @@
RTC_DISALLOW_COPY_AND_ASSIGN(MessageWithFunctor);
};
-class MessageHandlerWithTask final : public MessageHandler {
- public:
- MessageHandlerWithTask() = default;
-
- void OnMessage(Message* msg) override {
- static_cast<MessageLikeTask*>(msg->pdata)->Run();
- delete msg->pdata;
- }
-
- private:
- ~MessageHandlerWithTask() override {}
-
- RTC_DISALLOW_COPY_AND_ASSIGN(MessageHandlerWithTask);
-};
-
} // namespace rtc_thread_internal
class RTC_EXPORT ThreadManager {
@@ -267,13 +252,19 @@
// [&x, &y] { x.TrackComputations(y.Compute()); });
template <class FunctorT>
void PostTask(const Location& posted_from, FunctorT&& functor) {
- // Allocate at first call, never deallocate.
- static auto* const handler =
- new rtc_thread_internal::MessageHandlerWithTask;
- Post(posted_from, handler, 0,
+ Post(posted_from, GetPostTaskMessageHandler(), /*id=*/0,
new rtc_thread_internal::MessageWithFunctor<FunctorT>(
std::forward<FunctorT>(functor)));
}
+ template <class FunctorT>
+ void PostDelayedTask(const Location& posted_from,
+ FunctorT&& functor,
+ uint32_t milliseconds) {
+ PostDelayed(posted_from, milliseconds, GetPostTaskMessageHandler(),
+ /*id=*/0,
+ new rtc_thread_internal::MessageWithFunctor<FunctorT>(
+ std::forward<FunctorT>(functor)));
+ }
// From TaskQueueBase
void PostTask(std::unique_ptr<webrtc::QueuedTask> task) override;
@@ -347,6 +338,7 @@
public:
void OnMessage(Message* msg) override;
};
+
// Sets the per-thread allow-blocking-calls flag and returns the previous
// value. Must be called on this thread.
bool SetAllowBlockingCalls(bool allow);
@@ -381,6 +373,10 @@
void InvokeInternal(const Location& posted_from,
rtc::FunctionView<void()> functor);
+ // Returns a static-lifetime MessageHandler which runs message with
+ // MessageLikeTask payload data.
+ static MessageHandler* GetPostTaskMessageHandler();
+
std::list<_SendMessage> sendlist_;
std::string name_;
diff --git a/rtc_base/thread_unittest.cc b/rtc_base/thread_unittest.cc
index 8147c90..464f2d4 100644
--- a/rtc_base/thread_unittest.cc
+++ b/rtc_base/thread_unittest.cc
@@ -902,6 +902,48 @@
fourth.Wait(Event::kForever);
}
+TEST(ThreadPostDelayedTaskTest, 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->PostDelayedTask(
+ RTC_FROM_HERE,
+ Bind(&WaitAndSetEvent, &event_set_by_test_thread,
+ &event_set_by_background_thread),
+ /*milliseconds=*/10);
+ event_set_by_test_thread.Set();
+ event_set_by_background_thread.Wait(Event::kForever);
+}
+
+TEST(ThreadPostDelayedTaskTest, InvokesInDelayOrder) {
+ std::unique_ptr<rtc::Thread> background_thread(rtc::Thread::Create());
+ background_thread->Start();
+
+ Event first;
+ Event second;
+ Event third;
+ Event fourth;
+
+ background_thread->PostDelayedTask(RTC_FROM_HERE,
+ Bind(&WaitAndSetEvent, &third, &fourth),
+ /*milliseconds=*/11);
+ background_thread->PostDelayedTask(RTC_FROM_HERE,
+ Bind(&WaitAndSetEvent, &first, &second),
+ /*milliseconds=*/9);
+ background_thread->PostDelayedTask(RTC_FROM_HERE,
+ Bind(&WaitAndSetEvent, &second, &third),
+ /*milliseconds=*/10);
+
+ // 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);
+}
+
class ThreadFactory : public webrtc::TaskQueueFactory {
public:
std::unique_ptr<webrtc::TaskQueueBase, webrtc::TaskQueueDeleter>