Skip to content

Commit 0fc1879

Browse files
mariusaemeta-codesync[bot]
authored andcommitted
monomorphize QUIC packet send slots (#4812)
Summary: Pull Request resolved: #4812 Make `PacketIo` expose its borrowed send slot through a generic associated type, and make `Endpoint` retain its concrete packet I/O type. This removes the per-batch `Box<dyn PacketSendSlot>` allocation and virtual dispatch while preserving driver-owned slot lifetimes. Reviewed By: shayne-fletcher Differential Revision: D117573677
1 parent 7193dc2 commit 0fc1879

6 files changed

Lines changed: 58 additions & 61 deletions

File tree

‎chrysalis-transport-quiche/src/driver.rs‎

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ use crate::command::EndpointCommands;
150150
use crate::identity::EndpointIdentity;
151151
use crate::identity::certificate_pid;
152152
use crate::io::PacketIo;
153+
use crate::io::PacketSendSlot;
153154

154155
mod connection;
155156
mod network;
@@ -461,9 +462,9 @@ fn complete_unknown(submission: Submission, completions: &mut Vec<Completion>) {
461462
}
462463

463464
/// Single-owner quiche endpoint state machine.
464-
pub struct Endpoint {
465+
pub struct Endpoint<I> {
465466
driver: DriverId,
466-
io: Box<dyn PacketIo>,
467+
io: I,
467468
network: Network,
468469
submission_queue: EndpointSubmissionReceiver<EndpointCommand>,
469470
completion_sender: CompletionSender,
@@ -481,9 +482,9 @@ pub struct Endpoint {
481482
next_statistics_update: Instant,
482483
}
483484

484-
impl Endpoint {
485+
impl<I: PacketIo> Endpoint<I> {
485486
/// Constructs a client endpoint and its thread-safe application handles.
486-
pub fn client<I: PacketIo + 'static>(
487+
pub fn client(
487488
driver: DriverId,
488489
io: I,
489490
identity: EndpointIdentity,
@@ -507,7 +508,7 @@ impl Endpoint {
507508
}
508509

509510
/// Constructs a client endpoint with explicit admission limits.
510-
pub fn client_with_limits<I: PacketIo + 'static>(
511+
pub fn client_with_limits(
511512
driver: DriverId,
512513
io: I,
513514
identity: EndpointIdentity,
@@ -532,7 +533,7 @@ impl Endpoint {
532533
}
533534

534535
/// Constructs a server endpoint and its thread-safe application handles.
535-
pub fn server<I: PacketIo + 'static>(
536+
pub fn server(
536537
driver: DriverId,
537538
io: I,
538539
identity: EndpointIdentity,
@@ -556,7 +557,7 @@ impl Endpoint {
556557
}
557558

558559
/// Constructs a server endpoint with explicit admission limits.
559-
pub fn server_with_limits<I: PacketIo + 'static>(
560+
pub fn server_with_limits(
560561
driver: DriverId,
561562
io: I,
562563
identity: EndpointIdentity,
@@ -581,7 +582,7 @@ impl Endpoint {
581582
}
582583

583584
/// Constructs a duplex endpoint that can initiate and accept connections.
584-
pub fn duplex<I: PacketIo + 'static>(
585+
pub fn duplex(
585586
driver: DriverId,
586587
io: I,
587588
identity: EndpointIdentity,
@@ -606,7 +607,7 @@ impl Endpoint {
606607
}
607608

608609
/// Constructs a duplex endpoint with explicit admission limits.
609-
pub fn duplex_with_limits<I: PacketIo + 'static>(
610+
pub fn duplex_with_limits(
610611
driver: DriverId,
611612
io: I,
612613
identity: EndpointIdentity,
@@ -633,7 +634,7 @@ impl Endpoint {
633634
}
634635

635636
/// Constructs a duplex endpoint whose CIDs use `routing_pid` independently of its identity.
636-
pub fn duplex_routed<I: PacketIo + 'static>(
637+
pub fn duplex_routed(
637638
driver: DriverId,
638639
io: I,
639640
identity: EndpointIdentity,
@@ -659,7 +660,7 @@ impl Endpoint {
659660
}
660661

661662
/// Constructs a routed duplex endpoint with explicit admission limits.
662-
pub fn duplex_routed_with_limits<I: PacketIo + 'static>(
663+
pub fn duplex_routed_with_limits(
663664
driver: DriverId,
664665
io: I,
665666
identity: EndpointIdentity,
@@ -684,7 +685,7 @@ impl Endpoint {
684685
)
685686
}
686687

687-
fn new<I: PacketIo + 'static>(
688+
fn new(
688689
driver: DriverId,
689690
io: I,
690691
_identity: EndpointIdentity,
@@ -717,7 +718,7 @@ impl Endpoint {
717718
(
718719
Self {
719720
driver,
720-
io: Box::new(io),
721+
io,
721722
network: Network::new(
722723
driver,
723724
routing_pid,
@@ -836,7 +837,7 @@ impl Endpoint {
836837
}
837838
self.flush_completions();
838839
self.network
839-
.queue_packets(self.io.as_mut(), &mut self.new_completions)?;
840+
.queue_packets(&mut self.io, &mut self.new_completions)?;
840841

841842
let mut wait = self.network.next_timeout(maximum_wait);
842843
if let Some(deadline) = self.shutdown_deadline {
@@ -850,7 +851,7 @@ impl Endpoint {
850851
self.update_statistics();
851852
self.expire_shutdown();
852853
self.network
853-
.queue_packets(self.io.as_mut(), &mut self.new_completions)?;
854+
.queue_packets(&mut self.io, &mut self.new_completions)?;
854855
self.stage_completions();
855856
self.flush_completions();
856857
self.finish_shutdown_if_ready();

‎chrysalis-transport-quiche/src/driver/network.rs‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
use super::connection::ConnectionState;
1010
use super::*;
11+
use crate::io::PacketSendSlot;
1112

1213
pub(super) struct Network {
1314
driver: DriverId,
@@ -372,9 +373,9 @@ impl Network {
372373
.saturating_sub(established_servers);
373374
}
374375

375-
pub(super) fn queue_packets(
376+
pub(super) fn queue_packets<I: PacketIo>(
376377
&mut self,
377-
io: &mut dyn PacketIo,
378+
io: &mut I,
378379
_completions: &mut Vec<Completion>,
379380
) -> Result<(), Error> {
380381
let segment_size = io.segment_size();

‎chrysalis-transport-quiche/src/driver/tests.rs‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,8 @@ fn drain(handle: &EndpointHandle, events: &mut Vec<Completion>) {
9999
}
100100

101101
fn drive_until(
102-
client: &mut Endpoint,
103-
server: &mut Endpoint,
102+
client: &mut Endpoint<UdpDriver>,
103+
server: &mut Endpoint<UdpDriver>,
104104
client_handle: &EndpointHandle,
105105
server_handle: &EndpointHandle,
106106
client_events: &mut Vec<Completion>,
@@ -118,9 +118,9 @@ fn drive_until(
118118
}
119119

120120
fn endpoint_pair() -> (
121-
Endpoint,
121+
Endpoint<UdpDriver>,
122122
EndpointHandle,
123-
Endpoint,
123+
Endpoint<UdpDriver>,
124124
EndpointHandle,
125125
std::net::SocketAddr,
126126
Pid,
@@ -131,9 +131,9 @@ fn endpoint_pair() -> (
131131
fn endpoint_pair_with_completion_capacity(
132132
completion_capacity: usize,
133133
) -> (
134-
Endpoint,
134+
Endpoint<UdpDriver>,
135135
EndpointHandle,
136-
Endpoint,
136+
Endpoint<UdpDriver>,
137137
EndpointHandle,
138138
std::net::SocketAddr,
139139
Pid,

‎chrysalis-transport-quiche/src/io.rs‎

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,16 @@ pub trait PacketSendSlot {
3535
fn buffer_mut(&mut self) -> &mut [u8];
3636

3737
/// Queues the initialized prefix for transmission.
38-
fn submit(
39-
self: Box<Self>,
40-
length: usize,
41-
destination: SocketAddr,
42-
send_at: Instant,
43-
) -> io::Result<()>;
38+
fn submit(self, length: usize, destination: SocketAddr, send_at: Instant) -> io::Result<()>;
4439
}
4540

4641
/// Runtime-neutral packet I/O consumed by one quiche endpoint thread.
4742
pub trait PacketIo: Send {
43+
/// Driver-owned transmit allocation borrowed by [`Self::try_send_slot`].
44+
type SendSlot<'a>: PacketSendSlot
45+
where
46+
Self: 'a;
47+
4848
/// Returns whether an authenticated upstream boundary validated source addresses.
4949
fn peer_addresses_validated(&self) -> bool {
5050
false
@@ -63,7 +63,7 @@ pub trait PacketIo: Send {
6363
fn notifier(&self) -> Arc<dyn Notifier>;
6464

6565
/// Borrows a free transmit allocation.
66-
fn try_send_slot(&mut self) -> Option<Box<dyn PacketSendSlot + '_>>;
66+
fn try_send_slot(&mut self) -> Option<Self::SendSlot<'_>>;
6767

6868
/// Waits for packet I/O, pacing, or an application notification.
6969
fn poll(&mut self, timeout: Duration) -> io::Result<()>;
@@ -78,25 +78,19 @@ pub trait PacketIo: Send {
7878
) -> Result<(), Error>;
7979
}
8080

81-
struct UringSendSlot<'a>(SendSlot<'a>);
82-
83-
impl PacketSendSlot for UringSendSlot<'_> {
81+
impl PacketSendSlot for SendSlot<'_> {
8482
fn buffer_mut(&mut self) -> &mut [u8] {
85-
self.0.buffer_mut()
83+
SendSlot::buffer_mut(self)
8684
}
8785

88-
fn submit(
89-
self: Box<Self>,
90-
length: usize,
91-
destination: SocketAddr,
92-
send_at: Instant,
93-
) -> io::Result<()> {
94-
let Self(slot) = *self;
95-
slot.submit(length, destination, send_at)
86+
fn submit(self, length: usize, destination: SocketAddr, send_at: Instant) -> io::Result<()> {
87+
SendSlot::submit(self, length, destination, send_at)
9688
}
9789
}
9890

9991
impl PacketIo for UdpDriver {
92+
type SendSlot<'a> = SendSlot<'a>;
93+
10094
fn local_addr(&self) -> io::Result<SocketAddr> {
10195
UdpDriver::local_addr(self)
10296
}
@@ -113,9 +107,8 @@ impl PacketIo for UdpDriver {
113107
Arc::new(UdpDriver::notifier(self))
114108
}
115109

116-
fn try_send_slot(&mut self) -> Option<Box<dyn PacketSendSlot + '_>> {
110+
fn try_send_slot(&mut self) -> Option<Self::SendSlot<'_>> {
117111
UdpDriver::try_send_slot(self)
118-
.map(|slot| Box::new(UringSendSlot(slot)) as Box<dyn PacketSendSlot>)
119112
}
120113

121114
fn poll(&mut self, timeout: Duration) -> io::Result<()> {

‎chrysalis-transport-tokio/src/lib.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -685,9 +685,9 @@ impl Transport {
685685
)
686686
}
687687

688-
fn spawn(
688+
fn spawn<I: PacketIo + 'static>(
689689
pid: Pid,
690-
mut endpoint: Endpoint,
690+
mut endpoint: Endpoint<I>,
691691
handle: EndpointHandle,
692692
notifier: Arc<TokioNotifier>,
693693
completion_capacity: NonZeroUsize,

‎chrysalis-transport/src/packet_io.rs‎

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,7 @@ impl RoutedUdpPacketIo {
632632
}
633633
}
634634

635-
struct RoutedUdpSendSlot<'a> {
635+
pub(crate) struct RoutedUdpSendSlot<'a> {
636636
slot: Option<SendSlot<'a>>,
637637
router: &'a Router,
638638
addresses: &'a CarrierAddressBook,
@@ -649,12 +649,7 @@ impl PacketSendSlot for RoutedUdpSendSlot<'_> {
649649
.buffer_mut()
650650
}
651651

652-
fn submit(
653-
mut self: Box<Self>,
654-
length: usize,
655-
peer: SocketAddr,
656-
send_at: Instant,
657-
) -> io::Result<()> {
652+
fn submit(mut self, length: usize, peer: SocketAddr, send_at: Instant) -> io::Result<()> {
658653
let mut slot = self
659654
.slot
660655
.take()
@@ -719,6 +714,8 @@ impl PacketSendSlot for RoutedUdpSendSlot<'_> {
719714
}
720715

721716
impl PacketIo for RoutedUdpPacketIo {
717+
type SendSlot<'a> = RoutedUdpSendSlot<'a>;
718+
722719
fn peer_addresses_validated(&self) -> bool {
723720
false
724721
}
@@ -739,21 +736,21 @@ impl PacketIo for RoutedUdpPacketIo {
739736
self.wake.clone()
740737
}
741738

742-
fn try_send_slot(&mut self) -> Option<Box<dyn PacketSendSlot + '_>> {
739+
fn try_send_slot(&mut self) -> Option<Self::SendSlot<'_>> {
743740
let router = self.router.as_ref();
744741
let addresses = &self.addresses;
745742
let fallback = self.fallback.as_deref();
746743
let fallback_transmits = &mut self.fallback_transmits;
747744
let segment_size = self.segment_size;
748745
let slot = self.udp.try_send_slot()?;
749-
Some(Box::new(RoutedUdpSendSlot {
746+
Some(RoutedUdpSendSlot {
750747
slot: Some(slot),
751748
router,
752749
addresses,
753750
fallback,
754751
fallback_transmits,
755752
segment_size,
756-
}))
753+
})
757754
}
758755

759756
fn poll(&mut self, timeout: Duration) -> io::Result<()> {
@@ -1106,7 +1103,7 @@ impl<T: DatagramSocket> CarrierPacketIo<T> {
11061103
}
11071104
}
11081105

1109-
struct CarrierSendSlot<'a, T> {
1106+
pub(crate) struct CarrierSendSlot<'a, T> {
11101107
io: &'a mut CarrierPacketIo<T>,
11111108
buffer: Option<Vec<u8>>,
11121109
}
@@ -1119,7 +1116,7 @@ impl<T> PacketSendSlot for CarrierSendSlot<'_, T> {
11191116
}
11201117

11211118
fn submit(
1122-
mut self: Box<Self>,
1119+
mut self,
11231120
length: usize,
11241121
destination: SocketAddr,
11251122
send_at: Instant,
@@ -1161,6 +1158,11 @@ impl<T> Drop for CarrierSendSlot<'_, T> {
11611158
}
11621159

11631160
impl<T: DatagramSocket> PacketIo for CarrierPacketIo<T> {
1161+
type SendSlot<'a>
1162+
= CarrierSendSlot<'a, T>
1163+
where
1164+
T: 'a;
1165+
11641166
fn local_addr(&self) -> io::Result<SocketAddr> {
11651167
Ok(self.local)
11661168
}
@@ -1177,12 +1179,12 @@ impl<T: DatagramSocket> PacketIo for CarrierPacketIo<T> {
11771179
self.wake.clone()
11781180
}
11791181

1180-
fn try_send_slot(&mut self) -> Option<Box<dyn PacketSendSlot + '_>> {
1182+
fn try_send_slot(&mut self) -> Option<Self::SendSlot<'_>> {
11811183
let buffer = self.free_transmit.pop()?;
1182-
Some(Box::new(CarrierSendSlot {
1184+
Some(CarrierSendSlot {
11831185
io: self,
11841186
buffer: Some(buffer),
1185-
}))
1187+
})
11861188
}
11871189

11881190
fn poll(&mut self, timeout: Duration) -> io::Result<()> {

0 commit comments

Comments
 (0)