Introduce new interface for TaskQueueBase using absl::AnyInvocable

Bug: webrtc:14245
Change-Id: Ie4f47ea9753d6644aec2e95f531b521cc119a6c8
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/267402
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#37439}
This commit is contained in:
Danil Chapovalov
2022-07-05 11:01:27 +02:00
committed by WebRTC LUCI CQ
parent 4f1af1156f
commit 8feb6fd1e9
4 changed files with 176 additions and 71 deletions

View File

@ -9,9 +9,11 @@
*/
#include "api/task_queue/task_queue_test.h"
#include "absl/memory/memory.h"
#include <memory>
#include "absl/cleanup/cleanup.h"
#include "absl/strings/string_view.h"
#include "api/task_queue/to_queued_task.h"
#include "api/units/time_delta.h"
#include "rtc_base/event.h"
#include "rtc_base/ref_counter.h"
#include "rtc_base/time_utils.h"
@ -43,10 +45,10 @@ TEST_P(TaskQueueTest, PostAndCheckCurrent) {
// means that TaskQueueBase::Current() will still return a valid value.
EXPECT_FALSE(queue->IsCurrent());
queue->PostTask(ToQueuedTask([&event, &queue] {
queue->PostTask([&event, &queue] {
EXPECT_TRUE(queue->IsCurrent());
event.Set();
}));
});
EXPECT_TRUE(event.Wait(1000));
}
@ -55,20 +57,17 @@ TEST_P(TaskQueueTest, PostCustomTask) {
rtc::Event ran;
auto queue = CreateTaskQueue(factory, "PostCustomImplementation");
class CustomTask : public QueuedTask {
class CustomTask {
public:
explicit CustomTask(rtc::Event* ran) : ran_(ran) {}
private:
bool Run() override {
ran_->Set();
return false; // Do not allow the task to be deleted by the queue.
}
void operator()() { ran_->Set(); }
private:
rtc::Event* const ran_;
} my_task(&ran);
queue->PostTask(absl::WrapUnique(&my_task));
queue->PostTask(my_task);
EXPECT_TRUE(ran.Wait(1000));
}
@ -77,7 +76,7 @@ TEST_P(TaskQueueTest, PostDelayedZero) {
rtc::Event event;
auto queue = CreateTaskQueue(factory, "PostDelayedZero");
queue->PostDelayedTask(ToQueuedTask([&event] { event.Set(); }), 0);
queue->PostDelayedTask([&event] { event.Set(); }, TimeDelta::Zero());
EXPECT_TRUE(event.Wait(1000));
}
@ -86,9 +85,8 @@ TEST_P(TaskQueueTest, PostFromQueue) {
rtc::Event event;
auto queue = CreateTaskQueue(factory, "PostFromQueue");
queue->PostTask(ToQueuedTask([&event, &queue] {
queue->PostTask(ToQueuedTask([&event] { event.Set(); }));
}));
queue->PostTask(
[&event, &queue] { queue->PostTask([&event] { event.Set(); }); });
EXPECT_TRUE(event.Wait(1000));
}
@ -99,11 +97,12 @@ TEST_P(TaskQueueTest, PostDelayed) {
CreateTaskQueue(factory, "PostDelayed", TaskQueueFactory::Priority::HIGH);
int64_t start = rtc::TimeMillis();
queue->PostDelayedTask(ToQueuedTask([&event, &queue] {
EXPECT_TRUE(queue->IsCurrent());
event.Set();
}),
100);
queue->PostDelayedTask(
[&event, &queue] {
EXPECT_TRUE(queue->IsCurrent());
event.Set();
},
TimeDelta::Millis(100));
EXPECT_TRUE(event.Wait(1000));
int64_t end = rtc::TimeMillis();
// These tests are a little relaxed due to how "powerful" our test bots can
@ -120,11 +119,12 @@ TEST_P(TaskQueueTest, PostMultipleDelayed) {
std::vector<rtc::Event> events(100);
for (int i = 0; i < 100; ++i) {
rtc::Event* event = &events[i];
queue->PostDelayedTask(ToQueuedTask([event, &queue] {
EXPECT_TRUE(queue->IsCurrent());
event->Set();
}),
i);
queue->PostDelayedTask(
[event, &queue] {
EXPECT_TRUE(queue->IsCurrent());
event->Set();
},
TimeDelta::Millis(i));
}
for (rtc::Event& e : events)
@ -136,8 +136,9 @@ TEST_P(TaskQueueTest, PostDelayedAfterDestruct) {
rtc::Event run;
rtc::Event deleted;
auto queue = CreateTaskQueue(factory, "PostDelayedAfterDestruct");
queue->PostDelayedTask(
ToQueuedTask([&run] { run.Set(); }, [&deleted] { deleted.Set(); }), 100);
absl::Cleanup cleanup = [&deleted] { deleted.Set(); };
queue->PostDelayedTask([&run, cleanup = std::move(cleanup)] { run.Set(); },
TimeDelta::Millis(100));
// Destroy the queue.
queue = nullptr;
// Task might outlive the TaskQueue, but still should be deleted.
@ -153,38 +154,33 @@ TEST_P(TaskQueueTest, PostAndReuse) {
int call_count = 0;
class ReusedTask : public QueuedTask {
class ReusedTask {
public:
ReusedTask(int* counter, TaskQueueBase* reply_queue, rtc::Event* event)
: counter_(*counter), reply_queue_(reply_queue), event_(*event) {
EXPECT_EQ(counter_, 0);
}
ReusedTask(ReusedTask&&) = default;
ReusedTask& operator=(ReusedTask&&) = delete;
private:
bool Run() override {
void operator()() && {
if (++counter_ == 1) {
reply_queue_->PostTask(absl::WrapUnique(this));
// At this point, the object is owned by reply_queue_ and it's
// theoratically possible that the object has been deleted (e.g. if
// posting wasn't possible). So, don't touch any member variables here.
// Indicate to the current queue that ownership has been transferred.
return false;
reply_queue_->PostTask(std::move(*this));
// At this point, the object is in the moved-from state.
} else {
EXPECT_EQ(counter_, 2);
EXPECT_TRUE(reply_queue_->IsCurrent());
event_.Set();
return true; // Indicate that the object should be deleted.
}
}
private:
int& counter_;
TaskQueueBase* const reply_queue_;
rtc::Event& event_;
};
auto task =
std::make_unique<ReusedTask>(&call_count, reply_queue.get(), &event);
ReusedTask task(&call_count, reply_queue.get(), &event);
post_queue->PostTask(std::move(task));
EXPECT_TRUE(event.Wait(1000));
}
@ -215,16 +211,18 @@ TEST_P(TaskQueueTest, PostALot) {
int tasks_executed = 0;
auto task_queue = CreateTaskQueue(factory, "PostALot");
task_queue->PostTask(ToQueuedTask([&] {
task_queue->PostTask([&] {
// Post tasks from the queue to guarantee that the 1st task won't be
// executed before the last one is posted.
for (int i = 0; i < kTaskCount; ++i) {
task_queue->PostTask(ToQueuedTask(
[&] { ++tasks_executed; }, [&] { all_destroyed.DecrementCount(); }));
absl::Cleanup cleanup = [&] { all_destroyed.DecrementCount(); };
task_queue->PostTask([&tasks_executed, cleanup = std::move(cleanup)] {
++tasks_executed;
});
}
posting_done.Set();
}));
});
// Before destroying the task queue wait until all child tasks are posted.
posting_done.Wait(rtc::Event::kForever);
@ -257,17 +255,17 @@ TEST_P(TaskQueueTest, PostTwoWithSharedUnprotectedState) {
auto queue = CreateTaskQueue(factory, "PostTwoWithSharedUnprotectedState");
rtc::Event done;
queue->PostTask(ToQueuedTask([&state, &queue, &done] {
queue->PostTask([&state, &queue, &done] {
// Post tasks from queue to guarantee, that 1st task won't be
// executed before the second one will be posted.
queue->PostTask(ToQueuedTask([&state] { state.state = 1; }));
queue->PostTask(ToQueuedTask([&state, &done] {
queue->PostTask([&state] { state.state = 1; });
queue->PostTask([&state, &done] {
EXPECT_EQ(state.state, 1);
done.Set();
}));
});
// Check, that state changing tasks didn't start yet.
EXPECT_EQ(state.state, 0);
}));
});
EXPECT_TRUE(done.Wait(1000));
}