vfs/directory/watchers.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! Watchers handles a list of watcher connections attached to a directory. Watchers as described
//! in fuchsia.io.
pub mod event_producers;
mod watcher;
pub use watcher::Controller;
use crate::directory::entry_container::{Directory, DirectoryWatcher};
use crate::directory::watchers::event_producers::EventProducer;
use crate::execution_scope::ExecutionScope;
use fidl_fuchsia_io as fio;
use slab::Slab;
use std::sync::Arc;
/// Wraps all watcher connections observing one directory. The directory is responsible for
/// calling [`Self::add()`] and [`Self::send_event()`] method when appropriate to make sure
/// watchers are observing a consistent view.
pub struct Watchers(Slab<Arc<Controller>>);
impl Watchers {
/// Constructs a new Watchers instance with no connected watchers.
pub fn new() -> Self {
Watchers(Slab::new())
}
/// Connects a new watcher (connected over the `channel`) to the list of watchers. It is the
/// responsibility of the caller to also send `WATCH_EVENT_EXISTING` and `WatchMask::IDLE`
/// events on the returned [`Controller`] to the newly connected watcher using the
/// [`Self::send_event`] methods. This `mask` is the event mask this watcher has requested.
///
/// Return value of `None` means the executor did not accept a new task, so the watcher has
/// been dropped.
///
/// NOTE The reason `add` can not send both events on its own by consuming an
/// [`EventProducer`] is because a lazy directory needs async context to generate a list of
/// it's entries. Meaning we need a async version of the [`EventProducer`] - and that is a lot
/// of additional managing of functions and state. Traits do not support async methods yet, so
/// we would need to manage futures returned by the [`EventProducer`] methods explicitly.
/// Plus, for the [`crate::directory::immutable::Simple`] directory it is all unnecessary.
#[must_use = "Caller of add() must send WATCH_EVENT_EXISTING and fio::WatchMask::IDLE on the \
returned controller"]
pub fn add(
&mut self,
scope: ExecutionScope,
directory: Arc<dyn Directory>,
mask: fio::WatchMask,
watcher: DirectoryWatcher,
) -> Arc<Controller> {
let entry = self.0.vacant_entry();
let key = entry.key();
let done = move || {
// Add tests.
// TODO(72292)
directory.unregister_watcher(key);
};
let controller = Arc::new(watcher::new(scope, mask, watcher, done));
entry.insert(controller).clone()
}
/// Informs all the connected watchers about the specified event. While `mask` and `event`
/// carry the same information, as they are represented by `WatchMask::*` and `WATCH_EVENT_*`
/// constants in fuchsia.io, it is easier when both forms are provided. `mask` is used to
/// filter out those watchers that did not request for observation of this event and `event` is
/// used to construct the event object. The method will operate correctly only if `mask` and
/// `event` match.
///
/// In case of a communication error with any of the watchers, connection to this watcher is
/// closed.
pub fn send_event(&mut self, producer: &mut dyn EventProducer) {
while producer.prepare_for_next_buffer() {
let mut consumed_any = false;
for (_key, controller) in self.0.iter() {
controller.send_buffer(producer.mask(), || {
consumed_any = true;
producer.buffer()
});
}
if !consumed_any {
break;
}
}
}
/// Disconnects a watcher with the specified key. A directory will use this method during the
/// `unregister_watcher` call.
pub fn remove(&mut self, key: usize) {
self.0.remove(key);
}
}