libchromeos: Implement I/O watching in MessageLoop.

This patch introduces a simple I/O watching method to the MessageLoop
interface following the pattern used by shill and what glib and libevent
can offer as implementation backend. This also includes implementations
for the GlibMessageLoop and the FakeMessageLoop.

BUG=brillo:91,chromium:402066
TEST=Added unittest to validate GlibMessageLoop.

Change-Id: I0a0032bc40f6fd046b8b98076e0f553cdcd69051
Reviewed-on: https://chromium-review.googlesource.com/282110
Reviewed-by: Alex Deymo <deymo@chromium.org>
Tested-by: Alex Deymo <deymo@chromium.org>
Commit-Queue: Alex Deymo <deymo@chromium.org>
diff --git a/chromeos/message_loops/fake_message_loop_unittest.cc b/chromeos/message_loops/fake_message_loop_unittest.cc
index d2582fb..cec715d 100644
--- a/chromeos/message_loops/fake_message_loop_unittest.cc
+++ b/chromeos/message_loops/fake_message_loop_unittest.cc
@@ -81,6 +81,32 @@
   EXPECT_EQ(start + TimeDelta::FromSeconds(3), clock_.Now());
 }
 
+TEST_F(FakeMessageLoopTest, WatchFileDescriptorWaits) {
+  int fd = 1234;
+  // We will simulate this situation. At the beginning, we will watch for a
+  // file descriptor that won't trigger for 10s. Then we will pretend it is
+  // ready after 10s and expect its callback to run just once.
+  int called = 0;
+  TaskId task_id = loop_->WatchFileDescriptor(
+      FROM_HERE, fd, MessageLoop::kWatchRead, false,
+      Bind([&called] { called++; }));
+  EXPECT_NE(MessageLoop::kTaskIdNull, task_id);
+
+  EXPECT_NE(MessageLoop::kTaskIdNull,
+            loop_->PostDelayedTask(Bind([this] { this->loop_->BreakLoop(); }),
+                                   TimeDelta::FromSeconds(10)));
+  EXPECT_NE(MessageLoop::kTaskIdNull,
+            loop_->PostDelayedTask(Bind([this] { this->loop_->BreakLoop(); }),
+                                   TimeDelta::FromSeconds(20)));
+  loop_->Run();
+  EXPECT_EQ(0, called);
+
+  loop_->SetFileDescriptorReadiness(fd, MessageLoop::kWatchRead, true);
+  loop_->Run();
+  EXPECT_EQ(1, called);
+  EXPECT_FALSE(loop_->CancelTask(task_id));
+}
+
 TEST_F(FakeMessageLoopTest, PendingTasksTest) {
   loop_->PostDelayedTask(Bind(&base::DoNothing), TimeDelta::FromSeconds(1));
   EXPECT_TRUE(loop_->PendingTasks());