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}