|  | // 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 |