Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/devices/src/usb/xhci/ring_buffer_stop_cb.rs
5394 views
1
// Copyright 2019 The ChromiumOS Authors
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
use std::sync::Arc;
6
use std::sync::Mutex;
7
8
use base::error;
9
10
use crate::utils::FailHandle;
11
12
/// RingBufferStopCallback wraps a callback. The callback will be invoked when last instance of
13
/// RingBufferStopCallback and its clones is dropped.
14
///
15
/// The callback might not be invoked in certain cases. Don't depend this for safety.
16
#[derive(Clone)]
17
pub struct RingBufferStopCallback {
18
_inner: Arc<Mutex<RingBufferStopCallbackInner>>,
19
}
20
21
impl RingBufferStopCallback {
22
/// Create new callback from closure.
23
pub fn new<C: 'static + FnMut() + Send>(cb: C) -> RingBufferStopCallback {
24
RingBufferStopCallback {
25
_inner: Arc::new(Mutex::new(RingBufferStopCallbackInner {
26
callback: Box::new(cb),
27
})),
28
}
29
}
30
}
31
32
struct RingBufferStopCallbackInner {
33
callback: Box<dyn FnMut() + Send>,
34
}
35
36
impl Drop for RingBufferStopCallbackInner {
37
fn drop(&mut self) {
38
(self.callback)();
39
}
40
}
41
42
/// Helper function to wrap up a closure with fail handle. The fail handle will be triggered if the
43
/// closure returns an error.
44
pub fn fallible_closure<E: std::fmt::Display, C: FnMut() -> Result<(), E> + 'static + Send>(
45
fail_handle: Arc<dyn FailHandle>,
46
mut callback: C,
47
) -> impl FnMut() + 'static + Send {
48
move || match callback() {
49
Ok(()) => {}
50
Err(e) => {
51
error!("callback failed {}", e);
52
fail_handle.fail();
53
}
54
}
55
}
56
57
#[cfg(test)]
58
mod tests {
59
use std::sync::Arc;
60
use std::sync::Mutex;
61
62
use super::*;
63
64
fn task(_: RingBufferStopCallback) {}
65
66
#[test]
67
fn simple_raii_callback() {
68
let a = Arc::new(Mutex::new(0));
69
let ac = a.clone();
70
let cb = RingBufferStopCallback::new(move || {
71
*ac.lock().unwrap() = 1;
72
});
73
task(cb.clone());
74
task(cb.clone());
75
task(cb);
76
assert_eq!(*a.lock().unwrap(), 1);
77
}
78
}
79
80