1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/message_loop/message_pump_libevent.h" 6 7 #include <unistd.h> 8 9 #include "base/bind.h" 10 #include "base/message_loop/message_loop.h" 11 #include "base/posix/eintr_wrapper.h" 12 #include "base/run_loop.h" 13 #include "base/threading/thread.h" 14 #include "testing/gtest/include/gtest/gtest.h" 15 #include "third_party/libevent/event.h" 16 17 namespace base { 18 19 class MessagePumpLibeventTest : public testing::Test { 20 protected: 21 MessagePumpLibeventTest() 22 : ui_loop_(MessageLoop::TYPE_UI), 23 io_thread_("MessagePumpLibeventTestIOThread") {} 24 virtual ~MessagePumpLibeventTest() {} 25 26 virtual void SetUp() OVERRIDE { 27 Thread::Options options(MessageLoop::TYPE_IO, 0); 28 ASSERT_TRUE(io_thread_.StartWithOptions(options)); 29 ASSERT_EQ(MessageLoop::TYPE_IO, io_thread_.message_loop()->type()); 30 int ret = pipe(pipefds_); 31 ASSERT_EQ(0, ret); 32 } 33 34 virtual void TearDown() OVERRIDE { 35 if (IGNORE_EINTR(close(pipefds_[0])) < 0) 36 PLOG(ERROR) << "close"; 37 if (IGNORE_EINTR(close(pipefds_[1])) < 0) 38 PLOG(ERROR) << "close"; 39 } 40 41 MessageLoop* ui_loop() { return &ui_loop_; } 42 MessageLoopForIO* io_loop() const { 43 return static_cast<MessageLoopForIO*>(io_thread_.message_loop()); 44 } 45 46 void OnLibeventNotification( 47 MessagePumpLibevent* pump, 48 MessagePumpLibevent::FileDescriptorWatcher* controller) { 49 pump->OnLibeventNotification(0, EV_WRITE | EV_READ, controller); 50 } 51 52 int pipefds_[2]; 53 54 private: 55 MessageLoop ui_loop_; 56 Thread io_thread_; 57 }; 58 59 namespace { 60 61 // Concrete implementation of MessagePumpLibevent::Watcher that does 62 // nothing useful. 63 class StupidWatcher : public MessagePumpLibevent::Watcher { 64 public: 65 virtual ~StupidWatcher() {} 66 67 // base:MessagePumpLibevent::Watcher interface 68 virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE {} 69 virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {} 70 }; 71 72 #if GTEST_HAS_DEATH_TEST && !defined(NDEBUG) 73 74 // Test to make sure that we catch calling WatchFileDescriptor off of the 75 // wrong thread. 76 TEST_F(MessagePumpLibeventTest, TestWatchingFromBadThread) { 77 MessagePumpLibevent::FileDescriptorWatcher watcher; 78 StupidWatcher delegate; 79 80 ASSERT_DEATH(io_loop()->WatchFileDescriptor( 81 STDOUT_FILENO, false, MessageLoopForIO::WATCH_READ, &watcher, &delegate), 82 "Check failed: " 83 "watch_file_descriptor_caller_checker_.CalledOnValidThread\\(\\)"); 84 } 85 86 TEST_F(MessagePumpLibeventTest, QuitOutsideOfRun) { 87 scoped_ptr<MessagePumpLibevent> pump(new MessagePumpLibevent); 88 ASSERT_DEATH(pump->Quit(), "Check failed: in_run_. " 89 "Quit was called outside of Run!"); 90 } 91 92 #endif // GTEST_HAS_DEATH_TEST && !defined(NDEBUG) 93 94 class BaseWatcher : public MessagePumpLibevent::Watcher { 95 public: 96 explicit BaseWatcher(MessagePumpLibevent::FileDescriptorWatcher* controller) 97 : controller_(controller) { 98 DCHECK(controller_); 99 } 100 virtual ~BaseWatcher() {} 101 102 // base:MessagePumpLibevent::Watcher interface 103 virtual void OnFileCanReadWithoutBlocking(int /* fd */) OVERRIDE { 104 NOTREACHED(); 105 } 106 107 virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE { 108 NOTREACHED(); 109 } 110 111 protected: 112 MessagePumpLibevent::FileDescriptorWatcher* controller_; 113 }; 114 115 class DeleteWatcher : public BaseWatcher { 116 public: 117 explicit DeleteWatcher( 118 MessagePumpLibevent::FileDescriptorWatcher* controller) 119 : BaseWatcher(controller) {} 120 121 virtual ~DeleteWatcher() { 122 DCHECK(!controller_); 123 } 124 125 virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE { 126 DCHECK(controller_); 127 delete controller_; 128 controller_ = NULL; 129 } 130 }; 131 132 TEST_F(MessagePumpLibeventTest, DeleteWatcher) { 133 scoped_ptr<MessagePumpLibevent> pump(new MessagePumpLibevent); 134 MessagePumpLibevent::FileDescriptorWatcher* watcher = 135 new MessagePumpLibevent::FileDescriptorWatcher; 136 DeleteWatcher delegate(watcher); 137 pump->WatchFileDescriptor(pipefds_[1], 138 false, MessagePumpLibevent::WATCH_READ_WRITE, watcher, &delegate); 139 140 // Spoof a libevent notification. 141 OnLibeventNotification(pump.get(), watcher); 142 } 143 144 class StopWatcher : public BaseWatcher { 145 public: 146 explicit StopWatcher( 147 MessagePumpLibevent::FileDescriptorWatcher* controller) 148 : BaseWatcher(controller) {} 149 150 virtual ~StopWatcher() {} 151 152 virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE { 153 controller_->StopWatchingFileDescriptor(); 154 } 155 }; 156 157 TEST_F(MessagePumpLibeventTest, StopWatcher) { 158 scoped_ptr<MessagePumpLibevent> pump(new MessagePumpLibevent); 159 MessagePumpLibevent::FileDescriptorWatcher watcher; 160 StopWatcher delegate(&watcher); 161 pump->WatchFileDescriptor(pipefds_[1], 162 false, MessagePumpLibevent::WATCH_READ_WRITE, &watcher, &delegate); 163 164 // Spoof a libevent notification. 165 OnLibeventNotification(pump.get(), &watcher); 166 } 167 168 void QuitMessageLoopAndStart(const Closure& quit_closure) { 169 quit_closure.Run(); 170 171 MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current()); 172 RunLoop runloop; 173 MessageLoop::current()->PostTask(FROM_HERE, runloop.QuitClosure()); 174 runloop.Run(); 175 } 176 177 class NestedPumpWatcher : public MessagePumpLibevent::Watcher { 178 public: 179 NestedPumpWatcher() {} 180 virtual ~NestedPumpWatcher() {} 181 182 virtual void OnFileCanReadWithoutBlocking(int /* fd */) OVERRIDE { 183 RunLoop runloop; 184 MessageLoop::current()->PostTask(FROM_HERE, Bind(&QuitMessageLoopAndStart, 185 runloop.QuitClosure())); 186 runloop.Run(); 187 } 188 189 virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE {} 190 }; 191 192 TEST_F(MessagePumpLibeventTest, NestedPumpWatcher) { 193 scoped_ptr<MessagePumpLibevent> pump(new MessagePumpLibevent); 194 MessagePumpLibevent::FileDescriptorWatcher watcher; 195 NestedPumpWatcher delegate; 196 pump->WatchFileDescriptor(pipefds_[1], 197 false, MessagePumpLibevent::WATCH_READ, &watcher, &delegate); 198 199 // Spoof a libevent notification. 200 OnLibeventNotification(pump.get(), &watcher); 201 } 202 203 } // namespace 204 205 } // namespace base 206