devices/utils/
async_job_queue.rs

1// Copyright 2018 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
5use std::mem;
6use std::sync::Arc;
7
8use anyhow::Context;
9use base::Event;
10use base::EventType;
11use sync::Mutex;
12
13use super::Error;
14use super::EventHandler;
15use super::EventLoop;
16use super::Result;
17
18/// Async Job Queue can schedule async jobs.
19pub struct AsyncJobQueue {
20    jobs: Mutex<Vec<Box<dyn FnMut() + Send>>>,
21    evt: Event,
22}
23
24impl AsyncJobQueue {
25    /// Init job queue on event loop.
26    pub fn init(event_loop: &EventLoop) -> Result<Arc<AsyncJobQueue>> {
27        let evt = Event::new().map_err(Error::CreateEvent)?;
28        let queue = Arc::new(AsyncJobQueue {
29            jobs: Mutex::new(Vec::new()),
30            evt,
31        });
32        let handler: Arc<dyn EventHandler> = queue.clone();
33        event_loop.add_event(&queue.evt, EventType::Read, Arc::downgrade(&handler))?;
34        Ok(queue)
35    }
36
37    /// Queue a new job. It will be invoked on event loop.
38    pub fn queue_job<T: Fn() + 'static + Send>(&self, cb: T) -> Result<()> {
39        self.jobs.lock().push(Box::new(cb));
40        self.evt.signal().map_err(Error::WriteEvent)
41    }
42}
43
44impl EventHandler for AsyncJobQueue {
45    fn on_event(&self) -> anyhow::Result<()> {
46        // We want to read out the event.
47        self.evt.wait().context("read event failed")?;
48
49        let jobs = mem::take(&mut *self.jobs.lock());
50        for mut cb in jobs {
51            cb();
52        }
53        Ok(())
54    }
55}