Path: blob/main/devices/src/usb/xhci/ring_buffer_stop_cb.rs
5394 views
// Copyright 2019 The ChromiumOS Authors1// Use of this source code is governed by a BSD-style license that can be2// found in the LICENSE file.34use std::sync::Arc;5use std::sync::Mutex;67use base::error;89use crate::utils::FailHandle;1011/// RingBufferStopCallback wraps a callback. The callback will be invoked when last instance of12/// RingBufferStopCallback and its clones is dropped.13///14/// The callback might not be invoked in certain cases. Don't depend this for safety.15#[derive(Clone)]16pub struct RingBufferStopCallback {17_inner: Arc<Mutex<RingBufferStopCallbackInner>>,18}1920impl RingBufferStopCallback {21/// Create new callback from closure.22pub fn new<C: 'static + FnMut() + Send>(cb: C) -> RingBufferStopCallback {23RingBufferStopCallback {24_inner: Arc::new(Mutex::new(RingBufferStopCallbackInner {25callback: Box::new(cb),26})),27}28}29}3031struct RingBufferStopCallbackInner {32callback: Box<dyn FnMut() + Send>,33}3435impl Drop for RingBufferStopCallbackInner {36fn drop(&mut self) {37(self.callback)();38}39}4041/// Helper function to wrap up a closure with fail handle. The fail handle will be triggered if the42/// closure returns an error.43pub fn fallible_closure<E: std::fmt::Display, C: FnMut() -> Result<(), E> + 'static + Send>(44fail_handle: Arc<dyn FailHandle>,45mut callback: C,46) -> impl FnMut() + 'static + Send {47move || match callback() {48Ok(()) => {}49Err(e) => {50error!("callback failed {}", e);51fail_handle.fail();52}53}54}5556#[cfg(test)]57mod tests {58use std::sync::Arc;59use std::sync::Mutex;6061use super::*;6263fn task(_: RingBufferStopCallback) {}6465#[test]66fn simple_raii_callback() {67let a = Arc::new(Mutex::new(0));68let ac = a.clone();69let cb = RingBufferStopCallback::new(move || {70*ac.lock().unwrap() = 1;71});72task(cb.clone());73task(cb.clone());74task(cb);75assert_eq!(*a.lock().unwrap(), 1);76}77}787980