dope_core/driver/
control.rs1use std::io;
2use std::os::fd::BorrowedFd;
3
4use crate::backend::Backend;
5use crate::backend::ops::raw::control::{ControlBackend, RawQuiesce};
6use crate::io::fd::Fd;
7use crate::io::socket::option::SocketOption;
8
9use super::token::Token;
10use super::{DriverContext, OutboundReservation, PushError};
11
12#[doc(hidden)]
13#[must_use]
14pub struct Quiesce<'a> {
15 backend: &'a mut Backend,
16 state: RawQuiesce,
17 targets: bool,
18}
19
20#[doc(hidden)]
21#[must_use]
22pub struct QuiesceOutcome {
23 targets: bool,
24 poison: bool,
25}
26
27impl QuiesceOutcome {
28 pub fn has_targets(&self) -> bool {
29 self.targets
30 }
31
32 pub fn needs_poison(&self) -> bool {
33 self.poison
34 }
35}
36
37impl<'a> Quiesce<'a> {
38 fn new(backend: &'a mut Backend) -> Self {
39 Self {
40 backend,
41 state: <Backend as ControlBackend>::begin_quiesce(),
42 targets: false,
43 }
44 }
45
46 pub fn cancel(&mut self, target: Token) {
52 <Backend as ControlBackend>::quiesce_target(self.backend, &mut self.state, target);
53 self.targets = true;
54 }
55
56 pub fn finish(self) -> QuiesceOutcome {
57 QuiesceOutcome {
58 targets: self.targets,
59 poison: <Backend as ControlBackend>::finish_quiesce(self.backend, self.state),
60 }
61 }
62}
63
64pub trait ContextControl {
65 fn prepare_drop(&mut self);
66 fn register_shutdown_fd(&mut self, fd: BorrowedFd<'_>) -> io::Result<()>;
67 fn reserve_route(&mut self, id: u8) -> bool;
68 fn release_route(&mut self, id: u8);
69 fn poison_route(&mut self, id: u8);
70 fn quiesce(&mut self, targets: &[Token]) -> bool;
71 fn submit_option(
73 &mut self,
74 fd: &Fd<'_>,
75 option: impl Into<SocketOption>,
76 ) -> Result<(), PushError>;
77}
78
79impl ContextControl for DriverContext<'_, '_> {
80 fn prepare_drop(&mut self) {
81 <Backend as ControlBackend>::prepare_drop(self.backend());
82 }
83
84 fn register_shutdown_fd(&mut self, fd: BorrowedFd<'_>) -> io::Result<()> {
85 <Backend as ControlBackend>::register_shutdown_fd(self.backend(), fd)
86 }
87
88 fn reserve_route(&mut self, id: u8) -> bool {
89 <Backend as ControlBackend>::reserve_route(self.backend(), id)
90 }
91
92 fn release_route(&mut self, id: u8) {
93 <Backend as ControlBackend>::release_route(self.backend(), id);
94 }
95
96 fn poison_route(&mut self, id: u8) {
97 <Backend as ControlBackend>::poison_route(self.backend(), id);
98 }
99
100 fn quiesce(&mut self, targets: &[Token]) -> bool {
101 let mut quiesce = Quiesce::new(self.backend());
102 for target in targets {
103 quiesce.cancel(*target);
104 }
105 quiesce.finish().needs_poison()
106 }
107
108 fn submit_option(
109 &mut self,
110 fd: &Fd<'_>,
111 option: impl Into<SocketOption>,
112 ) -> Result<(), PushError> {
113 let option = option.into();
114 <Backend as ControlBackend>::submit_option(
115 self.backend(),
116 fd.slot(),
117 option.level(),
118 option.name(),
119 option.value(),
120 )
121 }
122}
123
124impl<'d> DriverContext<'_, 'd> {
125 #[doc(hidden)]
126 pub fn quiesce_batch(&mut self) -> Quiesce<'_> {
127 Quiesce::new(self.backend())
128 }
129
130 pub fn reserve_outbound(&mut self, count: u32) -> io::Result<OutboundReservation<'d>> {
131 let base = <Backend as ControlBackend>::reserve_outbound(self.backend(), count)?;
132 Ok(OutboundReservation::new(base, count))
133 }
134
135 #[doc(hidden)]
136 pub fn retire_outbound(&mut self, reservation: OutboundReservation<'d>) {
137 let (base, count) = reservation.into_range();
138 <Backend as ControlBackend>::retire_fixed(self.backend(), base, count);
139 }
140
141 #[doc(hidden)]
142 pub fn retire_fixed_fd(&mut self, fd: &mut Fd<'d>) {
143 let Some(slot) = fd.retire_slot(self.driver_ref()) else {
144 return;
145 };
146 self.backend().close_fd(slot);
147 <Backend as ControlBackend>::retire_fixed(self.backend(), slot.raw(), 1);
148 }
149}