1 // Copyright 2022 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef QUICHE_QUIC_CORE_IO_QUIC_POLL_EVENT_LOOP_H_ 6 #define QUICHE_QUIC_CORE_IO_QUIC_POLL_EVENT_LOOP_H_ 7 8 #if defined(_WIN32) 9 #include <winsock2.h> 10 #else 11 #include <poll.h> 12 #endif 13 14 #include <memory> 15 16 #include "absl/container/btree_map.h" 17 #include "absl/types/span.h" 18 #include "quiche/quic/core/io/quic_event_loop.h" 19 #include "quiche/quic/core/io/socket.h" 20 #include "quiche/quic/core/quic_alarm.h" 21 #include "quiche/quic/core/quic_alarm_factory.h" 22 #include "quiche/quic/core/quic_clock.h" 23 #include "quiche/common/quiche_linked_hash_map.h" 24 25 namespace quic { 26 27 // A simple and portable implementation of QuicEventLoop using poll(2). Works 28 // on all POSIX platforms (and can be potentially made to support Windows using 29 // WSAPoll). 30 // 31 // For most operations, this implementation has a typical runtime of 32 // O(N + log M), where N is the number of file descriptors, and M is the number 33 // of pending alarms. 34 // 35 // This API has to deal with the situations where callbacks are modified from 36 // the callbacks themselves. To address this, we use the following two 37 // approaches: 38 // 1. The code does not execute any callbacks until the very end of the 39 // processing, when all of the state for the event loop is consistent. 40 // 2. The callbacks are stored as weak pointers, since other callbacks can 41 // cause them to be unregistered. 42 class QuicPollEventLoop : public QuicEventLoop { 43 public: 44 QuicPollEventLoop(QuicClock* clock); 45 46 // QuicEventLoop implementation. SupportsEdgeTriggered()47 bool SupportsEdgeTriggered() const override { return false; } 48 ABSL_MUST_USE_RESULT bool RegisterSocket( 49 SocketFd fd, QuicSocketEventMask events, 50 QuicSocketEventListener* listener) override; 51 ABSL_MUST_USE_RESULT bool UnregisterSocket(SocketFd fd) override; 52 ABSL_MUST_USE_RESULT bool RearmSocket(SocketFd fd, 53 QuicSocketEventMask events) override; 54 ABSL_MUST_USE_RESULT bool ArtificiallyNotifyEvent( 55 SocketFd fd, QuicSocketEventMask events) override; 56 void RunEventLoopOnce(QuicTime::Delta default_timeout) override; 57 std::unique_ptr<QuicAlarmFactory> CreateAlarmFactory() override; GetClock()58 const QuicClock* GetClock() override { return clock_; } 59 60 protected: 61 // Allows poll(2) calls to be mocked out in unit tests. 62 virtual int PollSyscall(pollfd* fds, size_t nfds, int timeout); 63 64 private: 65 friend class QuicPollEventLoopPeer; 66 67 struct Registration { 68 QuicSocketEventMask events = 0; 69 QuicSocketEventListener* listener; 70 71 QuicSocketEventMask artificially_notify_at_next_iteration = 0; 72 }; 73 74 class Alarm : public QuicAlarm { 75 public: 76 Alarm(QuicPollEventLoop* loop, 77 QuicArenaScopedPtr<QuicAlarm::Delegate> delegate); 78 79 void SetImpl() override; 80 void CancelImpl() override; 81 DoFire()82 void DoFire() { 83 current_schedule_handle_.reset(); 84 Fire(); 85 } 86 87 private: 88 QuicPollEventLoop* loop_; 89 // Deleted when the alarm is cancelled, causing the corresponding weak_ptr 90 // in the alarm list to not be executed. 91 std::shared_ptr<Alarm*> current_schedule_handle_; 92 }; 93 94 class AlarmFactory : public QuicAlarmFactory { 95 public: AlarmFactory(QuicPollEventLoop * loop)96 AlarmFactory(QuicPollEventLoop* loop) : loop_(loop) {} 97 98 // QuicAlarmFactory implementation. 99 QuicAlarm* CreateAlarm(QuicAlarm::Delegate* delegate) override; 100 QuicArenaScopedPtr<QuicAlarm> CreateAlarm( 101 QuicArenaScopedPtr<QuicAlarm::Delegate> delegate, 102 QuicConnectionArena* arena) override; 103 104 private: 105 QuicPollEventLoop* loop_; 106 }; 107 108 // Used for deferred execution of I/O callbacks. 109 struct ReadyListEntry { 110 SocketFd fd; 111 std::weak_ptr<Registration> registration; 112 QuicSocketEventMask events; 113 }; 114 115 // We're using a linked hash map here to ensure the events are called in the 116 // registration order. This isn't strictly speaking necessary, but makes 117 // testing things easier. 118 using RegistrationMap = 119 quiche::QuicheLinkedHashMap<SocketFd, std::shared_ptr<Registration>>; 120 // Alarms are stored as weak pointers, since the alarm can be cancelled and 121 // disappear while in the queue. 122 using AlarmList = absl::btree_multimap<QuicTime, std::weak_ptr<Alarm*>>; 123 124 // Returns the timeout for the next poll(2) call. It is typically the time at 125 // which the next alarm is supposed to activate. 126 QuicTime::Delta ComputePollTimeout(QuicTime now, 127 QuicTime::Delta default_timeout) const; 128 // Calls poll(2) with the provided timeout and dispatches the callbacks 129 // accordingly. 130 void ProcessIoEvents(QuicTime start_time, QuicTime::Delta timeout); 131 // Calls all of the alarm callbacks that are scheduled before or at |time|. 132 void ProcessAlarmsUpTo(QuicTime time); 133 134 // Adds the I/O callbacks for |fd| to the |ready_lits| as appopriate. 135 void DispatchIoEvent(std::vector<ReadyListEntry>& ready_list, SocketFd fd, 136 short mask); // NOLINT(runtime/int) 137 // Runs all of the callbacks on the ready list. 138 void RunReadyCallbacks(std::vector<ReadyListEntry>& ready_list); 139 140 // Calls poll() while handling EINTR. Returns the return value of poll(2) 141 // system call. 142 int PollWithRetries(absl::Span<pollfd> fds, QuicTime start_time, 143 QuicTime::Delta timeout); 144 145 const QuicClock* clock_; 146 RegistrationMap registrations_; 147 AlarmList alarms_; 148 bool has_artificial_events_pending_ = false; 149 }; 150 151 class QuicPollEventLoopFactory : public QuicEventLoopFactory { 152 public: Get()153 static QuicPollEventLoopFactory* Get() { 154 static QuicPollEventLoopFactory* factory = new QuicPollEventLoopFactory(); 155 return factory; 156 } 157 Create(QuicClock * clock)158 std::unique_ptr<QuicEventLoop> Create(QuicClock* clock) override { 159 return std::make_unique<QuicPollEventLoop>(clock); 160 } 161 GetName()162 std::string GetName() const override { return "poll(2)"; } 163 }; 164 165 } // namespace quic 166 167 #endif // QUICHE_QUIC_CORE_IO_QUIC_POLL_EVENT_LOOP_H_ 168