This source file includes following definitions.
- thread_sync_
- DeleteCurrentMessageLoop
- SetUp
- TearDown
- destruct_order_
- RecordRun
- RecordLoop
- RecordLoopAndQuit
- UnblockTaskThread
- BlockTaskThreadHelper
- TEST_F
- TEST_F
- TEST_F
- TEST_F
#include "base/message_loop/message_loop_proxy.h"
#include "base/atomic_sequence_num.h"
#include "base/bind.h"
#include "base/debug/leak_annotations.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
namespace {
class MessageLoopProxyTest : public testing::Test {
public:
MessageLoopProxyTest()
: current_loop_(new MessageLoop()),
task_thread_("task_thread"),
thread_sync_(true, false) {
}
void DeleteCurrentMessageLoop() {
current_loop_.reset();
}
protected:
virtual void SetUp() OVERRIDE {
task_thread_.Start();
task_thread_.message_loop()->PostTask(
FROM_HERE,
Bind(&MessageLoopProxyTest::BlockTaskThreadHelper, Unretained(this)));
}
virtual void TearDown() OVERRIDE {
thread_sync_.Signal();
task_thread_.Stop();
DeleteCurrentMessageLoop();
}
class LoopRecorder : public RefCountedThreadSafe<LoopRecorder> {
public:
LoopRecorder(MessageLoop** run_on, MessageLoop** deleted_on,
int* destruct_order)
: run_on_(run_on),
deleted_on_(deleted_on),
destruct_order_(destruct_order) {
}
void RecordRun() {
*run_on_ = MessageLoop::current();
}
private:
friend class RefCountedThreadSafe<LoopRecorder>;
~LoopRecorder() {
*deleted_on_ = MessageLoop::current();
*destruct_order_ = g_order.GetNext();
}
MessageLoop** run_on_;
MessageLoop** deleted_on_;
int* destruct_order_;
};
static void RecordLoop(scoped_refptr<LoopRecorder> recorder) {
recorder->RecordRun();
}
static void RecordLoopAndQuit(scoped_refptr<LoopRecorder> recorder) {
recorder->RecordRun();
MessageLoop::current()->QuitWhenIdle();
}
void UnblockTaskThread() {
thread_sync_.Signal();
}
void BlockTaskThreadHelper() {
thread_sync_.Wait();
}
static StaticAtomicSequenceNumber g_order;
scoped_ptr<MessageLoop> current_loop_;
Thread task_thread_;
private:
base::WaitableEvent thread_sync_;
};
StaticAtomicSequenceNumber MessageLoopProxyTest::g_order;
TEST_F(MessageLoopProxyTest, PostTaskAndReply_Basic) {
MessageLoop* task_run_on = NULL;
MessageLoop* task_deleted_on = NULL;
int task_delete_order = -1;
MessageLoop* reply_run_on = NULL;
MessageLoop* reply_deleted_on = NULL;
int reply_delete_order = -1;
scoped_refptr<LoopRecorder> task_recoder =
new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
scoped_refptr<LoopRecorder> reply_recoder =
new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
ASSERT_TRUE(task_thread_.message_loop_proxy()->PostTaskAndReply(
FROM_HERE,
Bind(&RecordLoop, task_recoder),
Bind(&RecordLoopAndQuit, reply_recoder)));
task_recoder = NULL;
reply_recoder = NULL;
ASSERT_FALSE(task_deleted_on);
ASSERT_FALSE(reply_deleted_on);
UnblockTaskThread();
current_loop_->Run();
EXPECT_EQ(task_thread_.message_loop(), task_run_on);
EXPECT_EQ(current_loop_.get(), task_deleted_on);
EXPECT_EQ(current_loop_.get(), reply_run_on);
EXPECT_EQ(current_loop_.get(), reply_deleted_on);
EXPECT_LT(task_delete_order, reply_delete_order);
}
TEST_F(MessageLoopProxyTest, PostTaskAndReplyOnDeletedThreadDoesNotLeak) {
MessageLoop* task_run_on = NULL;
MessageLoop* task_deleted_on = NULL;
int task_delete_order = -1;
MessageLoop* reply_run_on = NULL;
MessageLoop* reply_deleted_on = NULL;
int reply_delete_order = -1;
scoped_refptr<LoopRecorder> task_recoder =
new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
scoped_refptr<LoopRecorder> reply_recoder =
new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
scoped_refptr<MessageLoopProxy> task_loop_proxy =
task_thread_.message_loop_proxy();
UnblockTaskThread();
task_thread_.Stop();
ASSERT_FALSE(task_loop_proxy->PostTaskAndReply(
FROM_HERE,
Bind(&RecordLoop, task_recoder),
Bind(&RecordLoopAndQuit, reply_recoder)));
EXPECT_EQ(task_delete_order, reply_delete_order);
ASSERT_TRUE(task_recoder->HasOneRef());
ASSERT_TRUE(reply_recoder->HasOneRef());
EXPECT_FALSE(task_run_on);
EXPECT_FALSE(reply_run_on);
}
TEST_F(MessageLoopProxyTest, PostTaskAndReply_SameLoop) {
MessageLoop* task_run_on = NULL;
MessageLoop* task_deleted_on = NULL;
int task_delete_order = -1;
MessageLoop* reply_run_on = NULL;
MessageLoop* reply_deleted_on = NULL;
int reply_delete_order = -1;
scoped_refptr<LoopRecorder> task_recoder =
new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
scoped_refptr<LoopRecorder> reply_recoder =
new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
ASSERT_TRUE(current_loop_->message_loop_proxy()->PostTaskAndReply(
FROM_HERE,
Bind(&RecordLoop, task_recoder),
Bind(&RecordLoopAndQuit, reply_recoder)));
task_recoder = NULL;
reply_recoder = NULL;
ASSERT_FALSE(task_deleted_on);
ASSERT_FALSE(reply_deleted_on);
current_loop_->Run();
EXPECT_EQ(current_loop_.get(), task_run_on);
EXPECT_EQ(current_loop_.get(), task_deleted_on);
EXPECT_EQ(current_loop_.get(), reply_run_on);
EXPECT_EQ(current_loop_.get(), reply_deleted_on);
EXPECT_LT(task_delete_order, reply_delete_order);
}
TEST_F(MessageLoopProxyTest, PostTaskAndReply_DeadReplyLoopDoesNotDelete) {
ANNOTATE_SCOPED_MEMORY_LEAK;
MessageLoop* task_run_on = NULL;
MessageLoop* task_deleted_on = NULL;
int task_delete_order = -1;
MessageLoop* reply_run_on = NULL;
MessageLoop* reply_deleted_on = NULL;
int reply_delete_order = -1;
scoped_refptr<LoopRecorder> task_recoder =
new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
scoped_refptr<LoopRecorder> reply_recoder =
new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
task_thread_.message_loop_proxy()->PostTaskAndReply(
FROM_HERE,
Bind(&RecordLoop, task_recoder),
Bind(&RecordLoopAndQuit, reply_recoder));
task_recoder = NULL;
reply_recoder = NULL;
ASSERT_FALSE(task_deleted_on);
ASSERT_FALSE(reply_deleted_on);
UnblockTaskThread();
current_loop_.reset();
MessageLoop* task_loop = task_thread_.message_loop();
task_thread_.Stop();
EXPECT_EQ(task_loop, task_run_on);
ASSERT_FALSE(task_deleted_on);
EXPECT_FALSE(reply_run_on);
ASSERT_FALSE(reply_deleted_on);
EXPECT_EQ(task_delete_order, reply_delete_order);
}
}
}