summaryrefslogtreecommitdiffstats
path: root/base/message_loop_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'base/message_loop_unittest.cc')
-rw-r--r--base/message_loop_unittest.cc186
1 files changed, 87 insertions, 99 deletions
diff --git a/base/message_loop_unittest.cc b/base/message_loop_unittest.cc
index 83be2b1..d959659 100644
--- a/base/message_loop_unittest.cc
+++ b/base/message_loop_unittest.cc
@@ -1056,68 +1056,6 @@ void RunTest_NonNestableInNestedLoop(MessageLoop::Type message_loop_type) {
#if defined(OS_WIN)
-class AutoresetWatcher : public MessageLoopForIO::Watcher {
- public:
- explicit AutoresetWatcher(HANDLE signal) : signal_(signal) {
- }
- virtual void OnObjectSignaled(HANDLE object);
- private:
- HANDLE signal_;
-};
-
-void AutoresetWatcher::OnObjectSignaled(HANDLE object) {
- MessageLoopForIO::current()->WatchObject(object, NULL);
- ASSERT_TRUE(SetEvent(signal_));
-}
-
-class AutoresetTask : public Task {
- public:
- AutoresetTask(HANDLE object, MessageLoopForIO::Watcher* watcher)
- : object_(object), watcher_(watcher) {}
- virtual void Run() {
- MessageLoopForIO::current()->WatchObject(object_, watcher_);
- }
-
- private:
- HANDLE object_;
- MessageLoopForIO::Watcher* watcher_;
-};
-
-void RunTest_AutoresetEvents(MessageLoop::Type message_loop_type) {
- MessageLoop loop(message_loop_type);
-
- SECURITY_ATTRIBUTES attributes;
- attributes.nLength = sizeof(attributes);
- attributes.bInheritHandle = false;
- attributes.lpSecurityDescriptor = NULL;
-
- // Init an autoreset and a manual reset events.
- HANDLE autoreset = CreateEvent(&attributes, FALSE, FALSE, NULL);
- HANDLE callback_called = CreateEvent(&attributes, TRUE, FALSE, NULL);
- ASSERT_TRUE(NULL != autoreset);
- ASSERT_TRUE(NULL != callback_called);
-
- Thread thread("Autoreset test");
- Thread::Options options;
- options.message_loop_type = message_loop_type;
- ASSERT_TRUE(thread.StartWithOptions(options));
-
- MessageLoop* thread_loop = thread.message_loop();
- ASSERT_TRUE(NULL != thread_loop);
-
- AutoresetWatcher watcher(callback_called);
- AutoresetTask* task = new AutoresetTask(autoreset, &watcher);
- thread_loop->PostTask(FROM_HERE, task);
- Sleep(100); // Make sure the thread runs and sleeps for lack of work.
-
- ASSERT_TRUE(SetEvent(autoreset));
-
- DWORD result = WaitForSingleObject(callback_called, 1000);
- EXPECT_EQ(WAIT_OBJECT_0, result);
-
- thread.Stop();
-}
-
class DispatcherImpl : public MessageLoopForUI::Dispatcher {
public:
DispatcherImpl() : dispatch_count_(0) {}
@@ -1150,68 +1088,68 @@ void RunTest_Dispatcher(MessageLoop::Type message_loop_type) {
class TestIOHandler : public MessageLoopForIO::IOHandler {
public:
- TestIOHandler(const wchar_t* name, HANDLE signal);
+ TestIOHandler(const wchar_t* name, HANDLE signal, bool wait);
- virtual void OnIOCompleted(OVERLAPPED* context, DWORD bytes_transfered,
- DWORD error);
+ virtual void OnIOCompleted(MessageLoopForIO::IOContext* context,
+ DWORD bytes_transfered, DWORD error);
- HANDLE file() { return file_.Get(); }
- void* buffer() { return buffer_; }
- OVERLAPPED* context() { return &context_; }
+ void Init();
+ void WaitForIO();
+ OVERLAPPED* context() { return &context_.overlapped; }
DWORD size() { return sizeof(buffer_); }
private:
char buffer_[48];
- OVERLAPPED context_;
+ MessageLoopForIO::IOContext context_;
HANDLE signal_;
ScopedHandle file_;
- ScopedHandle event_;
+ bool wait_;
};
-TestIOHandler::TestIOHandler(const wchar_t* name, HANDLE signal)
- : signal_(signal) {
+TestIOHandler::TestIOHandler(const wchar_t* name, HANDLE signal, bool wait)
+ : signal_(signal), wait_(wait) {
memset(buffer_, 0, sizeof(buffer_));
memset(&context_, 0, sizeof(context_));
-
- event_.Set(CreateEvent(NULL, TRUE, FALSE, NULL));
- EXPECT_TRUE(event_.IsValid());
- context_.hEvent = event_.Get();
+ context_.handler = this;
file_.Set(CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING,
FILE_FLAG_OVERLAPPED, NULL));
EXPECT_TRUE(file_.IsValid());
}
-void TestIOHandler::OnIOCompleted(OVERLAPPED* context, DWORD bytes_transfered,
- DWORD error) {
+void TestIOHandler::Init() {
+ MessageLoopForIO::current()->RegisterIOHandler(file_, this);
+
+ DWORD read;
+ EXPECT_FALSE(ReadFile(file_, buffer_, size(), &read, context()));
+ EXPECT_EQ(ERROR_IO_PENDING, GetLastError());
+ if (wait_)
+ WaitForIO();
+}
+
+void TestIOHandler::OnIOCompleted(MessageLoopForIO::IOContext* context,
+ DWORD bytes_transfered, DWORD error) {
ASSERT_TRUE(context == &context_);
- MessageLoopForIO::current()->RegisterIOContext(context, NULL);
ASSERT_TRUE(SetEvent(signal_));
}
+void TestIOHandler::WaitForIO() {
+ EXPECT_TRUE(MessageLoopForIO::current()->WaitForIOCompletion(300, this));
+ EXPECT_TRUE(MessageLoopForIO::current()->WaitForIOCompletion(400, this));
+}
+
class IOHandlerTask : public Task {
public:
explicit IOHandlerTask(TestIOHandler* handler) : handler_(handler) {}
- virtual void Run();
+ virtual void Run() {
+ handler_->Init();
+ }
private:
TestIOHandler* handler_;
};
-void IOHandlerTask::Run() {
- MessageLoopForIO::current()->RegisterIOHandler(handler_->file(), handler_);
- MessageLoopForIO::current()->RegisterIOContext(handler_->context(), handler_);
-
- DWORD read;
- EXPECT_FALSE(ReadFile(handler_->file(), handler_->buffer(), handler_->size(),
- &read, handler_->context()));
- EXPECT_EQ(ERROR_IO_PENDING, GetLastError());
-}
-
void RunTest_IOHandler() {
- // This test requires an IO loop.
- MessageLoop loop(MessageLoop::TYPE_IO);
-
ScopedHandle callback_called(CreateEvent(NULL, TRUE, FALSE, NULL));
ASSERT_TRUE(callback_called.IsValid());
@@ -1228,7 +1166,7 @@ void RunTest_IOHandler() {
MessageLoop* thread_loop = thread.message_loop();
ASSERT_TRUE(NULL != thread_loop);
- TestIOHandler handler(kPipeName, callback_called);
+ TestIOHandler handler(kPipeName, callback_called, false);
IOHandlerTask* task = new IOHandlerTask(&handler);
thread_loop->PostTask(FROM_HERE, task);
Sleep(100); // Make sure the thread runs and sleeps for lack of work.
@@ -1243,6 +1181,57 @@ void RunTest_IOHandler() {
thread.Stop();
}
+void RunTest_WaitForIO() {
+ ScopedHandle callback1_called(CreateEvent(NULL, TRUE, FALSE, NULL));
+ ScopedHandle callback2_called(CreateEvent(NULL, TRUE, FALSE, NULL));
+ ASSERT_TRUE(callback1_called.IsValid());
+ ASSERT_TRUE(callback2_called.IsValid());
+
+ const wchar_t* kPipeName1 = L"\\\\.\\pipe\\iohandler_pipe1";
+ const wchar_t* kPipeName2 = L"\\\\.\\pipe\\iohandler_pipe2";
+ ScopedHandle server1(CreateNamedPipe(kPipeName1, PIPE_ACCESS_OUTBOUND, 0, 1,
+ 0, 0, 0, NULL));
+ ScopedHandle server2(CreateNamedPipe(kPipeName2, PIPE_ACCESS_OUTBOUND, 0, 1,
+ 0, 0, 0, NULL));
+ ASSERT_TRUE(server1.IsValid());
+ ASSERT_TRUE(server2.IsValid());
+
+ Thread thread("IOHandler test");
+ Thread::Options options;
+ options.message_loop_type = MessageLoop::TYPE_IO;
+ ASSERT_TRUE(thread.StartWithOptions(options));
+
+ MessageLoop* thread_loop = thread.message_loop();
+ ASSERT_TRUE(NULL != thread_loop);
+
+ TestIOHandler handler1(kPipeName1, callback1_called, false);
+ TestIOHandler handler2(kPipeName2, callback2_called, true);
+ IOHandlerTask* task1 = new IOHandlerTask(&handler1);
+ IOHandlerTask* task2 = new IOHandlerTask(&handler2);
+ thread_loop->PostTask(FROM_HERE, task1);
+ Sleep(100); // Make sure the thread runs and sleeps for lack of work.
+ thread_loop->PostTask(FROM_HERE, task2);
+ Sleep(100);
+
+ // At this time handler1 is waiting to be called, and the thread is waiting
+ // on the Init method of handler2, filtering only handler2 callbacks.
+
+ const char buffer[] = "Hello there!";
+ DWORD written;
+ EXPECT_TRUE(WriteFile(server1, buffer, sizeof(buffer), &written, NULL));
+ Sleep(200);
+ EXPECT_EQ(WAIT_TIMEOUT, WaitForSingleObject(callback1_called, 0)) <<
+ "handler1 has not been called";
+
+ EXPECT_TRUE(WriteFile(server2, buffer, sizeof(buffer), &written, NULL));
+
+ HANDLE objects[2] = { callback1_called.Get(), callback2_called.Get() };
+ DWORD result = WaitForMultipleObjects(2, objects, TRUE, 1000);
+ EXPECT_EQ(WAIT_OBJECT_0, result);
+
+ thread.Stop();
+}
+
#endif // defined(OS_WIN)
} // namespace
@@ -1379,11 +1368,6 @@ TEST(MessageLoopTest, NonNestableInNestedLoop) {
}
#if defined(OS_WIN)
-TEST(MessageLoopTest, AutoresetEvents) {
- // This test requires an IO loop
- RunTest_AutoresetEvents(MessageLoop::TYPE_IO);
-}
-
TEST(MessageLoopTest, Dispatcher) {
// This test requires a UI loop
RunTest_Dispatcher(MessageLoop::TYPE_UI);
@@ -1392,4 +1376,8 @@ TEST(MessageLoopTest, Dispatcher) {
TEST(MessageLoopTest, IOHandler) {
RunTest_IOHandler();
}
+
+TEST(MessageLoopTest, WaitForIO) {
+ RunTest_WaitForIO();
+}
#endif // defined(OS_WIN)