summary refs log tree commit diff
path: root/devices/src/utils/async_job_queue.rs
diff options
context:
space:
mode:
authorJingkui Wang <jkwang@google.com>2019-03-07 13:43:33 -0800
committerchrome-bot <chrome-bot@chromium.org>2019-03-13 21:04:57 -0700
commit415ee63e043119aecdc2907d83f18a538698ad2d (patch)
tree22dc366816cac02349908e038d1e5a7c4ce4487e /devices/src/utils/async_job_queue.rs
parentea75bd164aedca9c429f1a9421ba944d8c786a50 (diff)
downloadcrosvm-415ee63e043119aecdc2907d83f18a538698ad2d.tar
crosvm-415ee63e043119aecdc2907d83f18a538698ad2d.tar.gz
crosvm-415ee63e043119aecdc2907d83f18a538698ad2d.tar.bz2
crosvm-415ee63e043119aecdc2907d83f18a538698ad2d.tar.lz
crosvm-415ee63e043119aecdc2907d83f18a538698ad2d.tar.xz
crosvm-415ee63e043119aecdc2907d83f18a538698ad2d.tar.zst
crosvm-415ee63e043119aecdc2907d83f18a538698ad2d.zip
add utils for device implementations
event_loop: event loop based on poll context.

async_job_queue: queue a job, it will be invoked on event loop. This
could be used to invoke a function without holding any locks.

BUG=chromium:831850
TEST=local build

Change-Id: Iab61ac43221bf5d635a0138073d7f88401e5ab07
Reviewed-on: https://chromium-review.googlesource.com/1509852
Commit-Ready: Jingkui Wang <jkwang@google.com>
Tested-by: Jingkui Wang <jkwang@google.com>
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Zach Reizner <zachr@chromium.org>
Diffstat (limited to 'devices/src/utils/async_job_queue.rs')
-rw-r--r--devices/src/utils/async_job_queue.rs60
1 files changed, 60 insertions, 0 deletions
diff --git a/devices/src/utils/async_job_queue.rs b/devices/src/utils/async_job_queue.rs
new file mode 100644
index 0000000..bc99c05
--- /dev/null
+++ b/devices/src/utils/async_job_queue.rs
@@ -0,0 +1,60 @@
+// Copyright 2018 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 super::{Error, Result};
+use super::{EventHandler, EventLoop};
+use std::mem;
+use std::os::unix::io::RawFd;
+use std::sync::Arc;
+use sync::Mutex;
+use sys_util::{EventFd, WatchingEvents};
+
+/// Async Job Queue can schedule async jobs.
+pub struct AsyncJobQueue {
+    jobs: Mutex<Vec<Box<FnMut() + 'static + Send>>>,
+    evt: EventFd,
+}
+
+impl AsyncJobQueue {
+    /// Init job queue on event loop.
+    pub fn init(event_loop: &EventLoop) -> Result<Arc<AsyncJobQueue>> {
+        let evt = EventFd::new().map_err(Error::CreateEventFd)?;
+        let queue = Arc::new(AsyncJobQueue {
+            jobs: Mutex::new(Vec::new()),
+            evt,
+        });
+        let handler: Arc<EventHandler> = queue.clone();
+        event_loop.add_event(
+            &queue.evt,
+            WatchingEvents::empty().set_read(),
+            Arc::downgrade(&handler),
+        );
+        Ok(queue)
+    }
+
+    /// Queue a new job. It will be invoked on event loop.
+    pub fn queue_job<T: Fn() + 'static + Send>(&self, cb: T) -> Result<()> {
+        self.jobs.lock().push(Box::new(cb));
+        self.evt.write(1).map_err(Error::WriteEventFd)
+    }
+}
+
+impl EventHandler for AsyncJobQueue {
+    fn on_event(&self, _fd: RawFd) -> std::result::Result<(), ()> {
+        // We want to read out the event, but the value is not important.
+        match self.evt.read() {
+            Ok(_) => {}
+            Err(e) => {
+                error!("read event fd failed {}", e);
+                return Err(());
+            }
+        }
+
+        let jobs = mem::replace(&mut *self.jobs.lock(), Vec::new());
+        for mut cb in jobs {
+            cb();
+        }
+        Ok(())
+    }
+}