Skip to main content

fuchsia_trace_provider/
lib.rs

1// Copyright 2019 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.
4
5use core::ffi::CStr;
6use core::ptr::{NonNull, null};
7use libasync::{AsAsyncDispatcherRef, AsyncDispatcher};
8use zx::sys::zx_handle_t;
9
10/// Creates a trace provider service that enables traces created by a process
11/// to be collected by the system trace manager.
12///
13/// Typically applications would call this method once, early in their main
14/// function to enable them to be eligible to produce traces.
15///
16/// It is safe but unnecessary to call this function more than once.
17pub fn trace_provider_create_with_fdio() {
18    unsafe {
19        sys::trace_provider_create_with_fdio_rust();
20    }
21}
22
23pub fn trace_provider_create_with_service(to_service_h: zx_handle_t) {
24    unsafe {
25        sys::trace_provider_create_with_service_rust(to_service_h);
26    }
27}
28
29/// Wait for trace provider initialization to acknowledge already-running traces before returning.
30///
31/// If the current thread is expected to initialize the provider then this should only be called
32/// after doing so to avoid a deadlock.
33pub fn trace_provider_wait_for_init() {
34    unsafe {
35        sys::trace_provider_wait_for_init();
36    }
37}
38
39/// Use this object to start and run a trace provider under an existing [`libasync`] dispatcher
40/// handle.
41///
42/// You can use this in combination with `libasync_scope_dispatcher` to run the trace
43/// provider on top of fuchsia-async, for example:
44///
45/// ```no_run
46/// #[fuchsia::main]
47/// async fn main() {
48///     // create a new scoped async dispatcher object for the current fuchsia-async executor.
49///     let scope_dispatcher = libasync_scope_dispatcher::ScopeDispatcher::new();
50///     // create a trace provider on it.
51///     let trace_provider =
52///         fuchsia_trace_provider::TraceProvider::new_with_fdio(&scope_dispatcher, None);
53///
54///     // run your program here...
55///
56///     // drop the trace provider before shutting down the dispatcher since it will queue work
57///     // on the dispatcher.
58///     drop(trace_provider);
59///     // shutdown the dispatcher.
60///     scope_dispatcher.shutdown().await;
61/// }
62/// ```
63///
64/// Note: As in the example above, make sure that this object is dropped before the dispatcher
65/// shuts down.
66pub struct TraceProvider {
67    trace_provider: NonNull<core::ffi::c_void>,
68    // just kept here to ensure that the dispatcher object is kept alive for memory safety reasons.
69    #[expect(unused)]
70    dispatcher: AsyncDispatcher,
71}
72
73impl TraceProvider {
74    pub fn new_with_fdio(
75        dispatcher: &impl AsAsyncDispatcherRef,
76        name: Option<&CStr>,
77    ) -> Option<Self> {
78        let dispatcher = AsyncDispatcher::new(dispatcher);
79        let trace_provider = NonNull::new(unsafe {
80            sys::trace_provider_create_with_fdio(
81                dispatcher.as_ptr().as_ptr(),
82                name.map_or(null(), CStr::as_ptr),
83            )
84        })?;
85        Some(Self { trace_provider, dispatcher })
86    }
87}
88
89impl Drop for TraceProvider {
90    fn drop(&mut self) {
91        unsafe { sys::trace_provider_destroy(self.trace_provider.as_ptr()) }
92    }
93}
94
95mod sys {
96    // From librust-trace-provider.so
97    unsafe extern "C" {
98        // See the C++ documentation for these functions in trace_provider.cc
99        pub(super) fn trace_provider_create_with_fdio_rust();
100        pub(super) fn trace_provider_create_with_service_rust(to_service_h: zx::sys::zx_handle_t);
101        pub(super) fn trace_provider_wait_for_init();
102
103        // These are directly imported from the C++ trace library.
104        pub(super) fn trace_provider_create_with_fdio(
105            dispatcher: *const libasync_sys::async_dispatcher_t,
106            name: *const core::ffi::c_char,
107        ) -> *mut core::ffi::c_void;
108        pub(super) fn trace_provider_destroy(trace_provider: *const core::ffi::c_void);
109    }
110}