1use derivative::Derivative;
8use netstack3_sync::Mutex;
9use netstack3_sync::atomic::{AtomicIsize, Ordering};
10
11use crate::BindingsSyncTypes;
12use crate::num::PositiveIsize;
13
14#[derive(Derivative)]
16#[derivative(Debug(bound = "L: core::fmt::Debug"))]
17pub struct SendBufferTracking<L, BT: BindingsSyncTypes> {
18 available_bytes: AtomicIsize,
26 inner: Mutex<Inner<L>, BT::Mutex>,
27}
28
29impl<L, BT: BindingsSyncTypes> SendBufferTracking<L, BT> {
30 pub fn new(capacity: PositiveIsize, listener: L) -> Self {
33 Self {
34 available_bytes: AtomicIsize::new(capacity.into()),
35 inner: Mutex::new(Inner {
36 listener,
37 notified_state: true,
40 capacity,
41 }),
42 }
43 }
44
45 #[cfg(any(test, feature = "testutils"))]
47 pub fn with_listener<R, F: FnOnce(&mut L) -> R>(&self, f: F) -> R {
48 f(&mut self.inner.lock().listener)
49 }
50}
51
52impl<L: SocketWritableListener, BT: BindingsSyncTypes> SendBufferTracking<L, BT> {
53 pub fn acquire(&self, bytes: PositiveIsize) -> Result<SendBufferSpace, SendBufferFullError> {
55 let bytes_isize = bytes.into();
56 let prev = self.available_bytes.fetch_sub(bytes_isize, Ordering::Acquire);
58 if prev > bytes_isize {
60 return Ok(SendBufferSpace(bytes));
61 }
62 if prev <= 0 {
69 self.return_and_notify(bytes_isize);
70 return Err(SendBufferFullError);
71 }
72
73 self.notify();
76 Ok(SendBufferSpace(bytes))
77 }
78
79 pub fn release(&self, space: SendBufferSpace) {
81 let SendBufferSpace(delta) = &space;
82 self.return_and_notify((*delta).into());
83 core::mem::forget(space);
85 }
86
87 fn return_and_notify(&self, delta: isize) {
88 let prev = self.available_bytes.fetch_add(delta, Ordering::Release);
90 if prev <= 0 && prev + delta > 0 {
91 self.notify();
92 }
93 }
94
95 fn notify(&self) {
96 let Self { available_bytes, inner } = self;
97 let mut inner = inner.lock();
98 Self::notify_locked(available_bytes, &mut inner);
99 }
100
101 fn notify_locked(available_bytes: &AtomicIsize, inner: &mut Inner<L>) {
102 let Inner { listener, notified_state, capacity: _ } = inner;
103 let new_writable = available_bytes.load(Ordering::Relaxed) > 0;
107 if core::mem::replace(notified_state, new_writable) != new_writable {
108 listener.on_writable_changed(new_writable);
109 }
110 }
111
112 pub fn capacity(&self) -> PositiveIsize {
114 self.inner.lock().capacity
115 }
116
117 pub fn available(&self) -> Option<PositiveIsize> {
119 PositiveIsize::new(self.available_bytes.load(Ordering::Relaxed))
120 }
121
122 pub fn set_capacity(&self, new_capacity: PositiveIsize) {
127 let Self { available_bytes, inner } = self;
128 let mut inner = inner.lock();
129 let Inner { listener: _, notified_state: _, capacity } = &mut *inner;
130 let old = core::mem::replace(capacity, new_capacity);
131 let delta = new_capacity.get() - old.get();
132 let _: isize = available_bytes.fetch_add(delta, Ordering::AcqRel);
135 Self::notify_locked(available_bytes, &mut inner);
138 }
139}
140
141#[derive(Debug)]
142struct Inner<L> {
143 listener: L,
144 notified_state: bool,
166 capacity: PositiveIsize,
172}
173
174#[derive(Debug, Eq, PartialEq)]
182pub struct SendBufferSpace(PositiveIsize);
183
184impl Drop for SendBufferSpace {
185 fn drop(&mut self) {
186 panic!("dropped send buffer space with {:?} bytes", self)
187 }
188}
189
190impl SendBufferSpace {
191 pub fn acknowledge_drop(self) {
196 core::mem::forget(self)
197 }
198}
199
200#[derive(Debug, Eq, PartialEq)]
202pub struct SendBufferFullError;
203
204pub trait SocketWritableListener {
208 fn on_writable_changed(&mut self, writable: bool);
214}
215
216#[cfg(any(test, feature = "testutils"))]
217pub(crate) mod testutil {
218 use super::*;
219
220 #[derive(Debug)]
222 pub struct FakeSocketWritableListener {
223 writable: bool,
224 }
225
226 impl FakeSocketWritableListener {
227 pub fn is_writable(&self) -> bool {
229 self.writable
230 }
231 }
232
233 impl Default for FakeSocketWritableListener {
234 fn default() -> Self {
235 Self { writable: true }
236 }
237 }
238
239 impl SocketWritableListener for FakeSocketWritableListener {
240 fn on_writable_changed(&mut self, writable: bool) {
241 assert_ne!(core::mem::replace(&mut self.writable, writable), writable);
242 }
243 }
244}
245
246#[cfg(test)]
247mod tests {
248 use super::*;
249 use crate::testutil::FakeBindingsCtx;
250 use testutil::FakeSocketWritableListener;
251
252 use alloc::vec::Vec;
253
254 type SendBufferTracking<L> = super::SendBufferTracking<L, FakeBindingsCtx<(), (), (), ()>>;
255
256 const SNDBUF: PositiveIsize = PositiveIsize::new(4).unwrap();
257 const HALF_SNDBUF: PositiveIsize = PositiveIsize::new(SNDBUF.get() / 2).unwrap();
258 const TWO_SNDBUF: PositiveIsize = PositiveIsize::new(SNDBUF.get() * 2).unwrap();
259 const ONE: PositiveIsize = PositiveIsize::new(1).unwrap();
260
261 impl SendBufferTracking<FakeSocketWritableListener> {
262 fn listener_writable(&self) -> bool {
263 self.inner.lock().listener.is_writable()
264 }
265 }
266
267 #[test]
268 fn acquire_all_buffer() {
269 let tracking = SendBufferTracking::new(SNDBUF, FakeSocketWritableListener::default());
270 let acquired = tracking.acquire(SNDBUF).expect("acquire");
271 assert_eq!(tracking.available_bytes.load(Ordering::SeqCst), 0);
272 assert_eq!(tracking.listener_writable(), false);
273 assert_eq!(tracking.acquire(ONE), Err(SendBufferFullError));
274 tracking.release(acquired);
275 assert_eq!(tracking.listener_writable(), true);
276 assert_eq!(tracking.available_bytes.load(Ordering::SeqCst), SNDBUF.get());
277 }
278
279 #[test]
280 fn acquire_half_buffer() {
281 let tracking = SendBufferTracking::new(SNDBUF, FakeSocketWritableListener::default());
282 let acquired = tracking.acquire(HALF_SNDBUF).expect("acquire");
283 assert_eq!(
284 tracking.available_bytes.load(Ordering::SeqCst),
285 SNDBUF.get() - HALF_SNDBUF.get()
286 );
287 assert_eq!(tracking.listener_writable(), true);
288 tracking.release(acquired);
289 assert_eq!(tracking.listener_writable(), true);
290 assert_eq!(tracking.available_bytes.load(Ordering::SeqCst), SNDBUF.get());
291 }
292
293 #[test]
294 fn acquire_multiple() {
295 let tracking = SendBufferTracking::new(SNDBUF, FakeSocketWritableListener::default());
296 let tokens = (0..SNDBUF.get())
297 .map(|_| {
298 assert_eq!(tracking.listener_writable(), true);
299 tracking.acquire(ONE).expect("acquire")
300 })
301 .collect::<Vec<_>>();
302 assert_eq!(tracking.available_bytes.load(Ordering::SeqCst), 0);
303 assert_eq!(tracking.listener_writable(), false);
304
305 assert_eq!(tracking.acquire(ONE), Err(SendBufferFullError));
306 for t in tokens {
307 tracking.release(t);
308 assert_eq!(tracking.listener_writable(), true);
309 }
310
311 assert_eq!(tracking.available_bytes.load(Ordering::SeqCst), SNDBUF.get());
312 assert_eq!(tracking.listener_writable(), true);
313 }
314
315 #[test]
316 fn overcommit_single_buffer() {
317 let tracking = SendBufferTracking::new(SNDBUF, FakeSocketWritableListener::default());
318 let acquired = tracking.acquire(TWO_SNDBUF).expect("acquire");
319 assert_eq!(tracking.listener_writable(), false);
320 assert_eq!(
321 tracking.available_bytes.load(Ordering::SeqCst),
322 SNDBUF.get() - TWO_SNDBUF.get()
323 );
324 assert_eq!(tracking.acquire(ONE), Err(SendBufferFullError));
325
326 tracking.release(acquired);
327 assert_eq!(tracking.listener_writable(), true);
328 assert_eq!(tracking.available_bytes.load(Ordering::SeqCst), SNDBUF.get());
329 }
330
331 #[test]
332 fn overcommit_two_buffers() {
333 let tracking = SendBufferTracking::new(SNDBUF, FakeSocketWritableListener::default());
334 let acquired1 = tracking.acquire(ONE).expect("acquire");
335 assert_eq!(tracking.listener_writable(), true);
336 assert_eq!(tracking.available_bytes.load(Ordering::SeqCst), SNDBUF.get() - 1);
337 let acquired2 = tracking.acquire(SNDBUF).expect("acquire");
338 assert_eq!(tracking.listener_writable(), false);
339 assert_eq!(tracking.available_bytes.load(Ordering::SeqCst), -1);
340 assert_eq!(tracking.acquire(ONE), Err(SendBufferFullError));
341
342 tracking.release(acquired1);
343 assert_eq!(tracking.listener_writable(), false);
345 assert_eq!(tracking.available_bytes.load(Ordering::SeqCst), 0);
346
347 tracking.release(acquired2);
348 assert_eq!(tracking.listener_writable(), true);
349 assert_eq!(tracking.available_bytes.load(Ordering::SeqCst), SNDBUF.get());
350 }
351
352 #[test]
353 fn capacity_increase_makes_writable() {
354 let tracking = SendBufferTracking::new(SNDBUF, FakeSocketWritableListener::default());
355 assert_eq!(tracking.capacity(), SNDBUF);
356 let acquired = tracking.acquire(SNDBUF).expect("acquire");
357 assert_eq!(tracking.listener_writable(), false);
358
359 tracking.set_capacity(TWO_SNDBUF);
360 assert_eq!(tracking.listener_writable(), true);
361 assert_eq!(
362 tracking.available_bytes.load(Ordering::SeqCst),
363 TWO_SNDBUF.get() - SNDBUF.get()
364 );
365 assert_eq!(tracking.capacity(), TWO_SNDBUF);
366 tracking.release(acquired);
367 }
368
369 #[test]
370 fn capacity_decrease_makes_non_writable() {
371 let tracking = SendBufferTracking::new(SNDBUF, FakeSocketWritableListener::default());
372 assert_eq!(tracking.capacity(), SNDBUF);
373 let acquired = tracking.acquire(HALF_SNDBUF).expect("acquire");
374 assert_eq!(tracking.listener_writable(), true);
375
376 tracking.set_capacity(HALF_SNDBUF);
377 assert_eq!(tracking.listener_writable(), false);
378 assert_eq!(tracking.available_bytes.load(Ordering::SeqCst), 0);
379 assert_eq!(tracking.capacity(), HALF_SNDBUF);
380 tracking.release(acquired);
381 assert_eq!(tracking.listener_writable(), true);
382 assert_eq!(tracking.available_bytes.load(Ordering::SeqCst), HALF_SNDBUF.get());
383 }
384}