traces/
watcher.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4use log::debug;
5use std::sync::OnceLock;
6use tokio::sync::watch::{self, Receiver, Sender};
7
8// Use a singleton so that `trace_provider_create_with_fdio` is used only once, and the
9// `c_callback` can interact with a `TraceObserver` instance.
10static TRACE_SINGLETON: OnceLock<TraceSingleton> = OnceLock::new();
11
12pub trait WatcherInterface {
13    fn recv(&mut self) -> impl std::future::Future<Output = ()> + Send;
14}
15/// Detects changes in the tracing system state.
16pub struct Watcher {
17    receiver: Receiver<()>,
18}
19
20impl Watcher {
21    pub fn new(receiver: Receiver<()>) -> Watcher {
22        Watcher { receiver }
23    }
24
25    /// Returns when one of more changes happened in the tracing system configuration.
26    pub async fn recv(&mut self) {
27        match self.receiver.changed().await {
28            Ok(_) => {} // One or more event occurred.
29            Err(_) => panic!("Dropping the sender should never happen"),
30        }
31    }
32}
33/// Setup a new observer and returns a Watcher object.
34/// Initializes the tracing system observation on first call.
35pub fn subscribe() -> Watcher {
36    let receiver = TRACE_SINGLETON.get_or_init(|| TraceSingleton::new()).sender.subscribe();
37    Watcher::new(receiver)
38}
39
40// Holds synchronization primitives, and guarantees that the trace system is initialized only once.
41struct TraceSingleton {
42    // Receives notifications when the trace state or set of enabled
43    // categories changes.
44    sender: Sender<()>,
45}
46
47extern "C" fn c_callback() {
48    TRACE_SINGLETON
49        .get()
50        .expect("Unexpected callback called before observer initialization")
51        .sender
52        .send(())
53        .ok(); // Error means there is no receiver connected, and can be ignored.
54}
55
56impl TraceSingleton {
57    fn new() -> TraceSingleton {
58        debug!("Register trace provider");
59        fuchsia_trace_provider::trace_provider_create_with_fdio();
60        debug!("Setup trace observer callback");
61        fuchsia_trace_observer::start_trace_observer(c_callback);
62        let (sender, _) = watch::channel(());
63        TraceSingleton { sender }
64    }
65}