|  | // Copyright 2022 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. | 
|  |  | 
|  | #ifndef QUICHE_QUIC_BINDINGS_QUIC_LIBEVENT_H_ | 
|  | #define QUICHE_QUIC_BINDINGS_QUIC_LIBEVENT_H_ | 
|  |  | 
|  | #include <memory> | 
|  | #include <optional> | 
|  | #include <utility> | 
|  |  | 
|  | #include "absl/container/flat_hash_set.h" | 
|  | #include "absl/container/node_hash_map.h" | 
|  | #include "event2/event.h" | 
|  | #include "event2/event_struct.h" | 
|  | #include "quiche/quic/core/io/quic_event_loop.h" | 
|  | #include "quiche/quic/core/quic_alarm.h" | 
|  | #include "quiche/quic/core/quic_alarm_factory.h" | 
|  | #include "quiche/quic/core/quic_udp_socket.h" | 
|  |  | 
|  | namespace quic { | 
|  |  | 
|  | // While we inline `struct event` sometimes, it is actually quite large, so | 
|  | // doing that for the libevent-based QuicAlarm would cause it to not fit into | 
|  | // the QuicConnectionArena. | 
|  | struct QUICHE_NO_EXPORT LibeventEventDeleter { | 
|  | void operator()(event* ev) { event_free(ev); } | 
|  | }; | 
|  |  | 
|  | // Provides a libevent-based implementation of QuicEventLoop.  Since libevent | 
|  | // uses relative time for all timeouts, the provided clock does not need to use | 
|  | // the UNIX time. | 
|  | class QUICHE_EXPORT LibeventQuicEventLoop : public QuicEventLoop { | 
|  | public: | 
|  | explicit LibeventQuicEventLoop(event_base* base, QuicClock* clock); | 
|  | ~LibeventQuicEventLoop() override; | 
|  |  | 
|  | // QuicEventLoop implementation. | 
|  | bool SupportsEdgeTriggered() const override { return edge_triggered_; } | 
|  | std::unique_ptr<QuicAlarmFactory> CreateAlarmFactory() override { | 
|  | return std::make_unique<AlarmFactory>(this); | 
|  | } | 
|  | bool RegisterSocket(QuicUdpSocketFd fd, QuicSocketEventMask events, | 
|  | QuicSocketEventListener* listener) override; | 
|  | bool UnregisterSocket(QuicUdpSocketFd fd) override; | 
|  | bool RearmSocket(QuicUdpSocketFd fd, QuicSocketEventMask events) override; | 
|  | bool ArtificiallyNotifyEvent(QuicUdpSocketFd fd, | 
|  | QuicSocketEventMask events) override; | 
|  | void RunEventLoopOnce(QuicTime::Delta default_timeout) override; | 
|  | const QuicClock* GetClock() override { return clock_; } | 
|  |  | 
|  | // Can be called from another thread to wake up the event loop from a blocking | 
|  | // RunEventLoopOnce() call. | 
|  | void WakeUp(); | 
|  |  | 
|  | event_base* base() { return base_; } | 
|  | QuicClock* clock() const { return clock_; } | 
|  |  | 
|  | private: | 
|  | void ActivateArtificialEvents(); | 
|  |  | 
|  | class AlarmFactory : public QuicAlarmFactory { | 
|  | public: | 
|  | AlarmFactory(LibeventQuicEventLoop* loop) : loop_(loop) {} | 
|  |  | 
|  | // QuicAlarmFactory interface. | 
|  | QuicAlarm* CreateAlarm(QuicAlarm::Delegate* delegate) override; | 
|  | QuicArenaScopedPtr<QuicAlarm> CreateAlarm( | 
|  | QuicArenaScopedPtr<QuicAlarm::Delegate> delegate, | 
|  | QuicConnectionArena* arena) override; | 
|  |  | 
|  | private: | 
|  | LibeventQuicEventLoop* loop_; | 
|  | }; | 
|  |  | 
|  | class Registration { | 
|  | public: | 
|  | Registration(LibeventQuicEventLoop* loop, QuicUdpSocketFd fd, | 
|  | QuicSocketEventMask events, QuicSocketEventListener* listener); | 
|  | ~Registration(); | 
|  |  | 
|  | void Rearm(QuicSocketEventMask events); | 
|  |  | 
|  | // Record artificial events that should be notified on the next iteration of | 
|  | // the event loop. | 
|  | void RecordArtificalEvents(QuicSocketEventMask events); | 
|  |  | 
|  | // If any artificial events have been recorded, notify the listener about | 
|  | // them in the current iteration. | 
|  | void MaybeNotifyArtificalEvents(); | 
|  |  | 
|  | private: | 
|  | LibeventQuicEventLoop* loop_; | 
|  | QuicSocketEventListener* listener_; | 
|  |  | 
|  | // Used for edge-triggered backends. | 
|  | event both_events_; | 
|  | // Used for level-triggered backends, since we may have to re-arm read | 
|  | // events and write events separately. | 
|  | event read_event_; | 
|  | event write_event_; | 
|  |  | 
|  | // Recorded artificial events to be notified on the next iteration. | 
|  | QuicSocketEventMask artificial_events_ = 0; | 
|  | }; | 
|  |  | 
|  | using RegistrationMap = absl::node_hash_map<QuicUdpSocketFd, Registration>; | 
|  |  | 
|  | event_base* base_; | 
|  | const bool edge_triggered_; | 
|  | QuicClock* clock_; | 
|  |  | 
|  | RegistrationMap registration_map_; | 
|  | std::unique_ptr<event, LibeventEventDeleter> artifical_event_timer_; | 
|  | absl::flat_hash_set<QuicUdpSocketFd> fds_with_artifical_events_; | 
|  | }; | 
|  |  | 
|  | // RAII-style wrapper around event_base. | 
|  | class QUICHE_EXPORT LibeventLoop { | 
|  | public: | 
|  | LibeventLoop(struct event_base* base) : event_base_(base) {} | 
|  | ~LibeventLoop() { event_base_free(event_base_); } | 
|  |  | 
|  | struct event_base* event_base() { return event_base_; } | 
|  |  | 
|  | private: | 
|  | struct event_base* event_base_; | 
|  | }; | 
|  |  | 
|  | // A version of LibeventQuicEventLoop that owns the supplied `event_base`.  Note | 
|  | // that the inheritance order here matters, since otherwise the `event_base` in | 
|  | // question will be deleted before the LibeventQuicEventLoop object referencing | 
|  | // it. | 
|  | class QUICHE_EXPORT LibeventQuicEventLoopWithOwnership | 
|  | : public LibeventLoop, | 
|  | public LibeventQuicEventLoop { | 
|  | public: | 
|  | static std::unique_ptr<LibeventQuicEventLoopWithOwnership> Create( | 
|  | QuicClock* clock, bool force_level_triggered = false); | 
|  |  | 
|  | // Takes ownership of |base|. | 
|  | explicit LibeventQuicEventLoopWithOwnership(struct event_base* base, | 
|  | QuicClock* clock) | 
|  | : LibeventLoop(base), LibeventQuicEventLoop(base, clock) {} | 
|  | }; | 
|  |  | 
|  | class QUICHE_EXPORT QuicLibeventEventLoopFactory : public QuicEventLoopFactory { | 
|  | public: | 
|  | // Provides the preferred libevent backend. | 
|  | static QuicLibeventEventLoopFactory* Get() { | 
|  | static QuicLibeventEventLoopFactory* factory = | 
|  | new QuicLibeventEventLoopFactory(/*force_level_triggered=*/false); | 
|  | return factory; | 
|  | } | 
|  |  | 
|  | // Provides the libevent backend that does not support edge-triggered | 
|  | // notifications.  Those are useful for tests, since we can test | 
|  | // level-triggered I/O even on platforms where edge-triggered is the default. | 
|  | static QuicLibeventEventLoopFactory* GetLevelTriggeredBackendForTests() { | 
|  | static QuicLibeventEventLoopFactory* factory = | 
|  | new QuicLibeventEventLoopFactory(/*force_level_triggered=*/true); | 
|  | return factory; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<QuicEventLoop> Create(QuicClock* clock) override { | 
|  | return LibeventQuicEventLoopWithOwnership::Create(clock, | 
|  | force_level_triggered_); | 
|  | } | 
|  | std::string GetName() const override { return name_; } | 
|  |  | 
|  | private: | 
|  | explicit QuicLibeventEventLoopFactory(bool force_level_triggered); | 
|  |  | 
|  | bool force_level_triggered_; | 
|  | std::string name_; | 
|  | }; | 
|  |  | 
|  | }  // namespace quic | 
|  |  | 
|  | #endif  // QUICHE_QUIC_BINDINGS_QUIC_LIBEVENT_H_ |