Add test to verify TaskQueue memory access order.

Bug: webrtc:10138
Change-Id: I53e8a3a612ad44feced8d63a4035d79b7e0f22a9
Reviewed-on: https://webrtc-review.googlesource.com/c/120601
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Commit-Queue: Artem Titov <titovartem@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26497}
This commit is contained in:
Artem Titov
2019-01-31 13:31:09 +01:00
committed by Commit Bot
parent 5054f54457
commit 01f64e0eb2
2 changed files with 65 additions and 0 deletions

View File

@ -208,5 +208,37 @@ TEST_P(TaskQueueTest, PostALot) {
EXPECT_EQ(tasks_cleaned_up, kTaskCount); EXPECT_EQ(tasks_cleaned_up, kTaskCount);
} }
// Test posting two tasks that have shared state not protected by a
// lock. The TaskQueue should guarantee memory read-write order and
// FIFO task execution order, so the second task should always see the
// changes that were made by the first task.
//
// If the TaskQueue doesn't properly synchronize the execution of
// tasks, there will be a data race, which is undefined behavior. The
// EXPECT calls may randomly catch this, but to make the most of this
// unit test, run it under TSan or some other tool that is able to
// directly detect data races.
TEST_P(TaskQueueTest, PostTwoWithSharedUnprotectedState) {
struct SharedState {
// First task will set this value to 1 and second will assert it.
int state = 0;
} state;
auto queue = CreateTaskQueue(GetParam(), "PostTwoWithSharedUnprotectedState");
rtc::Event done;
queue->PostTask(rtc::NewClosure([&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(rtc::NewClosure([&state] { state.state = 1; }));
queue->PostTask(rtc::NewClosure([&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));
}
} // namespace } // namespace
} // namespace webrtc } // namespace webrtc

View File

@ -367,4 +367,37 @@ TEST(TaskQueueTest, PostALot) {
EXPECT_EQ(kTaskCount, tasks_cleaned_up); EXPECT_EQ(kTaskCount, tasks_cleaned_up);
} }
// Test posting two tasks that have shared state not protected by a
// lock. The TaskQueue should guarantee memory read-write order and
// FIFO task execution order, so the second task should always see the
// changes that were made by the first task.
//
// If the TaskQueue doesn't properly synchronize the execution of
// tasks, there will be a data race, which is undefined behavior. The
// EXPECT calls may randomly catch this, but to make the most of this
// unit test, run it under TSan or some other tool that is able to
// directly detect data races.
TEST(TaskQueueTest, PostTwoWithSharedUnprotectedState) {
static const char kQueueName[] = "PostTwoWithSharedUnprotectedState";
struct SharedState {
// First task will set this value to 1 and second will assert it.
int state = 0;
} state;
TaskQueue queue(kQueueName);
rtc::Event 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([&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));
}
} // namespace rtc } // namespace rtc