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