| // 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 "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 { | 
 |  | 
 | // 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); | 
 |  | 
 |   // 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: | 
 |   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 ArtificiallyNotify(QuicSocketEventMask events); | 
 |     void Rearm(QuicSocketEventMask events); | 
 |  | 
 |    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_; | 
 |   }; | 
 |  | 
 |   using RegistrationMap = absl::node_hash_map<QuicUdpSocketFd, Registration>; | 
 |  | 
 |   event_base* base_; | 
 |   const bool edge_triggered_; | 
 |   QuicClock* clock_; | 
 |  | 
 |   RegistrationMap registration_map_; | 
 | }; | 
 |  | 
 | // 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_ |