| // Copyright 2013 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | // Epoll tests which determine that the right things happen in the right order. | 
 | // Also lots of testing of individual functions. | 
 |  | 
 | #include "epoll_server/simple_epoll_server.h" | 
 |  | 
 | #include <errno.h> | 
 | #include <fcntl.h> | 
 | #include <netinet/in.h> | 
 | #include <sys/epoll.h> | 
 | #include <sys/socket.h> | 
 | #include <unistd.h> | 
 |  | 
 | #include <algorithm> | 
 | #include <cstddef> | 
 | #include <cstdlib> | 
 | #include <cstring> | 
 | #include <memory> | 
 | #include <string> | 
 | #include <unordered_map> | 
 | #include <utility> | 
 | #include <vector> | 
 |  | 
 | #include "epoll_server/fake_simple_epoll_server.h" | 
 | #include "epoll_server/platform/api/epoll_address_test_utils.h" | 
 | #include "epoll_server/platform/api/epoll_expect_bug.h" | 
 | #include "epoll_server/platform/api/epoll_ptr_util.h" | 
 | #include "epoll_server/platform/api/epoll_test.h" | 
 | #include "epoll_server/platform/api/epoll_thread.h" | 
 | #include "epoll_server/platform/api/epoll_time.h" | 
 |  | 
 | namespace epoll_server { | 
 |  | 
 | namespace test { | 
 |  | 
 | namespace { | 
 |  | 
 | const int kPageSize = 4096; | 
 | const int kMaxBufLen = 10000; | 
 |  | 
 | // These are used to record what is happening. | 
 | enum { | 
 |   CREATION, | 
 |   REGISTRATION, | 
 |   MODIFICATION, | 
 |   EVENT, | 
 |   UNREGISTRATION, | 
 |   SHUTDOWN, | 
 |   DESTRUCTION | 
 | }; | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 |  | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 |  | 
 | struct RecordEntry { | 
 |   RecordEntry() : time(0), instance(nullptr), event_type(0), fd(0), data(0) {} | 
 |  | 
 |   RecordEntry(int64_t time, void* instance, int event_type, int fd, int data) | 
 |       : time(time), | 
 |         instance(instance), | 
 |         event_type(event_type), | 
 |         fd(fd), | 
 |         data(data) {} | 
 |  | 
 |   int64_t time; | 
 |   void* instance; | 
 |   int event_type; | 
 |   int fd; | 
 |   int data; | 
 |  | 
 |   bool IsEqual(const RecordEntry *entry) const { | 
 |     bool retval = true; | 
 |  | 
 |     if (instance  !=  entry->instance) { | 
 |       retval = false; | 
 |       EPOLL_LOG(INFO) << " instance (" << instance << ") != entry->instance(" | 
 |                       << entry->instance << ")"; | 
 |     } | 
 |     if (event_type != entry->event_type) { | 
 |       retval = false; | 
 |       EPOLL_LOG(INFO) << " event_type (" << event_type | 
 |                       << ") != entry->event_type(" << entry->event_type << ")"; | 
 |     } | 
 |     if ( fd != entry->fd ) { | 
 |       retval = false; | 
 |       EPOLL_LOG(INFO) << " fd (" << fd << ") != entry->fd (" << entry->fd | 
 |                       << ")"; | 
 |     } | 
 |     if (data != entry->data) { | 
 |       retval = false; | 
 |       EPOLL_LOG(INFO) << " data (" << data << ") != entry->data(" << entry->data | 
 |                       << ")"; | 
 |     } | 
 |     return retval; | 
 |   } | 
 | }; | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 |  | 
 | class Recorder { | 
 |  public: | 
 |   void Record(void* instance, int event_type, int fd, int data) { | 
 |     records_.push_back( | 
 |         RecordEntry(WallTimeNowInUsec(), instance, event_type, fd, data)); | 
 |   } | 
 |  | 
 |   const std::vector<RecordEntry> *records() const { return &records_; } | 
 |  | 
 |   bool IsEqual(const Recorder *recorder) const { | 
 |     const std::vector<RecordEntry> *records = recorder->records(); | 
 |  | 
 |      if (records_.size() != records->size()) { | 
 |        EPOLL_LOG(INFO) << "records_.size() (" << records_.size() | 
 |                        << ") != records->size() (" << records->size() << ")"; | 
 |        return false; | 
 |      } | 
 |      for (size_t i = 0; i < std::min(records_.size(), records->size()); ++i) { | 
 |        if (!records_[i].IsEqual(&(*records)[i])) { | 
 |          EPOLL_LOG(INFO) << "entry in index: " << i | 
 |                          << " differs from recorder."; | 
 |          return false; | 
 |        } | 
 |      } | 
 |     return true; | 
 |   } | 
 |  | 
 |  private: | 
 |   std::vector<RecordEntry> records_; | 
 | }; | 
 |  | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 |  | 
 | class RecordingCB : public EpollCallbackInterface { | 
 |  public: | 
 |   RecordingCB() : recorder_(new Recorder()) { | 
 |     recorder_->Record(this, CREATION, 0, 0); | 
 |   } | 
 |  | 
 |   ~RecordingCB() override { | 
 |     recorder_->Record(this, DESTRUCTION, 0, 0); | 
 |     delete recorder_; | 
 |   } | 
 |  | 
 |   void OnRegistration(SimpleEpollServer* /*eps*/, int fd, | 
 |                       int event_mask) override { | 
 |     recorder_->Record(this, REGISTRATION, fd, event_mask); | 
 |   } | 
 |  | 
 |   void OnModification(int fd, int event_mask) override { | 
 |     recorder_->Record(this, MODIFICATION, fd, event_mask); | 
 |   } | 
 |  | 
 |   void OnEvent(int fd, EpollEvent* event) override { | 
 |     recorder_->Record(this, EVENT, fd, event->in_events); | 
 |     if (event->in_events & EPOLLIN) { | 
 |       const int kLength = 1024; | 
 |       char buf[kLength]; | 
 |       int data_read; | 
 |       do { | 
 |         data_read = read(fd, &buf, kLength); | 
 |       } while (data_read > 0); | 
 |     } | 
 |   } | 
 |  | 
 |   void OnUnregistration(int fd, bool replaced) override { | 
 |     recorder_->Record(this, UNREGISTRATION, fd, replaced); | 
 |   } | 
 |  | 
 |   void OnShutdown(SimpleEpollServer* eps, int fd) override { | 
 |     if (fd >= 0) { | 
 |       eps->UnregisterFD(fd); | 
 |     } | 
 |     recorder_->Record(this, SHUTDOWN, fd, 0); | 
 |   } | 
 |  | 
 |   std::string Name() const override { return "RecordingCB"; } | 
 |  | 
 |   const Recorder* recorder() const { return recorder_; } | 
 |  | 
 |  protected: | 
 |   Recorder* recorder_; | 
 | }; | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 |  | 
 | // A simple test server that adds some test functions to SimpleEpollServer as | 
 | // well as allowing access to protected functions. | 
 | class EpollTestServer : public SimpleEpollServer { | 
 |  public: | 
 |   EpollTestServer() : SimpleEpollServer() {} | 
 |  | 
 |   ~EpollTestServer() override {} | 
 |  | 
 |   void CheckMapping(int fd, CB* cb) { | 
 |     CBAndEventMask tmp; | 
 |     tmp.fd = fd; | 
 |     FDToCBMap::iterator fd_i = cb_map_.find(tmp); | 
 |     CHECK(fd_i != cb_map_.end());  // Chokes CHECK_NE. | 
 |     CHECK(fd_i->cb == cb); | 
 |   } | 
 |  | 
 |   void CheckNotMapped(int fd) { | 
 |     CBAndEventMask tmp; | 
 |     tmp.fd = fd; | 
 |     FDToCBMap::iterator fd_i = cb_map_.find(tmp); | 
 |     CHECK(fd_i == cb_map_.end());  // Chokes CHECK_EQ. | 
 |   } | 
 |  | 
 |   void CheckEventMask(int fd, int event_mask) { | 
 |     CBAndEventMask tmp; | 
 |     tmp.fd = fd; | 
 |     FDToCBMap::iterator fd_i = cb_map_.find(tmp); | 
 |     CHECK(cb_map_.end() != fd_i);  // Chokes CHECK_NE. | 
 |     CHECK_EQ(fd_i->event_mask, event_mask); | 
 |   } | 
 |  | 
 |   void CheckNotRegistered(int fd) { | 
 |     struct epoll_event ee; | 
 |     memset(&ee, 0, sizeof(ee)); | 
 |     // If the fd is registered, the epoll_ctl call would succeed (return 0) and | 
 |     // the CHECK would fail. | 
 |     CHECK(epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, fd, &ee)); | 
 |   } | 
 |  | 
 |   size_t GetNumPendingAlarmsForTest() const { return alarm_map_.size(); } | 
 |  | 
 |   bool ContainsAlarm(AlarmCB* ac) { | 
 |     return all_alarms_.find(ac) != all_alarms_.end(); | 
 |   } | 
 |  | 
 |   using SimpleEpollServer::WaitForEventsAndCallHandleEvents; | 
 | }; | 
 |  | 
 | class EpollFunctionTest : public EpollTest { | 
 |  public: | 
 |   EpollFunctionTest() | 
 |       : fd_(-1), fd2_(-1), recorder_(nullptr), cb_(nullptr), ep_(nullptr) { | 
 |   } | 
 |  | 
 |   ~EpollFunctionTest() override { | 
 |     delete ep_; | 
 |     delete cb_; | 
 |   } | 
 |  | 
 |   void SetUp() override { | 
 |     ep_ = new EpollTestServer(); | 
 |     cb_ = new RecordingCB(); | 
 |     // recorder_ is safe to use directly as we know it has the same scope as | 
 |     // cb_ | 
 |     recorder_ = cb_->recorder(); | 
 |  | 
 |     int pipe_fds[2]; | 
 |     if (pipe(pipe_fds) < 0) { | 
 |       EPOLL_PLOG(FATAL) << "pipe() failed"; | 
 |     } | 
 |     fd_ = pipe_fds[0]; | 
 |     fd2_ = pipe_fds[1]; | 
 |   } | 
 |  | 
 |   void TearDown() override { | 
 |     close(fd_); | 
 |     close(fd2_); | 
 |   } | 
 |  | 
 |   void DeleteSimpleEpollServer() { | 
 |     delete ep_; | 
 |     ep_ = nullptr; | 
 |   } | 
 |  | 
 |   int fd() { return fd_; } | 
 |   int fd2() { return fd2_; } | 
 |   EpollTestServer*  ep() { return ep_; } | 
 |   EpollCallbackInterface* cb() { return cb_; } | 
 |   const Recorder* recorder() { return recorder_; } | 
 |  | 
 |  private: | 
 |   int fd_; | 
 |   int fd2_; | 
 |   const Recorder *recorder_; | 
 |   RecordingCB* cb_; | 
 |   EpollTestServer* ep_; | 
 | }; | 
 |  | 
 | TEST_F(EpollFunctionTest, TestUnconnectedSocket) { | 
 |   int fd = socket(AddressFamilyUnderTest(), SOCK_STREAM, IPPROTO_TCP); | 
 |   ep()->RegisterFD(fd, cb(), EPOLLIN | EPOLLOUT); | 
 |   ep()->WaitForEventsAndExecuteCallbacks(); | 
 |  | 
 |   Recorder tmp; | 
 |   tmp.Record(cb(), CREATION, 0, 0); | 
 |   tmp.Record(cb(), REGISTRATION, fd, EPOLLIN | EPOLLOUT); | 
 |   tmp.Record(cb(), EVENT, fd, EPOLLOUT | EPOLLHUP); | 
 |   EXPECT_TRUE(recorder()->IsEqual(&tmp)); | 
 | } | 
 |  | 
 | TEST_F(EpollFunctionTest, TestRegisterFD) { | 
 |   // Check that the basic register works. | 
 |   ep()->RegisterFD(fd(), cb(), EPOLLIN); | 
 |  | 
 |   // Make sure that the fd-CB mapping is there. | 
 |   ep()->CheckMapping(fd(), cb()); | 
 |   ep()->CheckEventMask(fd(), EPOLLIN); | 
 |  | 
 |   // Now make sure that if we register again, we stomp the old callback. | 
 |   // Also make sure we handle O_NONBLOCK correctly | 
 |   RecordingCB cb2; | 
 |   ep()->RegisterFD(fd(), &cb2, EPOLLOUT | O_NONBLOCK); | 
 |   ep()->CheckMapping(fd(), &cb2); | 
 |   ep()->CheckEventMask(fd(), EPOLLOUT | O_NONBLOCK); | 
 |  | 
 |   // Clean up. | 
 |   ep()->UnregisterFD(fd()); | 
 | } | 
 |  | 
 | TEST_F(EpollFunctionTest, TestRegisterFDForWrite) { | 
 |   ep()->RegisterFDForWrite(fd(), cb()); | 
 |   ep()->CheckMapping(fd(), cb()); | 
 |   ep()->CheckEventMask(fd(), EPOLLOUT); | 
 |  | 
 |   // Clean up. | 
 |   ep()->UnregisterFD(fd()); | 
 | } | 
 |  | 
 | TEST_F(EpollFunctionTest, TestRegisterFDForReadWrite) { | 
 |   ep()->RegisterFDForReadWrite(fd(), cb()); | 
 |   ep()->CheckMapping(fd(), cb()); | 
 |   ep()->CheckEventMask(fd(), EPOLLIN | EPOLLOUT); | 
 |  | 
 |   // Clean up. | 
 |   ep()->UnregisterFD(fd()); | 
 | } | 
 |  | 
 | TEST_F(EpollFunctionTest, TestRegisterFDForRead) { | 
 |   ep()->RegisterFDForRead(fd(), cb()); | 
 |   ep()->CheckMapping(fd(), cb()); | 
 |   ep()->CheckEventMask(fd(), EPOLLIN); | 
 |  | 
 |   ep()->UnregisterFD(fd()); | 
 | } | 
 |  | 
 | TEST_F(EpollFunctionTest, TestUnregisterFD) { | 
 |   ep()->RegisterFDForRead(fd(), cb()); | 
 |   ep()->CheckMapping(fd(), cb()); | 
 |   ep()->CheckEventMask(fd(), EPOLLIN); | 
 |  | 
 |     // Unregister and make sure that it's gone. | 
 |   ep()->UnregisterFD(fd()); | 
 |   ep()->CheckNotMapped(fd()); | 
 |   ep()->CheckNotRegistered(fd()); | 
 |  | 
 |   // And make sure that unregistering something a second time doesn't cause | 
 |   // crashes. | 
 |   ep()->UnregisterFD(fd()); | 
 |   ep()->CheckNotMapped(fd()); | 
 |   ep()->CheckNotRegistered(fd()); | 
 | } | 
 |  | 
 | TEST_F(EpollFunctionTest, TestModifyCallback) { | 
 |   // Check that nothing terrible happens if we modify an unregistered fd. | 
 |   ep()->ModifyCallback(fd(), EPOLLOUT); | 
 |   ep()->CheckNotMapped(fd()); | 
 |   ep()->CheckNotRegistered(fd()); | 
 |  | 
 |   // Check that the basic register works. | 
 |   ep()->RegisterFD(fd(), cb(), EPOLLIN); | 
 |   ep()->CheckMapping(fd(), cb()); | 
 |   ep()->CheckEventMask(fd(), EPOLLIN); | 
 |  | 
 |   // Check that adding a signal swaps it out for the first. | 
 |   ep()->ModifyCallback(fd(), EPOLLOUT); | 
 |   ep()->CheckMapping(fd(), cb()); | 
 |   ep()->CheckEventMask(fd(), EPOLLOUT); | 
 |  | 
 |   // Check that modifying from X to X works correctly. | 
 |   ep()->ModifyCallback(fd(), EPOLLOUT); | 
 |   ep()->CheckMapping(fd(), cb()); | 
 |   ep()->CheckEventMask(fd(), EPOLLOUT); | 
 |  | 
 |   // Check that modifying from something to nothing works. | 
 |   ep()->ModifyCallback(fd(), 0); | 
 |   ep()->CheckMapping(fd(), cb()); | 
 |   ep()->CheckEventMask(fd(), 0); | 
 |  | 
 |   ep()->UnregisterFD(fd()); | 
 | } | 
 |  | 
 | TEST_F(EpollFunctionTest, TestStopRead) { | 
 |   ep()->RegisterFDForReadWrite(fd(), cb()); | 
 |   ep()->CheckMapping(fd(), cb()); | 
 |   ep()->CheckEventMask(fd(), EPOLLIN | EPOLLOUT); | 
 |  | 
 |   // Unregister and make sure you only lose the read event. | 
 |   ep()->StopRead(fd()); | 
 |   ep()->CheckMapping(fd(), cb()); | 
 |   ep()->CheckEventMask(fd(), EPOLLOUT); | 
 |  | 
 |   ep()->UnregisterFD(fd()); | 
 | } | 
 |  | 
 | TEST_F(EpollFunctionTest, TestStartRead) { | 
 |   ep()->RegisterFDForWrite(fd(), cb()); | 
 |   ep()->CheckMapping(fd(), cb()); | 
 |   ep()->CheckEventMask(fd(), EPOLLOUT); | 
 |  | 
 |   // Make sure that StartRead adds EPOLLIN and doesn't remove other signals. | 
 |   ep()->StartRead(fd()); | 
 |   ep()->CheckMapping(fd(), cb()); | 
 |   ep()->CheckEventMask(fd(), EPOLLIN | EPOLLOUT); | 
 |  | 
 |   // Clean up. | 
 |   ep()->UnregisterFD(fd()); | 
 | } | 
 |  | 
 | TEST_F(EpollFunctionTest, TestStopWrite) { | 
 |   ep()->RegisterFDForReadWrite(fd(), cb()); | 
 |   ep()->CheckMapping(fd(), cb()); | 
 |   ep()->CheckEventMask(fd(), EPOLLIN | EPOLLOUT); | 
 |  | 
 |   // Unregister write and make sure you only lose the write event. | 
 |   ep()->StopWrite(fd()); | 
 |   ep()->CheckMapping(fd(), cb()); | 
 |   ep()->CheckEventMask(fd(), EPOLLIN); | 
 |  | 
 |   ep()->UnregisterFD(fd()); | 
 | } | 
 |  | 
 | TEST_F(EpollFunctionTest, TestStartWrite) { | 
 |   ep()->RegisterFDForRead(fd(), cb()); | 
 |   ep()->CheckMapping(fd(), cb()); | 
 |   ep()->CheckEventMask(fd(), EPOLLIN); | 
 |  | 
 |   // Make sure that StartWrite adds EPOLLOUT and doesn't remove other | 
 |   // signals. | 
 |   ep()->StartWrite(fd()); | 
 |   ep()->CheckMapping(fd(), cb()); | 
 |   ep()->CheckEventMask(fd(), EPOLLIN | EPOLLOUT); | 
 |  | 
 |   // Clean up. | 
 |   ep()->UnregisterFD(fd()); | 
 | } | 
 |  | 
 | TEST_F(EpollFunctionTest, TestSet_timeout_in_us) { | 
 |   // Check that set works with various values.  There's a separate test below | 
 |   // to make sure the values are used properly. | 
 |   ep()->set_timeout_in_us(10); | 
 |   EXPECT_EQ(10, ep()->timeout_in_us_for_test()); | 
 |  | 
 |   ep()->set_timeout_in_us(-1); | 
 |   EXPECT_EQ(-1, ep()->timeout_in_us_for_test()); | 
 | } | 
 |  | 
 | TEST_F(EpollFunctionTest, TestHandleEvent) { | 
 |   const std::vector<RecordEntry> *records = recorder()->records(); | 
 |  | 
 |   // Test that nothing bad happens if the FD is not in the map. | 
 |   ep()->HandleEvent(fd(), EPOLLOUT); | 
 |   ep()->CallReadyListCallbacks(); | 
 |  | 
 |   ep()->RegisterFD(fd(), cb(), 0); | 
 |   ep()->CheckMapping(fd(), cb()); | 
 |   ep()->CheckEventMask(fd(), 0); | 
 |  | 
 |   // At this point we should have creation and registration recorded. | 
 |   EXPECT_EQ(2u, records->size()); | 
 |  | 
 |   // Call handle event and make sure something was recorded. | 
 |   ep()->HandleEvent(fd(), EPOLLOUT); | 
 |   ep()->CallReadyListCallbacks(); | 
 |   EXPECT_EQ(3u, records->size()); | 
 |  | 
 |   // Call handle event and make sure something was recorded. | 
 |   ep()->HandleEvent(fd(), EPOLLIN | O_NONBLOCK); | 
 |   ep()->CallReadyListCallbacks(); | 
 |   EXPECT_EQ(4u, records->size()); | 
 |  | 
 |   Recorder tmp; | 
 |   tmp.Record(cb(), CREATION, 0, 0); | 
 |   tmp.Record(cb(), REGISTRATION, fd(), 0); | 
 |   tmp.Record(cb(), EVENT, fd(), EPOLLOUT); | 
 |   tmp.Record(cb(), EVENT, fd(), EPOLLIN | O_NONBLOCK); | 
 |  | 
 |   EXPECT_TRUE(recorder()->IsEqual(&tmp)); | 
 |   ep()->UnregisterFD(fd()); | 
 | } | 
 |  | 
 | TEST_F(EpollFunctionTest, TestNumFDsRegistered) { | 
 |   EXPECT_EQ(0, ep()->NumFDsRegistered()); | 
 |  | 
 |   ep()->RegisterFD(fd(), cb(), 0); | 
 |   EXPECT_EQ(1, ep()->NumFDsRegistered()); | 
 |  | 
 |   ep()->RegisterFD(fd2(), cb(), 0); | 
 |   EXPECT_EQ(2, ep()->NumFDsRegistered()); | 
 |  | 
 |   ep()->RegisterFD(fd2(), cb(), 0); | 
 |   EXPECT_EQ(2, ep()->NumFDsRegistered()); | 
 |  | 
 |   ep()->UnregisterFD(fd2()); | 
 |   EXPECT_EQ(1, ep()->NumFDsRegistered()); | 
 |  | 
 |   ep()->UnregisterFD(fd()); | 
 |   EXPECT_EQ(0, ep()->NumFDsRegistered()); | 
 | } | 
 |  | 
 | // Check all of the individual signals and 1-2 combinations. | 
 | TEST_F(EpollFunctionTest, TestEventMaskToString) { | 
 |   std::string test; | 
 |  | 
 |   test = SimpleEpollServer::EventMaskToString(EPOLLIN); | 
 |   EXPECT_EQ(test, "EPOLLIN "); | 
 |  | 
 |   test = SimpleEpollServer::EventMaskToString(EPOLLOUT); | 
 |   EXPECT_EQ(test, "EPOLLOUT "); | 
 |  | 
 |   test = SimpleEpollServer::EventMaskToString(EPOLLPRI); | 
 |   EXPECT_EQ(test, "EPOLLPRI "); | 
 |  | 
 |   test = SimpleEpollServer::EventMaskToString(EPOLLERR); | 
 |   EXPECT_EQ(test, "EPOLLERR "); | 
 |  | 
 |   test = SimpleEpollServer::EventMaskToString(EPOLLHUP); | 
 |   EXPECT_EQ(test, "EPOLLHUP "); | 
 |  | 
 |   test = SimpleEpollServer::EventMaskToString(EPOLLHUP | EPOLLIN); | 
 |   EXPECT_EQ(test, "EPOLLIN EPOLLHUP "); | 
 |  | 
 |   test = SimpleEpollServer::EventMaskToString(EPOLLIN | EPOLLOUT); | 
 |   EXPECT_EQ(test, "EPOLLIN EPOLLOUT "); | 
 | } | 
 |  | 
 | class TestAlarm : public EpollAlarmCallbackInterface { | 
 |  public: | 
 |   TestAlarm() | 
 |     : time_before_next_alarm_(-1), | 
 |       was_called_(false), | 
 |       num_called_(0), | 
 |       absolute_time_(false), | 
 |       onshutdown_called_(false), | 
 |       has_token_(false), | 
 |       eps_(nullptr) { | 
 |   } | 
 |   ~TestAlarm() override { | 
 |   } | 
 |   int64_t OnAlarm() override { | 
 |     has_token_ = false; | 
 |     was_called_ = true; | 
 |     ++num_called_; | 
 |     if (time_before_next_alarm_ < 0) { | 
 |       return 0; | 
 |     } | 
 |     if (absolute_time_) { | 
 |       return time_before_next_alarm_; | 
 |     } else { | 
 |       return WallTimeNowInUsec() + time_before_next_alarm_; | 
 |     } | 
 |   } | 
 |  | 
 |   void OnShutdown(SimpleEpollServer* /*eps*/) override { | 
 |     onshutdown_called_ = true; | 
 |     has_token_ = false; | 
 |   } | 
 |   void OnRegistration(const SimpleEpollServer::AlarmRegToken& token, | 
 |                       SimpleEpollServer* eps) override { | 
 |     has_token_ = true; | 
 |     last_token_ = token; | 
 |     eps_ = eps; | 
 |   } | 
 |   void OnUnregistration() override { | 
 |     has_token_ = false; | 
 |   } | 
 |  | 
 |   void UnregisterIfRegistered(SimpleEpollServer* eps) { | 
 |     if (has_token_) { | 
 |       eps->UnregisterAlarm(last_token_); | 
 |     } | 
 |   } | 
 |  | 
 |   void ReregisterAlarm(int64_t timeout_in_us) { | 
 |     CHECK(has_token_); | 
 |     eps_->ReregisterAlarm(last_token_, timeout_in_us); | 
 |   } | 
 |  | 
 |   void Reset() { | 
 |     time_before_next_alarm_ = -1; | 
 |     was_called_ = false; | 
 |     absolute_time_ = false; | 
 |   } | 
 |  | 
 |   bool was_called() const { return was_called_; } | 
 |   int num_called() const { return num_called_; } | 
 |  | 
 |   void set_time_before_next_alarm(int64_t time) { | 
 |     time_before_next_alarm_ = time; | 
 |   } | 
 |   void set_absolute_time(bool absolute) { | 
 |     absolute_time_ = absolute; | 
 |   } | 
 |   bool onshutdown_called() { return onshutdown_called_; } | 
 |  | 
 |  protected: | 
 |   int64_t time_before_next_alarm_; | 
 |   bool was_called_; | 
 |   int num_called_; | 
 |   // Is time_before_next_alarm relative to the current time or absolute? | 
 |   bool absolute_time_; | 
 |   bool onshutdown_called_; | 
 |   bool has_token_; | 
 |   SimpleEpollServer::AlarmRegToken last_token_; | 
 |   SimpleEpollServer* eps_; | 
 | }; | 
 |  | 
 | class TestChildAlarm; | 
 |  | 
 | // This node unregister all other alarms when it receives | 
 | // OnShutdown() from any one child. | 
 | class TestParentAlarm { | 
 |  public: | 
 |   void OnShutdown(TestChildAlarm* child, SimpleEpollServer* eps) { | 
 |     // Unregister | 
 |     for (ChildTokenMap::const_iterator it = child_tokens_.begin(); | 
 |          it != child_tokens_.end(); ++it) { | 
 |       if (it->first != child) { | 
 |         eps->UnregisterAlarm(it->second); | 
 |       } | 
 |     } | 
 |     child_tokens_.clear(); | 
 |   } | 
 |  | 
 |   void OnRegistration(TestChildAlarm* child, | 
 |                       const SimpleEpollServer::AlarmRegToken& token) { | 
 |     child_tokens_[child] = token; | 
 |   } | 
 |  | 
 |  protected: | 
 |   typedef std::unordered_map<TestChildAlarm*, SimpleEpollServer::AlarmRegToken> | 
 |       ChildTokenMap; | 
 |  | 
 |   ChildTokenMap child_tokens_; | 
 | }; | 
 |  | 
 | class TestChildAlarm : public TestAlarm { | 
 |  public: | 
 |   void set_parent(TestParentAlarm* tp) { parent_ = tp; } | 
 |   void OnShutdown(SimpleEpollServer* eps) override { | 
 |     onshutdown_called_ = true; | 
 |     // Inform parent of shutdown | 
 |     parent_->OnShutdown(this, eps); | 
 |   } | 
 |   void OnRegistration(const SimpleEpollServer::AlarmRegToken& token, | 
 |                       SimpleEpollServer* /*eps*/) override { | 
 |     parent_->OnRegistration(this, token); | 
 |   } | 
 |  | 
 |  protected: | 
 |   TestParentAlarm* parent_; | 
 | }; | 
 |  | 
 | class TestAlarmThatRegistersAnotherAlarm : public TestAlarm { | 
 |  public: | 
 |   TestAlarmThatRegistersAnotherAlarm() | 
 |       : alarm_(nullptr), | 
 |         reg_time_delta_usec_(0), | 
 |         eps_to_register_(nullptr), | 
 |         has_reg_alarm_(false) {} | 
 |   void SetRegisterAlarm(TestAlarm* alarm, int64_t time_delta_usec, | 
 |                         SimpleEpollServer* eps) { | 
 |     alarm_ = alarm; | 
 |     reg_time_delta_usec_ = time_delta_usec; | 
 |     has_reg_alarm_ = true; | 
 |     eps_to_register_ = eps; | 
 |   } | 
 |   int64_t OnAlarm() override { | 
 |     if (has_reg_alarm_) { | 
 |       eps_to_register_->RegisterAlarm( | 
 |           eps_to_register_->ApproximateNowInUsec() + reg_time_delta_usec_, | 
 |           alarm_); | 
 |       has_reg_alarm_ = false; | 
 |     } | 
 |     return TestAlarm::OnAlarm(); | 
 |   } | 
 |  | 
 |  protected: | 
 |   TestAlarm* alarm_; | 
 |   int64_t reg_time_delta_usec_; | 
 |   SimpleEpollServer* eps_to_register_; | 
 |   bool has_reg_alarm_; | 
 | }; | 
 |  | 
 | class TestAlarmThatRegistersAndReregistersAnotherAlarm : public TestAlarm { | 
 |  public: | 
 |   TestAlarmThatRegistersAndReregistersAnotherAlarm() | 
 |       : alarm_(nullptr), | 
 |         reg_time_delta_usec_(0), | 
 |         reregister_time_delta_usec_(0), | 
 |         eps_to_register_(nullptr), | 
 |         has_reg_alarm_(false) {} | 
 |   void SetRegisterAndReregisterAlarm(TestAlarm* alarm, int64_t time_delta_usec, | 
 |                                      int64_t reregister_delta_usec, | 
 |                                      SimpleEpollServer* eps) { | 
 |     alarm_ = alarm; | 
 |     reg_time_delta_usec_ = time_delta_usec; | 
 |     reregister_time_delta_usec_ = reregister_delta_usec; | 
 |     has_reg_alarm_ = true; | 
 |     eps_to_register_ = eps; | 
 |   } | 
 |   int64_t OnAlarm() override { | 
 |     if (has_reg_alarm_) { | 
 |       eps_to_register_->RegisterAlarm( | 
 |           eps_to_register_->ApproximateNowInUsec() + reg_time_delta_usec_, | 
 |           alarm_); | 
 |       alarm_->ReregisterAlarm(eps_to_register_->ApproximateNowInUsec() + | 
 |                               reregister_time_delta_usec_); | 
 |       has_reg_alarm_ = false; | 
 |     } | 
 |     return TestAlarm::OnAlarm(); | 
 |   } | 
 |  | 
 |  protected: | 
 |   TestAlarm* alarm_; | 
 |   int64_t reg_time_delta_usec_; | 
 |   int64_t reregister_time_delta_usec_; | 
 |   SimpleEpollServer* eps_to_register_; | 
 |   bool has_reg_alarm_; | 
 | }; | 
 |  | 
 | class TestAlarmThatUnregistersAnotherAlarm : public TestAlarm { | 
 |  public: | 
 |   TestAlarmThatUnregistersAnotherAlarm() | 
 |       : alarm_(nullptr), eps_to_register_(nullptr), has_unreg_alarm_(false) {} | 
 |   void SetUnregisterAlarm(TestAlarm* alarm, SimpleEpollServer* eps) { | 
 |     alarm_ = alarm; | 
 |     has_unreg_alarm_ = true; | 
 |     eps_to_register_ = eps; | 
 |   } | 
 |   int64_t OnAlarm() override { | 
 |     if (has_unreg_alarm_) { | 
 |       has_unreg_alarm_ = false; | 
 |       alarm_->UnregisterIfRegistered(eps_to_register_); | 
 |     } | 
 |     return TestAlarm::OnAlarm(); | 
 |   } | 
 |  | 
 |  protected: | 
 |   TestAlarm* alarm_; | 
 |   SimpleEpollServer* eps_to_register_; | 
 |   bool has_unreg_alarm_; | 
 | }; | 
 |  | 
 | class TestAlarmUnregister : public TestAlarm { | 
 |  public: | 
 |   TestAlarmUnregister() | 
 |       : onunregistration_called_(false), | 
 |         iterator_token_(nullptr) { | 
 |   } | 
 |   ~TestAlarmUnregister() override { | 
 |     delete iterator_token_; | 
 |   } | 
 |  | 
 |   void OnShutdown(SimpleEpollServer* /*eps*/) override { | 
 |     onshutdown_called_ = true; | 
 |   } | 
 |  | 
 |   int64_t OnAlarm() override { | 
 |     delete iterator_token_; | 
 |     iterator_token_ = nullptr; | 
 |  | 
 |     return TestAlarm::OnAlarm(); | 
 |   } | 
 |  | 
 |   void OnRegistration(const SimpleEpollServer::AlarmRegToken& token, | 
 |                       SimpleEpollServer* /*eps*/) override { | 
 |     // Multiple iterator tokens are not maintained by this code, | 
 |     // so we should have reset the iterator_token in OnAlarm or | 
 |     // OnUnregistration. | 
 |     CHECK(iterator_token_ == nullptr); | 
 |     iterator_token_ = new SimpleEpollServer::AlarmRegToken(token); | 
 |   } | 
 |   void OnUnregistration() override { | 
 |     delete iterator_token_; | 
 |     iterator_token_ = nullptr; | 
 |     // Make sure that this alarm was not already unregistered. | 
 |     CHECK(onunregistration_called_ == false); | 
 |     onunregistration_called_ = true; | 
 |   } | 
 |  | 
 |   bool onunregistration_called() { return onunregistration_called_; } | 
 |   // Returns true if the token has been filled in with the saved iterator | 
 |   // and false if it has not. | 
 |   bool get_token(SimpleEpollServer::AlarmRegToken* token) { | 
 |     if (iterator_token_ != nullptr) { | 
 |       *token = *iterator_token_; | 
 |       return true; | 
 |     } else { | 
 |       return false; | 
 |     } | 
 |   } | 
 |  | 
 |  protected: | 
 |   bool onunregistration_called_; | 
 |   SimpleEpollServer::AlarmRegToken* iterator_token_; | 
 | }; | 
 |  | 
 | void WaitForAlarm(SimpleEpollServer* eps, const TestAlarm& alarm) { | 
 |   for (int i = 0; i < 5; ++i) { | 
 |     // Ideally we would only have to call this once but it could wake up a bit | 
 |     // early and so not call the alarm.  If it wakes up early several times | 
 |     // there is something wrong. | 
 |     eps->WaitForEventsAndExecuteCallbacks(); | 
 |     if (alarm.was_called()) { | 
 |       break; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | // Check a couple of alarm times to make sure they're falling within a | 
 | // reasonable range. | 
 | TEST(SimpleEpollServerTest, TestAlarms) { | 
 |   EpollTestServer ep; | 
 |   TestAlarm alarm; | 
 |  | 
 |   int alarm_time = 10; | 
 |  | 
 |   // Register an alarm and make sure we wait long enough to hit it. | 
 |   ep.set_timeout_in_us(alarm_time * 1000 * 2); | 
 |   ep.RegisterAlarm(WallTimeNowInUsec() + alarm_time, &alarm); | 
 |   EXPECT_EQ(1u, ep.GetNumPendingAlarmsForTest()); | 
 |   WaitForAlarm(&ep, alarm); | 
 |   EXPECT_TRUE(alarm.was_called()); | 
 |   EXPECT_EQ(0u, ep.GetNumPendingAlarmsForTest()); | 
 |   alarm.Reset(); | 
 |  | 
 |   // Test a different time just to be careful. | 
 |   alarm_time = 20; | 
 |   ep.set_timeout_in_us(alarm_time * 1000 * 2); | 
 |   ep.RegisterAlarm(WallTimeNowInUsec() + alarm_time, &alarm); | 
 |   EXPECT_EQ(1u, ep.GetNumPendingAlarmsForTest()); | 
 |   WaitForAlarm(&ep, alarm); | 
 |   EXPECT_TRUE(alarm.was_called()); | 
 |   alarm.Reset(); | 
 |  | 
 |   // The alarm was a one-time thing.  Make sure that we don't hit it again. | 
 |   EXPECT_EQ(0u, ep.GetNumPendingAlarmsForTest()); | 
 |   ep.WaitForEventsAndExecuteCallbacks(); | 
 |   EXPECT_FALSE(alarm.was_called()); | 
 |   alarm.Reset(); | 
 | } | 
 |  | 
 | // Same as above, but using RegisterAlarmApproximateDelta. | 
 | TEST(SimpleEpollServerTest, TestRegisterAlarmApproximateDelta) { | 
 |   EpollTestServer ep; | 
 |   TestAlarm alarm; | 
 |  | 
 |   int alarm_time = 10; | 
 |  | 
 |   // Register an alarm and make sure we wait long enough to hit it. | 
 |   ep.set_timeout_in_us(alarm_time * 1000 * 2); | 
 |   ep.RegisterAlarmApproximateDelta(alarm_time * 1000, &alarm); | 
 |   EXPECT_EQ(1u, ep.GetNumPendingAlarmsForTest()); | 
 |   WaitForAlarm(&ep, alarm); | 
 |   EXPECT_TRUE(alarm.was_called()); | 
 |   EXPECT_EQ(0u, ep.GetNumPendingAlarmsForTest()); | 
 |   alarm.Reset(); | 
 |   int64_t first_now = ep.ApproximateNowInUsec(); | 
 |   EXPECT_LT(0u, first_now); | 
 |  | 
 |   // Test a different time just to be careful. | 
 |   alarm_time = 20; | 
 |   ep.set_timeout_in_us(alarm_time * 1000 * 2); | 
 |   ep.RegisterAlarmApproximateDelta(alarm_time * 1000, &alarm); | 
 |   EXPECT_EQ(1u, ep.GetNumPendingAlarmsForTest()); | 
 |   WaitForAlarm(&ep, alarm); | 
 |   EXPECT_TRUE(alarm.was_called()); | 
 |   alarm.Reset(); | 
 |   int64_t second_now = ep.ApproximateNowInUsec(); | 
 |  | 
 |   EXPECT_LT(first_now, second_now); | 
 |  | 
 |  | 
 |   // The alarm was a one-time thing.  Make sure that we don't hit it again. | 
 |   EXPECT_EQ(0u, ep.GetNumPendingAlarmsForTest()); | 
 |   ep.WaitForEventsAndExecuteCallbacks(); | 
 |   EXPECT_FALSE(alarm.was_called()); | 
 |   alarm.Reset(); | 
 | } | 
 |  | 
 | TEST(SimpleEpollServerTest, TestAlarmsWithInfiniteWait) { | 
 |   EpollTestServer ep; | 
 |   TestAlarm alarm; | 
 |  | 
 |   int alarm_time = 10; | 
 |  | 
 |   // Register an alarm and make sure we wait long enough to hit it. | 
 |   ep.set_timeout_in_us(-1); | 
 |   ep.RegisterAlarm(WallTimeNowInUsec() + alarm_time, &alarm); | 
 |   EXPECT_EQ(1u, ep.GetNumPendingAlarmsForTest()); | 
 |   WaitForAlarm(&ep, alarm); | 
 |   EXPECT_TRUE(alarm.was_called()); | 
 |   EXPECT_EQ(0u, ep.GetNumPendingAlarmsForTest()); | 
 |   alarm.Reset(); | 
 | } | 
 |  | 
 | // In this test we have an alarm that when fires gets re-registered | 
 | // at almost the same time at which it fires. Here, we want to make | 
 | // sure that when the alarm gets re-registered we do not call OnAlarm() | 
 | // on the same Alarm object again, until we have called | 
 | // WaitForEventsAndExecuteCallbacks(). A poor implementation of epoll | 
 | // server alarm handling can potentially cause OnAlarm() to be called | 
 | // multiple times. We make sure that the epoll server is not going in | 
 | // an infinite loop by checking that OnAlarm() is called exactly once | 
 | // on the alarm object that got registered again. | 
 | TEST(SimpleEpollServerTest, TestAlarmsThatGetReRegisteredAreNotCalledTwice) { | 
 |   // This alarm would get registered again | 
 |   TestAlarm alarm; | 
 |   TestAlarm alarm2; | 
 |   EpollTestServer ep; | 
 |   ep.set_timeout_in_us(-1); | 
 |  | 
 |   int64_t alarm_time = 10; | 
 |   int64_t abs_time = WallTimeNowInUsec() + alarm_time * 1000; | 
 |  | 
 |   // This will make the alarm re-register when OnAlarm is called. | 
 |   alarm.set_absolute_time(true); | 
 |   alarm.set_time_before_next_alarm(abs_time + 2); | 
 |  | 
 |   // Register two alarms and make sure we wait long enough to hit it. | 
 |   ep.RegisterAlarm(abs_time, &alarm); | 
 |   ep.RegisterAlarm(abs_time, &alarm2); | 
 |   EXPECT_EQ(2u, ep.GetNumPendingAlarmsForTest()); | 
 |  | 
 |   WaitForAlarm(&ep, alarm); | 
 |  | 
 |   EXPECT_TRUE(alarm.was_called()); | 
 |   // Make sure that alarm is called only once. | 
 |   EXPECT_EQ(1, alarm.num_called()); | 
 |   EXPECT_EQ(1u, ep.GetNumPendingAlarmsForTest()); | 
 |   alarm.Reset(); | 
 | } | 
 |  | 
 | // Here we make sure that when one alarm unregisters another alarm | 
 | // (that is supposed to be registered again because its OnAlarm | 
 | // returned > 0), the alarm thats supposed to be unregistered does | 
 | // actually gets unregistered. | 
 | TEST(SimpleEpollServerTest, TestAlarmsOneOnAlarmUnRegistersAnotherAlarm) { | 
 |   TestAlarm alarm; | 
 |   TestAlarmThatUnregistersAnotherAlarm alarm2; | 
 |   EpollTestServer ep; | 
 |   ep.set_timeout_in_us(-1); | 
 |  | 
 |   int64_t alarm_time = 1; | 
 |   int64_t abs_time = WallTimeNowInUsec() + alarm_time * 1000; | 
 |  | 
 |   // This will make the alarm re-register when OnAlarm is called. | 
 |   alarm.set_absolute_time(true); | 
 |   alarm.set_time_before_next_alarm(abs_time + 2); | 
 |  | 
 |  | 
 |   // Register two alarms and make sure we wait long enough to hit it. | 
 |   ep.RegisterAlarm(abs_time, &alarm); | 
 |   // This would cause us to unregister alarm when OnAlarm is called | 
 |   // on alarm2. | 
 |   alarm2.SetUnregisterAlarm(&alarm, &ep); | 
 |   ep.RegisterAlarm(abs_time + 1, &alarm2); | 
 |   EXPECT_EQ(2u, ep.GetNumPendingAlarmsForTest()); | 
 |  | 
 |   WaitForAlarm(&ep, alarm); | 
 |  | 
 |   EXPECT_TRUE(alarm.was_called()); | 
 |   // Make sure that alarm is called only once. | 
 |   EXPECT_EQ(1, alarm.num_called()); | 
 |   EXPECT_EQ(0u, ep.GetNumPendingAlarmsForTest()); | 
 |   alarm.Reset(); | 
 | } | 
 |  | 
 | // Check a couple of alarm times to make sure they're falling within a | 
 | // reasonable range. | 
 | TEST(SimpleEpollServerTest, TestRepeatAlarms) { | 
 |   EpollTestServer ep; | 
 |   TestAlarm alarm; | 
 |  | 
 |   int alarm_time = 20; | 
 |  | 
 |   // Register an alarm and make sure we wait long enough to hit it. | 
 |   ep.set_timeout_in_us(alarm_time * 1000 * 2); | 
 |   alarm.set_time_before_next_alarm(1000*alarm_time); | 
 |   ep.RegisterAlarm(WallTimeNowInUsec() + alarm_time, &alarm); | 
 |   EXPECT_EQ(1u, ep.GetNumPendingAlarmsForTest()); | 
 |  | 
 |   WaitForAlarm(&ep, alarm); | 
 |   // When we wake up it should be because the Alarm has been called, and has | 
 |   // registered itself to be called again. | 
 |  | 
 |   // Make sure the first alarm was called properly. | 
 |   EXPECT_TRUE(alarm.was_called()); | 
 |  | 
 |   // Resetting means that the alarm is no longer a recurring alarm.  It will be | 
 |   // called once more and then stop. | 
 |   alarm.Reset(); | 
 |  | 
 |   // Make sure the alarm is called one final time. | 
 |   EXPECT_EQ(1u, ep.GetNumPendingAlarmsForTest()); | 
 |   ep.set_timeout_in_us(alarm_time * 1000 * 2); | 
 |   WaitForAlarm(&ep, alarm); | 
 |  | 
 |   EXPECT_TRUE(alarm.was_called()); | 
 |   alarm.Reset(); | 
 |  | 
 |   // The alarm was a one-time thing.  Make sure that we don't hit it again. | 
 |   EXPECT_EQ(0u, ep.GetNumPendingAlarmsForTest()); | 
 |   ep.WaitForEventsAndExecuteCallbacks(); | 
 |   EXPECT_FALSE(alarm.was_called()); | 
 | } | 
 |  | 
 | // Verify that an alarm that repeats itself in the past works properly. | 
 | TEST(SimpleEpollServerTest, TestRepeatAlarmInPast) { | 
 |   EpollTestServer ep; | 
 |   TestAlarm alarm; | 
 |  | 
 |   int64_t alarm_time = 20; | 
 |   int64_t abs_time = WallTimeNowInUsec() + alarm_time * 1000; | 
 |  | 
 |   // Make the alarm re-register in the past when OnAlarm is called. | 
 |   alarm.set_absolute_time(true); | 
 |   alarm.set_time_before_next_alarm(abs_time - 1000); | 
 |  | 
 |   // Register the alarm and make sure we wait long enough to hit it. | 
 |   ep.set_timeout_in_us(alarm_time * 1000 * 2); | 
 |   ep.RegisterAlarm(abs_time, &alarm); | 
 |   EXPECT_EQ(1u, ep.GetNumPendingAlarmsForTest()); | 
 |  | 
 |   WaitForAlarm(&ep, alarm); | 
 |   // When we wake up it should be because the Alarm has been called, and has | 
 |   // registered itself to be called again. | 
 |  | 
 |   // Make sure the first alarm was called properly. | 
 |   EXPECT_TRUE(alarm.was_called()); | 
 |  | 
 |   // Resetting means that the alarm is no longer a recurring alarm.  It will be | 
 |   // called once more and then stop. | 
 |   alarm.Reset(); | 
 |  | 
 |   // Make sure the alarm is called one final time. | 
 |   EXPECT_EQ(1u, ep.GetNumPendingAlarmsForTest()); | 
 |   ep.set_timeout_in_us(alarm_time * 1000 * 2); | 
 |   WaitForAlarm(&ep, alarm); | 
 |  | 
 |   EXPECT_TRUE(alarm.was_called()); | 
 |   alarm.Reset(); | 
 |  | 
 |   // The alarm was a one-time thing.  Make sure that we don't hit it again. | 
 |   EXPECT_EQ(0u, ep.GetNumPendingAlarmsForTest()); | 
 |   ep.WaitForEventsAndExecuteCallbacks(); | 
 |   EXPECT_FALSE(alarm.was_called()); | 
 | } | 
 |  | 
 | class EpollTestAlarms : public SimpleEpollServer { | 
 |  public: | 
 |   EpollTestAlarms() : SimpleEpollServer() {} | 
 |  | 
 |   inline int64_t NowInUsec() const override { return time_; } | 
 |  | 
 |   void CallAndReregisterAlarmEvents() override { | 
 |     recorded_now_in_us_ = NowInUsec(); | 
 |     SimpleEpollServer::CallAndReregisterAlarmEvents(); | 
 |   } | 
 |  | 
 |   void set_time(int64_t time) { time_ = time; } | 
 |  | 
 |   size_t GetNumPendingAlarmsForTest() const { return alarm_map_.size(); } | 
 |  | 
 |  private: | 
 |   int64_t time_; | 
 | }; | 
 |  | 
 | // Test multiple interleaving alarms to make sure they work right. | 
 | // Pattern is roughly: | 
 | // time:   15    20    30    40 | 
 | // alarm:   A     B     A'    C | 
 | TEST(SimpleEpollServerTest, TestMultipleAlarms) { | 
 |   EpollTestAlarms ep; | 
 |   TestAlarm alarmA; | 
 |   TestAlarm alarmB; | 
 |   TestAlarm alarmC; | 
 |  | 
 |   ep.set_timeout_in_us(50 * 1000 * 2); | 
 |   alarmA.set_time_before_next_alarm(1000 * 30); | 
 |   alarmA.set_absolute_time(true); | 
 |   ep.RegisterAlarm(15 * 1000, &alarmA); | 
 |   ep.RegisterAlarm(20 * 1000, &alarmB); | 
 |   ep.RegisterAlarm(40 * 1000, &alarmC); | 
 |  | 
 |   ep.set_time(15 * 1000); | 
 |   ep.CallAndReregisterAlarmEvents();  // A | 
 |   EXPECT_TRUE(alarmA.was_called()); | 
 |   EXPECT_FALSE(alarmB.was_called()); | 
 |   EXPECT_FALSE(alarmC.was_called()); | 
 |   alarmA.Reset();  // Unregister A in the future. | 
 |  | 
 |   ep.set_time(20 * 1000); | 
 |   ep.CallAndReregisterAlarmEvents();  // B | 
 |   EXPECT_FALSE(alarmA.was_called()); | 
 |   EXPECT_TRUE(alarmB.was_called()); | 
 |   EXPECT_FALSE(alarmC.was_called()); | 
 |   alarmB.Reset(); | 
 |  | 
 |   ep.set_time(30 * 1000); | 
 |   ep.CallAndReregisterAlarmEvents();  // A | 
 |   EXPECT_TRUE(alarmA.was_called()); | 
 |   EXPECT_FALSE(alarmB.was_called()); | 
 |   EXPECT_FALSE(alarmC.was_called()); | 
 |   alarmA.Reset(); | 
 |  | 
 |   ep.set_time(40 * 1000); | 
 |   ep.CallAndReregisterAlarmEvents();  // C | 
 |   EXPECT_FALSE(alarmA.was_called()); | 
 |   EXPECT_FALSE(alarmB.was_called()); | 
 |   EXPECT_TRUE(alarmC.was_called()); | 
 |   alarmC.Reset(); | 
 |  | 
 |   ep.CallAndReregisterAlarmEvents();  // None. | 
 |   EXPECT_FALSE(alarmA.was_called()); | 
 |   EXPECT_FALSE(alarmB.was_called()); | 
 |   EXPECT_FALSE(alarmC.was_called()); | 
 | } | 
 |  | 
 | TEST(SimpleEpollServerTest, TestAlarmOnShutdown) { | 
 |   TestAlarm alarm1; | 
 |   { | 
 |     EpollTestServer ep; | 
 |     const int64_t now = WallTimeNowInUsec(); | 
 |     ep.RegisterAlarm(now + 5000, &alarm1); | 
 |   } | 
 |  | 
 |   EXPECT_TRUE(alarm1.onshutdown_called()); | 
 | } | 
 |  | 
 | // Tests that if we have multiple alarms | 
 | // OnShutdown then we handle them properly. | 
 | TEST(SimpleEpollServerTest, TestMultipleAlarmOnShutdown) { | 
 |   TestAlarm alarm1; | 
 |   TestAlarm alarm2; | 
 |   TestAlarm alarm3; | 
 |   { | 
 |     EpollTestServer ep; | 
 |     const int64_t now = WallTimeNowInUsec(); | 
 |     ep.RegisterAlarm(now + 5000, &alarm1); | 
 |     ep.RegisterAlarm(now + 9000, &alarm2); | 
 |     ep.RegisterAlarm(now + 9000, &alarm3); | 
 |   } | 
 |  | 
 |   EXPECT_TRUE(alarm1.onshutdown_called()); | 
 |   EXPECT_TRUE(alarm2.onshutdown_called()); | 
 |   EXPECT_TRUE(alarm3.onshutdown_called()); | 
 | } | 
 | TEST(SimpleEpollServerTest, TestMultipleAlarmUnregistrationOnShutdown) { | 
 |   TestParentAlarm tp; | 
 |   TestChildAlarm alarm1; | 
 |   TestChildAlarm alarm2; | 
 |   alarm1.set_parent(&tp); | 
 |   alarm2.set_parent(&tp); | 
 |   { | 
 |     EpollTestServer ep; | 
 |     const int64_t now = WallTimeNowInUsec(); | 
 |     ep.RegisterAlarm(now + 5000, &alarm1); | 
 |     ep.RegisterAlarm(now + 9000, &alarm2); | 
 |   } | 
 |  | 
 |   EXPECT_TRUE(alarm1.onshutdown_called()); | 
 |   EXPECT_FALSE(alarm2.onshutdown_called()); | 
 | } | 
 |  | 
 | // Check an alarm set in the past runs right away. | 
 | TEST(SimpleEpollServerTest, TestPastAlarm) { | 
 |   EpollTestServer ep; | 
 |   TestAlarm alarm; | 
 |  | 
 |   // Register the alarm and make sure we wait long enough to hit it. | 
 |   ep.set_timeout_in_us(1000 * 2); | 
 |   ep.RegisterAlarm(WallTimeNowInUsec() - 1000, &alarm); | 
 |   EXPECT_EQ(1u, ep.GetNumPendingAlarmsForTest()); | 
 |   ep.WaitForEventsAndExecuteCallbacks(); | 
 |   EXPECT_TRUE(alarm.was_called()); | 
 |   EXPECT_EQ(0u, ep.GetNumPendingAlarmsForTest()); | 
 |   alarm.Reset(); | 
 | } | 
 |  | 
 | // Test Unregistering of Alarms | 
 | TEST(SimpleEpollServerTest, TestUnregisterAlarm) { | 
 |   EpollTestServer ep; | 
 |   SimpleEpollServer::AlarmRegToken temptok; | 
 |  | 
 |   TestAlarmUnregister alarm1; | 
 |   TestAlarmUnregister alarm2; | 
 |  | 
 |   ep.RegisterAlarm(WallTimeNowInUsec() + 5 * 1000, &alarm1); | 
 |   ep.RegisterAlarm(WallTimeNowInUsec() + 13 * 1000, &alarm2); | 
 |  | 
 |   // Unregister an alarm. | 
 |   if (alarm2.get_token(&temptok)) { | 
 |     ep.UnregisterAlarm(temptok); | 
 |   } | 
 |   EXPECT_EQ(1u, ep.GetNumPendingAlarmsForTest()); | 
 |   EXPECT_TRUE(alarm2.onunregistration_called()); | 
 |  | 
 |   if (alarm1.get_token(&temptok)) { | 
 |     ep.UnregisterAlarm(temptok); | 
 |   } | 
 |   EXPECT_EQ(0u, ep.GetNumPendingAlarmsForTest()); | 
 |   EXPECT_TRUE(alarm1.onunregistration_called()); | 
 | } | 
 |  | 
 | // Test Reregistering of Alarms | 
 | TEST(SimpleEpollServerTest, TestReregisterAlarm) { | 
 |   EpollTestAlarms ep; | 
 |   SimpleEpollServer::AlarmRegToken token; | 
 |  | 
 |   TestAlarmUnregister alarm; | 
 |   ep.set_time(1000); | 
 |   ep.RegisterAlarm(5000, &alarm); | 
 |  | 
 |   EXPECT_EQ(1u, ep.GetNumPendingAlarmsForTest()); | 
 |   ASSERT_TRUE(alarm.get_token(&token)); | 
 |   ep.ReregisterAlarm(token, 6000); | 
 |   EXPECT_EQ(1u, ep.GetNumPendingAlarmsForTest()); | 
 |  | 
 |   ep.set_time(5000); | 
 |   ep.set_timeout_in_us(0); | 
 |   ep.CallAndReregisterAlarmEvents(); | 
 |   EXPECT_FALSE(alarm.was_called()); | 
 |  | 
 |   ep.set_time(6000); | 
 |   ep.CallAndReregisterAlarmEvents(); | 
 |   EXPECT_TRUE(alarm.was_called()); | 
 | } | 
 |  | 
 | TEST(SimpleEpollServerTest, TestReregisterDeferredAlarm) { | 
 |   EpollTestAlarms ep; | 
 |   ep.set_timeout_in_us(0); | 
 |  | 
 |   TestAlarm alarm; | 
 |   TestAlarmThatRegistersAndReregistersAnotherAlarm register_alarm; | 
 |   // Register the alarm in the past so it is added as a deferred alarm. | 
 |   register_alarm.SetRegisterAndReregisterAlarm(&alarm, -500, 500, &ep); | 
 |   ep.set_time(1000); | 
 |   ep.RegisterAlarm(1000, ®ister_alarm); | 
 |   // Call reregister twice, first to run register_alarm and second to run any | 
 |   // scheduled deferred alarms. | 
 |   ep.CallAndReregisterAlarmEvents(); | 
 |   ep.CallAndReregisterAlarmEvents(); | 
 |  | 
 |   EXPECT_EQ(1u, ep.GetNumPendingAlarmsForTest()); | 
 |   EXPECT_FALSE(alarm.was_called()); | 
 |  | 
 |   ep.set_time(1500); | 
 |   ep.CallAndReregisterAlarmEvents(); | 
 |   EXPECT_TRUE(alarm.was_called()); | 
 | } | 
 |  | 
 | // Check if an alarm fired and got reregistered, you are able to | 
 | // unregister the second registration. | 
 | TEST(SimpleEpollServerTest, TestFiredReregisteredAlarm) { | 
 |   EpollTestAlarms ep; | 
 |   TestAlarmUnregister alarmA; | 
 |  | 
 |   SimpleEpollServer::AlarmRegToken first_token; | 
 |   SimpleEpollServer::AlarmRegToken second_token; | 
 |   bool found; | 
 |  | 
 |   ep.set_timeout_in_us(50 * 1000 * 2); | 
 |   alarmA.set_time_before_next_alarm(1000 * 30); | 
 |   alarmA.set_absolute_time(true); | 
 |  | 
 | // Alarm A first fires at 15, then 30 | 
 |   ep.RegisterAlarm(15 * 1000, &alarmA); | 
 |  | 
 |   found = alarmA.get_token(&first_token); | 
 |   EXPECT_TRUE(found); | 
 |  | 
 |   ep.set_time(15 * 1000); | 
 |   ep.CallAndReregisterAlarmEvents();  // A | 
 |   EXPECT_TRUE(alarmA.was_called()); | 
 |  | 
 |   alarmA.Reset(); | 
 |  | 
 |   found = alarmA.get_token(&second_token); | 
 |   EXPECT_TRUE(found); | 
 |   if (found) { | 
 |     ep.UnregisterAlarm(second_token); | 
 |   } | 
 |  | 
 |   ep.set_time(30 * 1000); | 
 |   ep.CallAndReregisterAlarmEvents();  // A | 
 |  | 
 |   alarmA.Reset(); | 
 | } | 
 |  | 
 | // Here we make sure that one alarm can unregister another alarm | 
 | // in OnShutdown(). | 
 | TEST(SimpleEpollServerTest, TestAlarmCanUnregistersAnotherAlarmOnShutdown) { | 
 |   TestAlarmThatUnregistersAnotherAlarm alarm1; | 
 |   TestAlarm alarm2; | 
 |   { | 
 |     EpollTestServer ep; | 
 |     // Register two alarms and make alarm1 is placed in queue in front of alarm2 | 
 |     // so that when the queue is cleared, alarm1 is processed first. | 
 |     const int64_t now = WallTimeNowInUsec(); | 
 |     ep.RegisterAlarm(now + 5000, &alarm1); | 
 |     ep.RegisterAlarm(now + 9000, &alarm2); | 
 |     alarm1.SetUnregisterAlarm(&alarm2, &ep); | 
 |     EXPECT_EQ(2u, ep.GetNumPendingAlarmsForTest()); | 
 |   } | 
 | } | 
 |  | 
 | class TestAlarmRegisterAnotherAlarmShutdown : public TestAlarmUnregister { | 
 |  public: | 
 |   TestAlarmRegisterAnotherAlarmShutdown(EpollAlarmCallbackInterface* alarm2, | 
 |                                         int64_t when) | 
 |       : alarm2_(alarm2), when_(when) {} | 
 |   void OnShutdown(SimpleEpollServer* eps) override { | 
 |     TestAlarmUnregister::OnShutdown(eps); | 
 |     eps->RegisterAlarm(when_, alarm2_); | 
 |   } | 
 |  | 
 |  private: | 
 |   EpollAlarmCallbackInterface* alarm2_; | 
 |   int64_t when_; | 
 | }; | 
 |  | 
 | // This tests that alarm registers another alarm when shutting down. | 
 | // The two cases are: new alarm comes before and after the alarm being | 
 | // notified by OnShutdown() | 
 | TEST(SimpleEpollServerTest, AlarmRegistersAnotherAlarmOnShutdownBeforeSelf) { | 
 |   TestAlarm alarm2; | 
 |   int64_t alarm_time = WallTimeNowInUsec() + 5000; | 
 |   TestAlarmRegisterAnotherAlarmShutdown alarm1(&alarm2, alarm_time - 1000); | 
 |   { | 
 |     EpollTestAlarms ep; | 
 |     ep.RegisterAlarm(alarm_time, &alarm1); | 
 |   } | 
 |   EXPECT_TRUE(alarm1.onshutdown_called()); | 
 |   EXPECT_FALSE(alarm2.onshutdown_called()); | 
 | } | 
 |  | 
 | TEST(SimpleEpollServerTest, AlarmRegistersAnotherAlarmOnShutdownAfterSelf) { | 
 |   TestAlarm alarm2; | 
 |   int64_t alarm_time = WallTimeNowInUsec() + 5000; | 
 |   TestAlarmRegisterAnotherAlarmShutdown alarm1(&alarm2, alarm_time + 1000); | 
 |   { | 
 |     EpollTestAlarms ep; | 
 |     ep.RegisterAlarm(alarm_time, &alarm1); | 
 |   } | 
 |   EXPECT_TRUE(alarm1.onshutdown_called()); | 
 |   EXPECT_TRUE(alarm2.onshutdown_called()); | 
 | } | 
 |  | 
 | TEST(SimpleEpollServerTest, TestWrite) { | 
 |   SimpleEpollServer ep; | 
 |   ep.set_timeout_in_us(1); | 
 |   char data[kPageSize] = {0}; | 
 |  | 
 |   int pipe_fds[2]; | 
 |   if (pipe(pipe_fds) < 0) { | 
 |     EPOLL_PLOG(FATAL) << "pipe() failed"; | 
 |   } | 
 |   int read_fd = pipe_fds[0]; | 
 |   int write_fd = pipe_fds[1]; | 
 |  | 
 |   RecordingCB recording_cb; | 
 |   const Recorder* recorder = recording_cb.recorder(); | 
 |   const std::vector<RecordEntry> *records = recorder->records(); | 
 |  | 
 |   // Register to listen to write events. | 
 |   ep.RegisterFD(write_fd, &recording_cb, EPOLLOUT | O_NONBLOCK); | 
 |   // At this point the recorder should have the creation and registration | 
 |   // events. | 
 |   EXPECT_EQ(2u, records->size()); | 
 |  | 
 |   // Fill up the pipe. | 
 |   int written = 1; | 
 |   for (int i = 0; i < 17 && written > 0 ; ++i) { | 
 |     written = write(write_fd, &data, kPageSize); | 
 |   } | 
 |   EXPECT_LT(written, 0); | 
 |  | 
 |   // There should be no new events as the pipe is not available for writing. | 
 |   ep.WaitForEventsAndExecuteCallbacks(); | 
 |   EXPECT_EQ(2u, records->size()); | 
 |  | 
 |   // Now read data from the pipe to make it writable again.  This time the | 
 |   // we should get an EPOLLOUT event. | 
 |   int size = read(read_fd, &data, kPageSize); | 
 |   EXPECT_EQ(kPageSize, size); | 
 |   ep.WaitForEventsAndExecuteCallbacks(); | 
 |   EXPECT_EQ(3u, records->size()); | 
 |  | 
 |   // Now unsubscribe from writable events (which adds a modification record) | 
 |   // and wait to verify that no event records are added. | 
 |   ep.StopWrite(write_fd); | 
 |   ep.WaitForEventsAndExecuteCallbacks(); | 
 |   EXPECT_EQ(4u, records->size()); | 
 |  | 
 |   // We had the right number of events all along. Make sure they were actually | 
 |   // the right events. | 
 |   Recorder tmp; | 
 |   tmp.Record(&recording_cb, CREATION, 0, 0); | 
 |   tmp.Record(&recording_cb, REGISTRATION, write_fd, EPOLLOUT | O_NONBLOCK); | 
 |   tmp.Record(&recording_cb, EVENT, write_fd, EPOLLOUT); | 
 |   tmp.Record(&recording_cb, MODIFICATION, write_fd, O_NONBLOCK); | 
 |  | 
 |   EXPECT_TRUE(recorder->IsEqual(&tmp)); | 
 |   ep.UnregisterFD(write_fd); | 
 |  | 
 |   close(read_fd); | 
 |   close(write_fd); | 
 | } | 
 |  | 
 | TEST(SimpleEpollServerTest, TestReadWrite) { | 
 |   SimpleEpollServer ep; | 
 |   ep.set_timeout_in_us(1); | 
 |   char data[kPageSize] = {0}; | 
 |  | 
 |   int pipe_fds[2]; | 
 |   if (pipe(pipe_fds) < 0) { | 
 |     EPOLL_PLOG(FATAL) << "pipe() failed"; | 
 |   } | 
 |   int read_fd = pipe_fds[0]; | 
 |   int write_fd = pipe_fds[1]; | 
 |  | 
 |   RecordingCB recording_cb; | 
 |   const Recorder* recorder = recording_cb.recorder(); | 
 |   const std::vector<RecordEntry> *records = recorder->records(); | 
 |  | 
 |   // Register to listen to read and write events. | 
 |   ep.RegisterFDForReadWrite(read_fd, &recording_cb); | 
 |   // At this point the recorder should have the creation and registration | 
 |   // events. | 
 |   EXPECT_EQ(2u, records->size()); | 
 |  | 
 |   int written = write(write_fd, &data, kPageSize); | 
 |   EXPECT_EQ(kPageSize, written); | 
 |  | 
 |   ep.WaitForEventsAndExecuteCallbacks(); | 
 |   ep.UnregisterFD(read_fd); | 
 |  | 
 |   close(read_fd); | 
 |   close(write_fd); | 
 | } | 
 |  | 
 | TEST(SimpleEpollServerTest, TestMultipleFDs) { | 
 |   SimpleEpollServer ep; | 
 |   ep.set_timeout_in_us(1); | 
 |   char data = 'x'; | 
 |  | 
 |   int pipe_one[2]; | 
 |   if (pipe(pipe_one) < 0) { | 
 |     EPOLL_PLOG(FATAL) << "pipe() failed"; | 
 |   } | 
 |   int pipe_two[2]; | 
 |   if (pipe(pipe_two) < 0) { | 
 |     EPOLL_PLOG(FATAL) << "pipe() failed"; | 
 |   } | 
 |  | 
 |   RecordingCB recording_cb_one; | 
 |   const Recorder* recorder_one = recording_cb_one.recorder(); | 
 |   const std::vector<RecordEntry> *records_one = recorder_one->records(); | 
 |  | 
 |   RecordingCB recording_cb_two; | 
 |   const Recorder* recorder_two = recording_cb_two.recorder(); | 
 |   const std::vector<RecordEntry> *records_two = recorder_two->records(); | 
 |  | 
 |   // Register to listen to read events for both pipes | 
 |   ep.RegisterFDForRead(pipe_one[0], &recording_cb_one); | 
 |   ep.RegisterFDForRead(pipe_two[0], &recording_cb_two); | 
 |  | 
 |   EXPECT_EQ(2u, records_one->size()); | 
 |   EXPECT_EQ(2u, records_two->size()); | 
 |  | 
 |   EXPECT_EQ(1, write(pipe_one[1], &data, 1)); | 
 |   ep.WaitForEventsAndExecuteCallbacks(); | 
 |   EXPECT_EQ(3u, records_one->size()); | 
 |   EXPECT_EQ(2u, records_two->size()); | 
 |  | 
 |   EXPECT_EQ(1, write(pipe_two[1], &data, 1)); | 
 |   ep.WaitForEventsAndExecuteCallbacks(); | 
 |   EXPECT_EQ(3u, records_one->size()); | 
 |   EXPECT_EQ(3u, records_two->size()); | 
 |  | 
 |   EXPECT_EQ(1, write(pipe_one[1], &data, 1)); | 
 |   EXPECT_EQ(1, write(pipe_two[1], &data, 1)); | 
 |   ep.WaitForEventsAndExecuteCallbacks(); | 
 |   EXPECT_EQ(4u, records_one->size()); | 
 |   EXPECT_EQ(4u, records_two->size()); | 
 |  | 
 |   ep.WaitForEventsAndExecuteCallbacks(); | 
 |   ep.UnregisterFD(pipe_one[0]); | 
 |   ep.UnregisterFD(pipe_two[0]); | 
 |   close(pipe_one[0]); | 
 |   close(pipe_one[1]); | 
 |   close(pipe_two[0]); | 
 |   close(pipe_two[1]); | 
 | } | 
 |  | 
 | // Check that the SimpleEpollServer calls OnShutdown for any registered FDs. | 
 | TEST(SimpleEpollServerTest, TestFDOnShutdown) { | 
 |   int pipe_fds[2]; | 
 |   if (pipe(pipe_fds) < 0) { | 
 |     EPOLL_PLOG(FATAL) << "pipe() failed"; | 
 |   } | 
 |   int read_fd = pipe_fds[0]; | 
 |   int write_fd = pipe_fds[1]; | 
 |  | 
 |   RecordingCB recording_cb1; | 
 |   RecordingCB recording_cb2; | 
 |   const Recorder* recorder1 = recording_cb1.recorder(); | 
 |   const Recorder* recorder2 = recording_cb2.recorder(); | 
 |  | 
 |   { | 
 |     SimpleEpollServer ep; | 
 |     ep.set_timeout_in_us(1); | 
 |  | 
 |     // Register to listen to write events. | 
 |     ep.RegisterFD(write_fd, &recording_cb1, EPOLLOUT | O_NONBLOCK); | 
 |     ep.RegisterFD(read_fd, &recording_cb2, EPOLLIN | O_NONBLOCK); | 
 |   } | 
 |  | 
 |   // Make sure OnShutdown was called for both callbacks. | 
 |   Recorder write_recorder; | 
 |   write_recorder.Record(&recording_cb1, CREATION, 0, 0); | 
 |   write_recorder.Record( | 
 |       &recording_cb1, REGISTRATION, write_fd, EPOLLOUT | O_NONBLOCK); | 
 |   write_recorder.Record(&recording_cb1, UNREGISTRATION, write_fd, false); | 
 |   write_recorder.Record(&recording_cb1, SHUTDOWN, write_fd, 0); | 
 |   EXPECT_TRUE(recorder1->IsEqual(&write_recorder)); | 
 |  | 
 |   Recorder read_recorder; | 
 |   read_recorder.Record(&recording_cb2, CREATION, 0, 0); | 
 |   read_recorder.Record( | 
 |       &recording_cb2, REGISTRATION, read_fd, EPOLLIN | O_NONBLOCK); | 
 |   read_recorder.Record(&recording_cb2, UNREGISTRATION, read_fd, false); | 
 |   read_recorder.Record(&recording_cb2, SHUTDOWN, read_fd, 0); | 
 |   EXPECT_TRUE(recorder2->IsEqual(&read_recorder)); | 
 |  | 
 |   close(read_fd); | 
 |   close(write_fd); | 
 | } | 
 |  | 
 | class UnregisterCB : public EpollCallbackInterface { | 
 |  public: | 
 |   explicit UnregisterCB(int fd) | 
 |     : eps_(nullptr), fd_(fd), onshutdown_called_(false) { | 
 |   } | 
 |  | 
 |   ~UnregisterCB() override { | 
 |   } | 
 |  | 
 |   void OnShutdown(SimpleEpollServer* /*eps*/, int fd) override { | 
 |     eps_->UnregisterFD(fd_); | 
 |     eps_->UnregisterFD(fd); | 
 |     onshutdown_called_ = true; | 
 |     eps_ = nullptr; | 
 |   } | 
 |  | 
 |   void set_epollserver(SimpleEpollServer* eps) { eps_ = eps; } | 
 |   bool onshutdown_called() { return onshutdown_called_; } | 
 |  | 
 |   void OnRegistration(SimpleEpollServer* /*eps*/, int /*fd*/, | 
 |                       int /*event_mask*/) override {} | 
 |   void OnModification(int /*fd*/, int /*event_mask*/) override {} | 
 |   void OnEvent(int /*fd*/, EpollEvent* /*event*/) override {} | 
 |   void OnUnregistration(int /*fd*/, bool /*replaced*/) override {} | 
 |  | 
 |   std::string Name() const override { return "UnregisterCB"; } | 
 |  | 
 |  protected: | 
 |   SimpleEpollServer* eps_; | 
 |   int fd_; | 
 |   bool onshutdown_called_; | 
 | }; | 
 |  | 
 | // Check that unregistering fds in OnShutdown works cleanly. | 
 | TEST(SimpleEpollServerTest, TestUnregisteringFDsOnShutdown) { | 
 |   int pipe_fds[2]; | 
 |   if (pipe(pipe_fds) < 0) { | 
 |     EPOLL_PLOG(FATAL) << "pipe() failed"; | 
 |   } | 
 |   int read_fd = pipe_fds[0]; | 
 |   int write_fd = pipe_fds[1]; | 
 |  | 
 |   UnregisterCB unreg_cb1(read_fd); | 
 |   UnregisterCB unreg_cb2(write_fd); | 
 |  | 
 |   { | 
 |     SimpleEpollServer ep; | 
 |     ep.set_timeout_in_us(1); | 
 |  | 
 |     unreg_cb1.set_epollserver(&ep); | 
 |     unreg_cb2.set_epollserver(&ep); | 
 |  | 
 |     // Register to listen to write events. | 
 |     ep.RegisterFD(write_fd, &unreg_cb1, EPOLLOUT | O_NONBLOCK); | 
 |     ep.RegisterFD(read_fd, &unreg_cb2, EPOLLIN | O_NONBLOCK); | 
 |   } | 
 |  | 
 |   // Make sure at least one onshutdown was called. | 
 |   EXPECT_TRUE(unreg_cb1.onshutdown_called() || | 
 |               unreg_cb2.onshutdown_called()); | 
 |   // Make sure that both onshutdowns were not called. | 
 |   EXPECT_TRUE(!(unreg_cb1.onshutdown_called() && | 
 |               unreg_cb2.onshutdown_called())); | 
 |  | 
 |   close(read_fd); | 
 |   close(write_fd); | 
 | } | 
 |  | 
 | TEST(SimpleEpollServerTest, TestFDsAndAlarms) { | 
 |   SimpleEpollServer ep; | 
 |   ep.set_timeout_in_us(5); | 
 |   char data = 'x'; | 
 |  | 
 |   int pipe_fds[2]; | 
 |   if (pipe(pipe_fds) < 0) { | 
 |     EPOLL_PLOG(FATAL) << "pipe() failed"; | 
 |   } | 
 |  | 
 |   RecordingCB recording_cb; | 
 |   const Recorder* recorder = recording_cb.recorder(); | 
 |   const std::vector<RecordEntry> *records = recorder->records(); | 
 |  | 
 |   TestAlarm alarm; | 
 |  | 
 |   ep.RegisterFDForRead(pipe_fds[0], &recording_cb); | 
 |  | 
 |   EXPECT_EQ(2u, records->size()); | 
 |   EXPECT_FALSE(alarm.was_called()); | 
 |  | 
 |   // Write to the pipe and set a longish alarm so we get a read event followed | 
 |   // by an alarm event. | 
 |   int written = write(pipe_fds[1], &data, 1); | 
 |   EXPECT_EQ(1, written); | 
 |   ep.WaitForEventsAndExecuteCallbacks(); | 
 |   EXPECT_EQ(3u, records->size()); | 
 |   EXPECT_FALSE(alarm.was_called()); | 
 |   ep.RegisterAlarm(WallTimeNowInUsec() + 1000, &alarm); | 
 |   WaitForAlarm(&ep, alarm); | 
 |   EXPECT_EQ(3u, records->size()); | 
 |   EXPECT_TRUE(alarm.was_called()); | 
 |   alarm.Reset(); | 
 |  | 
 |   // Now set a short alarm so the alarm and the read event are called together. | 
 |   ep.RegisterAlarm(WallTimeNowInUsec(), &alarm); | 
 |   written = write(pipe_fds[1], &data, 1); | 
 |   EXPECT_EQ(1, written); | 
 |   ep.WaitForEventsAndExecuteCallbacks(); | 
 |   EXPECT_TRUE(alarm.was_called()); | 
 |   EXPECT_EQ(4u, records->size()); | 
 |  | 
 |   ep.UnregisterFD(pipe_fds[0]); | 
 |  | 
 |   close(pipe_fds[0]); | 
 |   close(pipe_fds[1]); | 
 | } | 
 |  | 
 | class EpollReader: public EpollCallbackInterface { | 
 |  public: | 
 |   explicit EpollReader(int len) | 
 |       : len_(0), | 
 |         expected_len_(len), | 
 |         done_reading_(false) { | 
 |     memset(&buf_, 0, kMaxBufLen); | 
 |   } | 
 |  | 
 |   ~EpollReader() override {} | 
 |  | 
 |   void OnRegistration(SimpleEpollServer* /*eps*/, int /*fd*/, | 
 |                       int /*event_mask*/) override {} | 
 |  | 
 |   void OnModification(int /*fd*/, int /*event_mask*/) override {} | 
 |  | 
 |   void OnEvent(int fd, EpollEvent* event) override { | 
 |     if (event->in_events & EPOLLIN) { | 
 |       len_ += read(fd, &buf_ + len_, kMaxBufLen - len_); | 
 |     } | 
 |  | 
 |     // If we have finished reading... | 
 |     if (event->in_events & EPOLLHUP) { | 
 |       CHECK_EQ(len_, expected_len_); | 
 |       done_reading_ = true; | 
 |     } | 
 |   } | 
 |  | 
 |   void OnUnregistration(int /*fd*/, bool /*replaced*/) override {} | 
 |  | 
 |   void OnShutdown(SimpleEpollServer* /*eps*/, int /*fd*/) override { | 
 |     // None of the current tests involve having active callbacks when the | 
 |     // server shuts down. | 
 |     EPOLL_LOG(FATAL); | 
 |   } | 
 |  | 
 |   std::string Name() const override { return "EpollReader"; } | 
 |  | 
 |   // Returns true if the data in buf is the same as buf_, false otherwise. | 
 |   bool CheckOutput(char* buf, int len) { | 
 |     if (len != len_) { | 
 |       return false; | 
 |     } | 
 |     return !memcmp(buf, buf_, len); | 
 |   } | 
 |  | 
 |   bool done_reading() { return done_reading_; } | 
 |  | 
 |  protected: | 
 |   int len_; | 
 |   int expected_len_; | 
 |   char buf_[kMaxBufLen]; | 
 |   bool done_reading_; | 
 | }; | 
 |  | 
 | void TestPipe(char *test_message, int len) { | 
 |   int pipe_fds[2]; | 
 |   if (pipe(pipe_fds) < 0) { | 
 |     EPOLL_PLOG(FATAL) << "pipe failed()"; | 
 |   } | 
 |   int reader_pipe = pipe_fds[0]; | 
 |   int writer_pipe = pipe_fds[1]; | 
 |   int child_pid; | 
 |   memset(test_message, 'x', len); | 
 |  | 
 |   switch (child_pid = fork()) { | 
 |     case 0: {  // Child will send message. | 
 |       const char *message = test_message; | 
 |       int size; | 
 |       close(reader_pipe); | 
 |       while ((size = write(writer_pipe, message, len)) > 0) { | 
 |         message += size; | 
 |         len -= size; | 
 |         if (len == 0) { | 
 |           break; | 
 |         } | 
 |       } | 
 |       if (len > 0) { | 
 |         EPOLL_PLOG(FATAL) << "write() failed"; | 
 |       } | 
 |       close(writer_pipe); | 
 |  | 
 |       _exit(0); | 
 |     } | 
 |     case -1: | 
 |       EPOLL_PLOG(FATAL) << "fork() failed"; | 
 |       break; | 
 |     default: {  // Parent will receive message. | 
 |       close(writer_pipe); | 
 |       auto ep = EpollMakeUnique<SimpleEpollServer>(); | 
 |       ep->set_timeout_in_us(1); | 
 |       EpollReader reader(len); | 
 |       ep->RegisterFD(reader_pipe, &reader, EPOLLIN); | 
 |  | 
 |       int64_t start_ms = WallTimeNowInUsec() / 1000; | 
 |       // Loop until we're either done reading, or have waited ~10 us. | 
 |       while (!reader.done_reading() && | 
 |              (WallTimeNowInUsec() / 1000 - start_ms) < 10000) { | 
 |         ep->WaitForEventsAndExecuteCallbacks(); | 
 |       } | 
 |       ep->UnregisterFD(reader_pipe); | 
 |       CHECK(reader.CheckOutput(test_message, len)); | 
 |       break; | 
 |     } | 
 |   } | 
 |  | 
 |   close(reader_pipe); | 
 |   close(writer_pipe); | 
 | } | 
 |  | 
 | TEST(SimpleEpollServerTest, TestSmallPipe) { | 
 |   char buf[kMaxBufLen]; | 
 |   TestPipe(buf, 10); | 
 | } | 
 |  | 
 | TEST(SimpleEpollServerTest, TestLargePipe) { | 
 |   char buf[kMaxBufLen]; | 
 |   TestPipe(buf, kMaxBufLen); | 
 | } | 
 |  | 
 | // Tests RegisterFDForRead as well as StopRead. | 
 | TEST(SimpleEpollServerTest, TestRead) { | 
 |   SimpleEpollServer ep; | 
 |   ep.set_timeout_in_us(1); | 
 |   int len = 1; | 
 |  | 
 |   int pipe_fds[2]; | 
 |   if (pipe(pipe_fds) < 0) { | 
 |     EPOLL_PLOG(FATAL) << "pipe() failed"; | 
 |   } | 
 |   int read_fd = pipe_fds[0]; | 
 |   int write_fd = pipe_fds[1]; | 
 |  | 
 |   auto reader = EpollMakeUnique<EpollReader>(len); | 
 |  | 
 |   // Check that registering a FD for read alerts us when there is data to be | 
 |   // read. | 
 |   ep.RegisterFDForRead(read_fd, reader.get()); | 
 |   char data = 'a'; | 
 |   int size = write(write_fd, &data, 1); | 
 |   EXPECT_EQ(1, size); | 
 |   ep.WaitForEventsAndExecuteCallbacks(); | 
 |   EXPECT_TRUE(reader->CheckOutput(&data, len)); | 
 |  | 
 |   // Remove the callback for read events, write to the pipe and make sure that | 
 |   // we did not read more data. | 
 |   ep.StopRead(read_fd); | 
 |   size = write(write_fd, &data, len); | 
 |   EXPECT_EQ(1, size); | 
 |   // The wait will return after timeout. | 
 |   ep.WaitForEventsAndExecuteCallbacks(); | 
 |   EXPECT_TRUE(reader->CheckOutput(&data, len)); | 
 |   ep.UnregisterFD(read_fd); | 
 |  | 
 |   close(read_fd); | 
 |   close(write_fd); | 
 | } | 
 |  | 
 | class EdgeTriggerCB : public EpollCallbackInterface { | 
 |  public: | 
 |   EdgeTriggerCB(int read_size, int write_size, char write_char, char peer_char) | 
 |       : eps_(nullptr), | 
 |         read_buf_(read_size), | 
 |         write_buf_(write_size, write_char), | 
 |         peer_char_(peer_char) { | 
 |     Reset(); | 
 |   } | 
 |  | 
 |   ~EdgeTriggerCB() override {} | 
 |  | 
 |   void Reset() { | 
 |     CHECK(eps_ == nullptr); | 
 |     bytes_read_ = 0; | 
 |     bytes_written_ = 0; | 
 |     can_read_ = false; | 
 |     will_read_ = false; | 
 |     can_write_ = false; | 
 |     will_write_ = false; | 
 |     read_closed_ = false; | 
 |     write_closed_ = false; | 
 |   } | 
 |  | 
 |   void ResetByteCounts() { | 
 |     bytes_read_ = bytes_written_ = 0; | 
 |   } | 
 |  | 
 |   void set_will_read(bool will_read) { will_read_ = will_read; } | 
 |  | 
 |   void set_will_write(bool will_write) { will_write_ = will_write; } | 
 |  | 
 |   bool can_write() const { return can_write_; } | 
 |  | 
 |   int bytes_read() const { return bytes_read_; } | 
 |  | 
 |   int bytes_written() const { return bytes_written_; } | 
 |  | 
 |   void OnRegistration(SimpleEpollServer* eps, int fd, int event_mask) override { | 
 |     EXPECT_TRUE(eps_ == nullptr); | 
 |     eps_ = eps; | 
 |     Initialize(fd, event_mask); | 
 |   } | 
 |  | 
 |   void OnModification(int fd, int event_mask) override { | 
 |     EXPECT_TRUE(eps_ != nullptr); | 
 |     if (event_mask & EPOLLET) { | 
 |       Initialize(fd, event_mask); | 
 |     } else { | 
 |       eps_->SetFDNotReady(fd); | 
 |     } | 
 |   } | 
 |  | 
 |   void OnEvent(int fd, EpollEvent* event) override { | 
 |     const int event_mask = event->in_events; | 
 |     if (event_mask & (EPOLLHUP | EPOLLERR)) { | 
 |       write_closed_ = true; | 
 |       return; | 
 |     } | 
 |     if (will_read_ && event_mask & EPOLLIN) { | 
 |       EXPECT_FALSE(read_closed_); | 
 |       int read_size = read_buf_.size(); | 
 |       memset(&read_buf_[0], 0, read_size); | 
 |       int len = recv(fd, &read_buf_[0], read_size, MSG_DONTWAIT); | 
 |       // Update the readiness states | 
 |       can_read_ = (len == read_size); | 
 |  | 
 |       if (len > 0) { | 
 |         bytes_read_ += len; | 
 |         EPOLL_VLOG(1) << "fd: " << fd << ", read " << len | 
 |                       << ", total: " << bytes_read_; | 
 |         // Now check the bytes read | 
 |         EXPECT_TRUE(CheckReadBuffer(len)); | 
 |       } else if (len < 0) { | 
 |         EPOLL_VLOG(1) << "fd: " << fd << " read hit EAGAIN"; | 
 |         EXPECT_EQ(EAGAIN, errno) << strerror(errno); | 
 |         can_read_ = false; | 
 |       } else { | 
 |         read_closed_ = true; | 
 |       } | 
 |     } | 
 |     if (will_write_ && event_mask & EPOLLOUT) { | 
 |       // Write side close/full close can only detected by EPOLLHUP, which is | 
 |       // caused by EPIPE. | 
 |       EXPECT_FALSE(write_closed_); | 
 |       int write_size = write_buf_.size(); | 
 |       int len = send(fd, &write_buf_[0], write_size, MSG_DONTWAIT); | 
 |       can_write_ = (len == write_size); | 
 |       if (len > 0) { | 
 |         bytes_written_ += len; | 
 |         EPOLL_VLOG(1) << "fd: " << fd << ", write " << len | 
 |                       << ", total: " << bytes_written_; | 
 |       } else { | 
 |         EPOLL_VLOG(1) << "fd: " << fd << " write hit EAGAIN"; | 
 |         EXPECT_EQ(EAGAIN, errno) << strerror(errno); | 
 |         can_write_ = false; | 
 |       } | 
 |     } | 
 |     // Since we can only get on the ready list once, wait till we confirm both | 
 |     // read and write side continuation state and set the correct event mask | 
 |     // for the ready list. | 
 |     event->out_ready_mask = can_read_ ? static_cast<int>(EPOLLIN) : 0; | 
 |     if (can_write_) { | 
 |       event->out_ready_mask |= EPOLLOUT; | 
 |     } | 
 |   } | 
 |  | 
 |   void OnUnregistration(int /*fd*/, bool /*replaced*/) override { | 
 |     EXPECT_TRUE(eps_ != nullptr); | 
 |     eps_ = nullptr; | 
 |   } | 
 |  | 
 |   void OnShutdown(SimpleEpollServer* /*eps*/, int /*fd*/) override { | 
 |     // None of the current tests involve having active callbacks when the | 
 |     // server shuts down. | 
 |     EPOLL_LOG(FATAL); | 
 |   } | 
 |  | 
 |   std::string Name() const override { return "EdgeTriggerCB"; } | 
 |  | 
 |  private: | 
 |   SimpleEpollServer* eps_; | 
 |   std::vector<char> read_buf_; | 
 |   int bytes_read_; | 
 |   std::vector<char> write_buf_; | 
 |   int bytes_written_; | 
 |   char peer_char_;   // The char we expected to read. | 
 |   bool can_read_; | 
 |   bool will_read_; | 
 |   bool can_write_; | 
 |   bool will_write_; | 
 |   bool read_closed_; | 
 |   bool write_closed_; | 
 |  | 
 |   void Initialize(int fd, int event_mask) { | 
 |     CHECK(eps_); | 
 |     can_read_ = can_write_ = false; | 
 |     if (event_mask & EPOLLET) { | 
 |       int events = 0; | 
 |       if (event_mask & EPOLLIN) { | 
 |         events |= EPOLLIN; | 
 |         can_read_ = true; | 
 |       } | 
 |       if (event_mask & EPOLLOUT) { | 
 |         events |= EPOLLOUT; | 
 |         can_write_ = true; | 
 |       } | 
 |       eps_->SetFDReady(fd, events); | 
 |     } | 
 |   } | 
 |  | 
 |   bool CheckReadBuffer(int len) const { | 
 |     for (int i = 0; i < len; ++i) { | 
 |       if (peer_char_ != read_buf_[i]) { | 
 |         return false; | 
 |       } | 
 |     } | 
 |     return true; | 
 |   } | 
 | }; | 
 |  | 
 | // Test adding and removing from the ready list. | 
 | TEST(SimpleEpollServerTest, TestReadyList) { | 
 |   SimpleEpollServer ep; | 
 |   int pipe_fds[2]; | 
 |   if (pipe(pipe_fds) < 0) { | 
 |     EPOLL_PLOG(FATAL) << "pipe() failed"; | 
 |   } | 
 |  | 
 |   // Just use any CB will do, since we never wait on epoll events. | 
 |   EdgeTriggerCB reader1(0, 0, 0, 0); | 
 |   EdgeTriggerCB reader2(0, 0, 0, 0); | 
 |  | 
 |   ep.RegisterFD(pipe_fds[0], &reader1, EPOLLIN); | 
 |   ep.RegisterFD(pipe_fds[1], &reader2, EPOLLOUT); | 
 |  | 
 |   // Adding fds that are registered with eps | 
 |   EXPECT_FALSE(ep.IsFDReady(pipe_fds[0])); | 
 |   EXPECT_FALSE(ep.IsFDReady(pipe_fds[1])); | 
 |  | 
 |   ep.SetFDReady(pipe_fds[0], EPOLLIN); | 
 |   EXPECT_TRUE(ep.IsFDReady(pipe_fds[0])); | 
 |   EXPECT_FALSE(ep.IsFDReady(pipe_fds[1])); | 
 |   EXPECT_EQ(1u, ep.ReadyListSize()); | 
 |   ep.SetFDReady(pipe_fds[1], EPOLLOUT); | 
 |   EXPECT_TRUE(ep.IsFDReady(pipe_fds[0])); | 
 |   EXPECT_TRUE(ep.IsFDReady(pipe_fds[1])); | 
 |   EXPECT_EQ(2u, ep.ReadyListSize()); | 
 |  | 
 |   // Now check that SetFDNotReady doesn't affect other fds | 
 |   ep.SetFDNotReady(pipe_fds[0]); | 
 |   EXPECT_FALSE(ep.IsFDReady(pipe_fds[0])); | 
 |   EXPECT_TRUE(ep.IsFDReady(pipe_fds[1])); | 
 |   EXPECT_EQ(1u, ep.ReadyListSize()); | 
 |  | 
 |   ep.UnregisterFD(pipe_fds[0]); | 
 |   ep.UnregisterFD(pipe_fds[1]); | 
 |   EXPECT_EQ(0u, ep.ReadyListSize()); | 
 |  | 
 |   // Now try adding them when they are not registered, and it shouldn't work. | 
 |   ep.SetFDReady(pipe_fds[0], EPOLLIN); | 
 |   EXPECT_FALSE(ep.IsFDReady(pipe_fds[0])); | 
 |   EXPECT_EQ(0u, ep.ReadyListSize()); | 
 |  | 
 |   close(pipe_fds[0]); | 
 |   close(pipe_fds[1]); | 
 | } | 
 |  | 
 | class EPSWaitThread : public EpollThread { | 
 |  public: | 
 |   explicit EPSWaitThread(SimpleEpollServer* eps) | 
 |       : EpollThread("EPSWait"), eps_(eps), done_(false) {} | 
 |  | 
 |   void Run() override { | 
 |     eps_->WaitForEventsAndExecuteCallbacks(); | 
 |   } | 
 |  | 
 |   bool done() { return done_; } | 
 |  private: | 
 |   SimpleEpollServer* eps_; | 
 |   bool done_; | 
 | }; | 
 |  | 
 | TEST(EpollServerTest, TestWake) { | 
 |   SimpleEpollServer eps; | 
 |   eps.set_timeout_in_us(-1); | 
 |   EPSWaitThread eps_thread(&eps); | 
 |   eps_thread.Start(); | 
 |  | 
 |   EXPECT_FALSE(eps_thread.done()); | 
 |   eps.Wake(); | 
 |   eps_thread.Join(); | 
 | } | 
 |  | 
 | class UnRegisterWhileProcessingCB: public EpollCallbackInterface { | 
 |  public: | 
 |   explicit UnRegisterWhileProcessingCB(int fd) : eps_(nullptr), fd_(fd) {} | 
 |  | 
 |   ~UnRegisterWhileProcessingCB() override { | 
 |   } | 
 |  | 
 |   void OnShutdown(SimpleEpollServer* /*eps*/, int /*fd*/) override {} | 
 |  | 
 |   void set_epoll_server(SimpleEpollServer* eps) { eps_ = eps; } | 
 |   void OnRegistration(SimpleEpollServer* /*eps*/, int /*fd*/, | 
 |                       int /*event_mask*/) override {} | 
 |   void OnModification(int /*fd*/, int /*event_mask*/) override {} | 
 |   void OnEvent(int /*fd*/, EpollEvent* /*event*/) override { | 
 |     // This should cause no problems. | 
 |     eps_->UnregisterFD(fd_); | 
 |   } | 
 |   void OnUnregistration(int /*fd*/, bool /*replaced*/) override {} | 
 |   std::string Name() const override { return "UnRegisterWhileProcessingCB"; } | 
 |  | 
 |  protected: | 
 |   SimpleEpollServer* eps_; | 
 |   int fd_; | 
 | }; | 
 |  | 
 | class RegisterWhileProcessingCB: public EpollCallbackInterface { | 
 |  public: | 
 |   RegisterWhileProcessingCB(int fd, EpollCallbackInterface* cb) | 
 |     : eps_(nullptr), fd_(fd), cb_(cb) {} | 
 |  | 
 |   ~RegisterWhileProcessingCB() override { | 
 |   } | 
 |  | 
 |   void OnShutdown(SimpleEpollServer* /*eps*/, int /*fd*/) override {} | 
 |  | 
 |   void set_epoll_server(SimpleEpollServer* eps) { eps_ = eps; } | 
 |   void OnRegistration(SimpleEpollServer* /*eps*/, int /*fd*/, | 
 |                       int /*event_mask*/) override {} | 
 |   void OnModification(int /*fd*/, int /*event_mask*/) override {} | 
 |   void OnEvent(int /*fd*/, EpollEvent* /*event*/) override { | 
 |     // This should cause no problems. | 
 |     eps_->RegisterFDForReadWrite(fd_, cb_); | 
 |   } | 
 |   void OnUnregistration(int /*fd*/, bool /*replaced*/) override {} | 
 |   std::string Name() const override { return "RegisterWhileProcessingCB"; } | 
 |  | 
 |  protected: | 
 |   SimpleEpollServer* eps_; | 
 |   int fd_; | 
 |   EpollCallbackInterface* cb_; | 
 | }; | 
 |  | 
 | // Nothing bad should happen when we do this. We're -only- | 
 | // testing that nothing bad occurs in this test. | 
 | TEST(SimpleEpollServerTest, NothingBadWhenUnRegisteringFDWhileProcessingIt) { | 
 |   UnRegisterWhileProcessingCB cb(0); | 
 |   { | 
 |     FakeSimpleEpollServer epoll_server; | 
 |     cb.set_epoll_server(&epoll_server); | 
 |     epoll_server.RegisterFDForReadWrite(0, &cb); | 
 |     epoll_event ee; | 
 |     ee.data.fd = 0; | 
 |     epoll_server.AddEvent(0, ee); | 
 |     epoll_server.AdvanceBy(1); | 
 |     epoll_server.WaitForEventsAndExecuteCallbacks(); | 
 |   } | 
 | } | 
 |  | 
 | // | 
 | // testing that nothing bad occurs in this test. | 
 | TEST(SimpleEpollServerTest, | 
 |      NoEventsDeliveredForFdsOfUnregisteredCBsWithReRegdFD) { | 
 |   // events: fd0, fd1, fd2 | 
 |   // fd0 -> unreg fd2 | 
 |   // fd1 -> reg fd2 | 
 |   // fd2 -> no event should be seen | 
 |   RecordingCB recorder_cb; | 
 |   UnRegisterWhileProcessingCB unreg_cb(-3); | 
 |   RegisterWhileProcessingCB reg_other_cb(-3, &recorder_cb); | 
 |   { | 
 |     FakeSimpleEpollServer epoll_server; | 
 |     unreg_cb.set_epoll_server(&epoll_server); | 
 |     reg_other_cb.set_epoll_server(&epoll_server); | 
 |     epoll_server.RegisterFDForReadWrite(-1, &unreg_cb); | 
 |     epoll_server.RegisterFDForReadWrite(-2, ®_other_cb); | 
 |     epoll_server.RegisterFDForReadWrite(-3, &recorder_cb); | 
 |  | 
 |     epoll_event ee; | 
 |     ee.events = EPOLLIN;  // asserted for all events for this test. | 
 |  | 
 |     // Note that these events are in 'backwards' order in terms of time. | 
 |     // Currently, the SimpleEpollServer code invokes the CBs from last delivered | 
 |     // to first delivered, so this is to be sure that we invoke the CB for -1 | 
 |     // before -2, before -3. | 
 |     ee.data.fd = -1; | 
 |     epoll_server.AddEvent(2, ee); | 
 |     ee.data.fd = -2; | 
 |     epoll_server.AddEvent(1, ee); | 
 |     ee.data.fd = -3; | 
 |     epoll_server.AddEvent(0, ee); | 
 |  | 
 |     epoll_server.AdvanceBy(5); | 
 |     epoll_server.WaitForEventsAndExecuteCallbacks(); | 
 |   } | 
 |  | 
 |   Recorder correct_recorder; | 
 |   correct_recorder.Record(&recorder_cb, CREATION, 0, 0); | 
 |   correct_recorder.Record(&recorder_cb, REGISTRATION, -3, | 
 |                           EPOLLIN | EPOLLOUT); | 
 |   correct_recorder.Record(&recorder_cb, UNREGISTRATION, -3, 0); | 
 |   correct_recorder.Record(&recorder_cb, REGISTRATION, -3, | 
 |                           EPOLLIN | EPOLLOUT); | 
 |   correct_recorder.Record(&recorder_cb, SHUTDOWN, -3, 0); | 
 |  | 
 |   EXPECT_TRUE(correct_recorder.IsEqual(recorder_cb.recorder())); | 
 | } | 
 |  | 
 | class ReRegWhileReadyListOnEvent: public EpollCallbackInterface { | 
 |  public: | 
 |   explicit ReRegWhileReadyListOnEvent(int /*fd*/) : eps_(nullptr) {} | 
 |  | 
 |   void OnShutdown(SimpleEpollServer* /*eps*/, int /*fd*/) override {} | 
 |  | 
 |   void set_epoll_server(SimpleEpollServer* eps) { eps_ = eps; } | 
 |   void OnRegistration(SimpleEpollServer* /*eps*/, int /*fd*/, | 
 |                       int /*event_mask*/) override {} | 
 |   void OnModification(int /*fd*/, int /*event_mask*/) override {} | 
 |   void OnEvent(int fd, EpollEvent* /*event_mask*/) override { | 
 |     // This should cause no problems. | 
 |     eps_->UnregisterFD(fd); | 
 |     eps_->RegisterFDForReadWrite(fd, this); | 
 |     eps_->UnregisterFD(fd); | 
 |   } | 
 |   void OnUnregistration(int /*fd*/, bool /*replaced*/) override {} | 
 |   std::string Name() const override { return "ReRegWhileReadyListOnEvent"; } | 
 |  | 
 |  protected: | 
 |   SimpleEpollServer* eps_; | 
 | }; | 
 |  | 
 | // Nothing bad should happen when we do this. We're -only- | 
 | // testing that nothing bad occurs in this test. | 
 | TEST(SimpleEpollServerTest, | 
 |      NothingBadWhenReRegisteringFDWhileProcessingFromReadyList) { | 
 |   ReRegWhileReadyListOnEvent cb(0); | 
 |   { | 
 |     FakeSimpleEpollServer epoll_server; | 
 |     cb.set_epoll_server(&epoll_server); | 
 |     epoll_server.RegisterFDForReadWrite(0, &cb); | 
 |     epoll_event ee; | 
 |     ee.data.fd = 0; | 
 |     epoll_server.AddEvent(0, ee); | 
 |     epoll_server.AdvanceBy(1); | 
 |     epoll_server.WaitForEventsAndExecuteCallbacks(); | 
 |   } | 
 | } | 
 |  | 
 | class UnRegEverythingReadyListOnEvent: public EpollCallbackInterface { | 
 |  public: | 
 |   UnRegEverythingReadyListOnEvent() : eps_(nullptr), fd_(0), fd_range_(0) {} | 
 |  | 
 |   void set_fd(int fd) { fd_ = fd; } | 
 |   void set_fd_range(int fd_range) { fd_range_ = fd_range; } | 
 |   void set_num_called(int* num_called) { num_called_ = num_called; } | 
 |  | 
 |   void OnShutdown(SimpleEpollServer* /*eps*/, int /*fd*/) override {} | 
 |  | 
 |   void set_epoll_server(SimpleEpollServer* eps) { eps_ = eps; } | 
 |   void OnRegistration(SimpleEpollServer* eps, int fd, | 
 |                       int /*event_mask*/) override { | 
 |     eps->SetFDReady(fd, EPOLLIN); | 
 |   } | 
 |   void OnModification(int /*fd*/, int /*event_mask*/) override {} | 
 |   void OnEvent(int /*fd*/, EpollEvent* /*event*/) override { | 
 |     // This should cause no problems. | 
 |     CHECK(num_called_ != nullptr); | 
 |     ++(*num_called_); | 
 |     // Note that we're iterating from -fd_range + 1 -> 0. | 
 |     // We do this because there is an FD installed into the | 
 |     // epollserver somewhere in the low numbers. | 
 |     // Using negative FD numbers (which are guaranteed to not | 
 |     // exist in the epoll-server) ensures that we will not | 
 |     // come in conflict with the preexisting FD. | 
 |     for (int i = -fd_range_ + 1; i <= 0; ++i) { | 
 |       eps_->UnregisterFD(i); | 
 |     } | 
 |   } | 
 |   void OnUnregistration(int /*fd*/, bool /*replaced*/) override {} | 
 |   std::string Name() const override { | 
 |     return "UnRegEverythingReadyListOnEvent"; | 
 |   } | 
 |  | 
 |  protected: | 
 |   SimpleEpollServer* eps_; | 
 |   int fd_; | 
 |   int fd_range_; | 
 |   int* num_called_; | 
 | }; | 
 |  | 
 | TEST(SimpleEpollServerTest, | 
 |      NothingBadWhenUnRegisteredWhileProcessingFromReadyList) { | 
 |   const size_t kNumCallbacks = 32u; | 
 |   UnRegEverythingReadyListOnEvent callbacks[kNumCallbacks]; | 
 |   int num_called = 0; | 
 |   { | 
 |     FakeSimpleEpollServer epoll_server; | 
 |     for (size_t i = 0; i < kNumCallbacks; ++i) { | 
 |       callbacks[i].set_fd(-i); | 
 |       callbacks[i].set_fd_range(kNumCallbacks); | 
 |       callbacks[i].set_num_called(&num_called); | 
 |       callbacks[i].set_epoll_server(&epoll_server); | 
 |       epoll_server.RegisterFDForReadWrite(0, &callbacks[i]); | 
 |       epoll_event ee; | 
 |       ee.data.fd = -i; | 
 |       epoll_server.AddEvent(0, ee); | 
 |     } | 
 |     epoll_server.AdvanceBy(1); | 
 |     epoll_server.WaitForEventsAndExecuteCallbacks(); | 
 |     epoll_server.WaitForEventsAndExecuteCallbacks(); | 
 |   } | 
 |   EXPECT_EQ(1, num_called); | 
 | } | 
 |  | 
 | TEST(SimpleEpollServerTest, TestThatVerifyReadyListWorksWithNothingInList) { | 
 |   FakeSimpleEpollServer epoll_server; | 
 |   epoll_server.VerifyReadyList(); | 
 | } | 
 |  | 
 | TEST(SimpleEpollServerTest, TestThatVerifyReadyListWorksWithStuffInLists) { | 
 |   FakeSimpleEpollServer epoll_server; | 
 |   epoll_server.VerifyReadyList(); | 
 | } | 
 |  | 
 | TEST(SimpleEpollServerTest, | 
 |      ApproximateNowInUsAccurateOutideOfWaitForEventsAndExecuteCallbacks) { | 
 |   FakeSimpleEpollServer epoll_server; | 
 |   epoll_server.AdvanceBy(1232); | 
 |   EXPECT_EQ(epoll_server.ApproximateNowInUsec(), epoll_server.NowInUsec()); | 
 |   epoll_server.AdvanceBy(1111); | 
 |   EXPECT_EQ(epoll_server.ApproximateNowInUsec(), epoll_server.NowInUsec()); | 
 | } | 
 |  | 
 | class ApproximateNowInUsecTestCB: public EpollCallbackInterface { | 
 |  public: | 
 |   ApproximateNowInUsecTestCB() : feps_(nullptr), called_(false) {} | 
 |  | 
 |   void OnRegistration(SimpleEpollServer* /*eps*/, int /*fd*/, | 
 |                       int /*event_mask*/) override {} | 
 |   void OnModification(int /*fd*/, int /*event_mask*/) override {} | 
 |   void OnEvent(int /*fd*/, EpollEvent* /*event*/) override { | 
 |     EXPECT_EQ(feps_->ApproximateNowInUsec(), feps_->NowInUsec()); | 
 |     feps_->AdvanceBy(1111); | 
 |     EXPECT_EQ(1 * 1111 + feps_->ApproximateNowInUsec(), feps_->NowInUsec()); | 
 |     feps_->AdvanceBy(1111); | 
 |     EXPECT_EQ(2 * 1111 + feps_->ApproximateNowInUsec(), feps_->NowInUsec()); | 
 |     called_ = true; | 
 |   } | 
 |   void OnUnregistration(int /*fd*/, bool /*replaced*/) override {} | 
 |   void OnShutdown(SimpleEpollServer* /*eps*/, int /*fd*/) override {} | 
 |   std::string Name() const override { return "ApproximateNowInUsecTestCB"; } | 
 |  | 
 |   void set_fakeepollserver(FakeSimpleEpollServer* feps) { feps_ = feps; } | 
 |   bool called() const { return called_; } | 
 |  | 
 |  protected: | 
 |   FakeSimpleEpollServer* feps_; | 
 |   bool called_; | 
 | }; | 
 |  | 
 | TEST(SimpleEpollServerTest, | 
 |      ApproximateNowInUsApproximateInsideOfWaitForEventsAndExecuteCallbacks) { | 
 |   int dummy_fd = 11111; | 
 |   ApproximateNowInUsecTestCB aniutcb; | 
 |   { | 
 |     FakeSimpleEpollServer epoll_server; | 
 |     aniutcb.set_fakeepollserver(&epoll_server); | 
 |  | 
 |     epoll_server.RegisterFD(dummy_fd, &aniutcb, EPOLLIN); | 
 |     epoll_event ee; | 
 |     ee.data.fd = dummy_fd; | 
 |     ee.events = EPOLLIN; | 
 |     epoll_server.AddEvent(10242, ee); | 
 |     epoll_server.set_timeout_in_us(-1); | 
 |     epoll_server.AdvanceByAndWaitForEventsAndExecuteCallbacks(20000); | 
 |     EXPECT_TRUE(aniutcb.called()); | 
 |   } | 
 | } | 
 |  | 
 | // A mock epoll server that also simulates kernel delay in scheduling epoll | 
 | // events. | 
 | class FakeEpollServerWithDelay : public FakeSimpleEpollServer { | 
 |  public: | 
 |   FakeEpollServerWithDelay() : FakeSimpleEpollServer(), delay(0) {} | 
 |  | 
 |   int delay; | 
 |  | 
 |  protected: | 
 |   int epoll_wait_impl(int epfd, struct epoll_event* events, int max_events, | 
 |                       int timeout_in_ms) override { | 
 |     int out = FakeSimpleEpollServer::epoll_wait_impl(epfd, events, max_events, | 
 |                                                      timeout_in_ms); | 
 |     AdvanceBy(delay); | 
 |     return out; | 
 |   } | 
 | }; | 
 |  | 
 | // A callback that records the epoll event's delay. | 
 | class RecordDelayOnEvent: public EpollCallbackInterface { | 
 |  public: | 
 |   RecordDelayOnEvent() : last_delay(-1), eps_(nullptr) {} | 
 |  | 
 |   ~RecordDelayOnEvent() override { | 
 |   } | 
 |  | 
 |   void OnShutdown(SimpleEpollServer* /*eps*/, int /*fd*/) override {} | 
 |  | 
 |   std::string Name() const override { return "RecordDelayOnEvent"; } | 
 |  | 
 |   void set_epoll_server(SimpleEpollServer* eps) { eps_ = eps; } | 
 |   void OnRegistration(SimpleEpollServer* /*eps*/, int /*fd*/, | 
 |                       int /*event_mask*/) override {} | 
 |   void OnModification(int /*fd*/, int /*event_mask*/) override {} | 
 |   void OnEvent(int /*fd*/, EpollEvent* /*event*/) override { | 
 |     last_delay = eps_->LastDelayInUsec(); | 
 |   } | 
 |   void OnUnregistration(int /*fd*/, bool /*replaced*/) override {} | 
 |  | 
 |   int64_t last_delay; | 
 |  | 
 |  protected: | 
 |   SimpleEpollServer* eps_; | 
 | }; | 
 |  | 
 | // Tests that an epoll callback sees the correct delay for its event when it | 
 | // calls LastDelayInUsec(). | 
 | TEST(EpollServerTest, TestLastDelay) { | 
 |   RecordDelayOnEvent cb; | 
 |   FakeEpollServerWithDelay epoll_server; | 
 |  | 
 |   cb.set_epoll_server(&epoll_server); | 
 |  | 
 |   epoll_server.RegisterFDForReadWrite(0, &cb); | 
 |   epoll_event ee; | 
 |   ee.data.fd = 0; | 
 |  | 
 |   // Inject delay, and confirm that it's reported. | 
 |   epoll_server.set_timeout_in_us(5000); | 
 |   epoll_server.delay = 6000; | 
 |   epoll_server.AddEvent(0, ee); | 
 |   epoll_server.AdvanceBy(1); | 
 |   epoll_server.WaitForEventsAndExecuteCallbacks(); | 
 |   EXPECT_EQ(cb.last_delay, 1000); | 
 |  | 
 |   // Fire an event before the timeout ends, and confirm that reported delay | 
 |   // isn't negative. | 
 |   epoll_server.set_timeout_in_us(5000); | 
 |   epoll_server.delay = 0; | 
 |   epoll_server.AddEvent(0, ee); | 
 |   epoll_server.AdvanceBy(1); | 
 |   epoll_server.WaitForEventsAndExecuteCallbacks(); | 
 |   EXPECT_EQ(cb.last_delay, 0); | 
 |  | 
 |   // Wait forever until an event fires, and confirm there's no reported delay. | 
 |   epoll_server.set_timeout_in_us(-1); | 
 |   epoll_server.delay = 6000; | 
 |   epoll_server.AddEvent(0, ee); | 
 |   epoll_server.AdvanceBy(1); | 
 |   epoll_server.WaitForEventsAndExecuteCallbacks(); | 
 |   EXPECT_EQ(cb.last_delay, 0); | 
 | } | 
 |  | 
 | TEST(SimpleEpollServerAlarmTest, TestShutdown) { | 
 |   std::unique_ptr<SimpleEpollServer> eps(new SimpleEpollServer); | 
 |   EpollAlarm alarm1; | 
 |   EpollAlarm alarm2; | 
 |  | 
 |   eps->RegisterAlarmApproximateDelta(10000000, &alarm1); | 
 |   eps->RegisterAlarmApproximateDelta(10000000, &alarm2); | 
 |  | 
 |   alarm2.UnregisterIfRegistered(); | 
 |   EXPECT_FALSE(alarm2.registered()); | 
 |   eps = nullptr; | 
 |  | 
 |   EXPECT_FALSE(alarm1.registered()); | 
 | } | 
 |  | 
 | TEST(SimpleEpollServerAlarmTest, TestUnregister) { | 
 |   SimpleEpollServer eps; | 
 |   EpollAlarm alarm; | 
 |  | 
 |   eps.RegisterAlarmApproximateDelta(10000000, &alarm); | 
 |   EXPECT_TRUE(alarm.registered()); | 
 |  | 
 |   alarm.UnregisterIfRegistered(); | 
 |   EXPECT_FALSE(alarm.registered()); | 
 |  | 
 |   alarm.UnregisterIfRegistered(); | 
 |   EXPECT_FALSE(alarm.registered()); | 
 | } | 
 |  | 
 | TEST(SimpleEpollServerAlarmTest, TestUnregisterOnDestruction) { | 
 |   EpollTestServer eps; | 
 |   std::unique_ptr<EpollAlarm> alarm(new EpollAlarm()); | 
 |   EpollAlarm* alarm_ptr = alarm.get(); | 
 |  | 
 |   eps.RegisterAlarmApproximateDelta(10000000, alarm.get()); | 
 |   EXPECT_TRUE(eps.ContainsAlarm(alarm_ptr)); | 
 |   alarm = nullptr; | 
 |   EXPECT_EQ(0u, eps.GetNumPendingAlarmsForTest()); | 
 | } | 
 |  | 
 | TEST(SimpleEpollServerAlarmTest, TestUnregisterOnAlarm) { | 
 |   EpollTestServer eps; | 
 |   EpollAlarm alarm; | 
 |  | 
 |   eps.RegisterAlarmApproximateDelta(1, &alarm); | 
 |   EXPECT_TRUE(eps.ContainsAlarm(&alarm)); | 
 |  | 
 |   while (alarm.registered()) { | 
 |     eps.WaitForEventsAndExecuteCallbacks(); | 
 |   } | 
 |   EXPECT_FALSE(eps.ContainsAlarm(&alarm)); | 
 | } | 
 |  | 
 | TEST(SimpleEpollServerAlarmTest, TestReregisterAlarm) { | 
 |   EpollTestAlarms ep; | 
 |  | 
 |   EpollAlarm alarm; | 
 |   ep.set_time(1000); | 
 |   ep.RegisterAlarm(5000, &alarm); | 
 |  | 
 |   EXPECT_EQ(1u, ep.GetNumPendingAlarmsForTest()); | 
 |   alarm.ReregisterAlarm(6000); | 
 |   EXPECT_EQ(1u, ep.GetNumPendingAlarmsForTest()); | 
 |  | 
 |   ep.set_time(5000); | 
 |   ep.set_timeout_in_us(0); | 
 |   ep.CallAndReregisterAlarmEvents(); | 
 |   EXPECT_EQ(1u, ep.GetNumPendingAlarmsForTest()); | 
 |  | 
 |   ep.set_time(6000); | 
 |   ep.CallAndReregisterAlarmEvents(); | 
 |   EXPECT_EQ(0u, ep.GetNumPendingAlarmsForTest()); | 
 | } | 
 |  | 
 | TEST(SimpleEpollServerAlarmTest, TestThatSameAlarmCanNotBeRegisteredTwice) { | 
 |   TestAlarm alarm; | 
 |   SimpleEpollServer epoll_server; | 
 |   epoll_server.RegisterAlarm(1, &alarm); | 
 |   EXPECT_EPOLL_BUG(epoll_server.RegisterAlarm(1, &alarm), | 
 |                    "Alarm already exists"); | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | }  // namespace test | 
 |  | 
 | }  // namespace epoll_server |