blob: 82783e9a1cddeec6dbc6d3423ba7ae89b7a85b9e [file] [log] [blame]
// 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.
#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 {
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_; }
class AlarmFactory : public QuicAlarmFactory {
AlarmFactory(LibeventQuicEventLoop* loop) : loop_(loop) {}
// QuicAlarmFactory interface.
QuicAlarm* CreateAlarm(QuicAlarm::Delegate* delegate) override;
QuicArenaScopedPtr<QuicAlarm> CreateAlarm(
QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
QuicConnectionArena* arena) override;
LibeventQuicEventLoop* loop_;
class Registration {
Registration(LibeventQuicEventLoop* loop, QuicUdpSocketFd fd,
QuicSocketEventMask events, QuicSocketEventListener* listener);
void ArtificiallyNotify(QuicSocketEventMask events);
void Rearm(QuicSocketEventMask events);
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 {
LibeventLoop(struct event_base* base) : event_base_(base) {}
~LibeventLoop() { event_base_free(event_base_); }
struct event_base* event_base() { return event_base_; }
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 {
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 {
// 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,
std::string GetName() const override { return name_; }
explicit QuicLibeventEventLoopFactory(bool force_level_triggered);
bool force_level_triggered_;
std::string name_;
} // namespace quic