| // 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() override; | |
| bool SupportsWakeUp() const override { return true; } | |
| 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_ |