summary refs log tree commit diff
path: root/devices/src/usb/xhci/ring_buffer_stop_cb.rs
diff options
context:
space:
mode:
Diffstat (limited to 'devices/src/usb/xhci/ring_buffer_stop_cb.rs')
-rw-r--r--devices/src/usb/xhci/ring_buffer_stop_cb.rs56
1 files changed, 56 insertions, 0 deletions
diff --git a/devices/src/usb/xhci/ring_buffer_stop_cb.rs b/devices/src/usb/xhci/ring_buffer_stop_cb.rs
new file mode 100644
index 0000000..29b3aa1
--- /dev/null
+++ b/devices/src/usb/xhci/ring_buffer_stop_cb.rs
@@ -0,0 +1,56 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::sync::{Arc, Mutex};
+
+/// RingBufferStopCallback wraps a callback. The callback will be invoked when last instance of
+/// RingBufferStopCallback and its clones is dropped.
+///
+/// The callback might not be invoked in certain cases. Don't depend this for safety.
+#[derive(Clone)]
+pub struct RingBufferStopCallback {
+    inner: Arc<Mutex<RingBufferStopCallbackInner>>,
+}
+
+impl RingBufferStopCallback {
+    /// Create new callback from closure.
+    pub fn new<C: 'static + FnMut() + Send>(cb: C) -> RingBufferStopCallback {
+        RingBufferStopCallback {
+            inner: Arc::new(Mutex::new(RingBufferStopCallbackInner {
+                callback: Box::new(cb),
+            })),
+        }
+    }
+}
+
+struct RingBufferStopCallbackInner {
+    callback: Box<FnMut() + Send>,
+}
+
+impl Drop for RingBufferStopCallbackInner {
+    fn drop(&mut self) {
+        (self.callback)();
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use std::sync::{Arc, Mutex};
+
+    fn task(_: RingBufferStopCallback) {}
+
+    #[test]
+    fn simple_raii_callback() {
+        let a = Arc::new(Mutex::new(0));
+        let ac = a.clone();
+        let cb = RingBufferStopCallback::new(move || {
+            *ac.lock().unwrap() = 1;
+        });
+        task(cb.clone());
+        task(cb.clone());
+        task(cb);
+        assert_eq!(*a.lock().unwrap(), 1);
+    }
+}