blob: b06ab4ec2d562ce1dc5c2fdf2adc9c787b3d0629 [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.
#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_