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};
78// 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();
1112pub trait WatcherInterface {
13fn 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}
1920impl Watcher {
21pub fn new(receiver: Receiver<()>) -> Watcher {
22 Watcher { receiver }
23 }
2425/// Returns when one of more changes happened in the tracing system configuration.
26pub async fn recv(&mut self) {
27match self.receiver.changed().await {
28Ok(_) => {} // One or more event occurred.
29Err(_) => 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 {
36let receiver = TRACE_SINGLETON.get_or_init(|| TraceSingleton::new()).sender.subscribe();
37 Watcher::new(receiver)
38}
3940// 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.
44sender: Sender<()>,
45}
4647extern "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}
5556impl TraceSingleton {
57fn new() -> TraceSingleton {
58debug!("Register trace provider");
59 fuchsia_trace_provider::trace_provider_create_with_fdio();
60debug!("Setup trace observer callback");
61 fuchsia_trace_observer::start_trace_observer(c_callback);
62let (sender, _) = watch::channel(());
63 TraceSingleton { sender }
64 }
65}