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