blob: 0078eb6d1a7a24301ae7cc7e3370743237ccea63 [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 <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();
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_