zx/
info.rs

1// Copyright 2018 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
5//! Type-safe bindings for Zircon object information.
6
7use crate::{HandleRef, Status, ok, sys};
8use std::mem::MaybeUninit;
9use std::ops::Deref;
10use zerocopy::{FromBytes, Immutable};
11
12// Tuning constants for get_info_vec(). pub(crate) to support unit tests.
13pub(crate) const INFO_VEC_SIZE_INITIAL: usize = 16;
14
15#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
16#[repr(transparent)]
17pub struct Topic(sys::zx_object_info_topic_t);
18
19impl Deref for Topic {
20    type Target = sys::zx_object_info_topic_t;
21
22    fn deref(&self) -> &Self::Target {
23        &self.0
24    }
25}
26
27/// A query to get info about a zircon object.
28///
29/// # Safety
30///
31/// `InfoTy` must be the same size as what the kernel expects to return for the provided topic.
32pub(crate) unsafe trait ObjectQuery {
33    /// A `Topic` identifying this query.
34    const TOPIC: Topic;
35    /// The datatype returned by querying for Self::TOPIC.
36    type InfoTy: FromBytes + Immutable;
37}
38
39assoc_values!(Topic, [
40    NONE = sys::ZX_INFO_NONE;
41    HANDLE_VALID = sys::ZX_INFO_HANDLE_VALID;
42    HANDLE_BASIC = sys::ZX_INFO_HANDLE_BASIC;
43    PROCESS = sys::ZX_INFO_PROCESS;
44    PROCESS_THREADS = sys::ZX_INFO_PROCESS_THREADS;
45    VMAR = sys::ZX_INFO_VMAR;
46    VMAR_MAPS = sys::ZX_INFO_VMAR_MAPS;
47    JOB_CHILDREN = sys::ZX_INFO_JOB_CHILDREN;
48    JOB_PROCESSES = sys::ZX_INFO_JOB_PROCESSES;
49    THREAD = sys::ZX_INFO_THREAD;
50    THREAD_EXCEPTION_REPORT = sys::ZX_INFO_THREAD_EXCEPTION_REPORT;
51    TASK_STATS = sys::ZX_INFO_TASK_STATS;
52    TASK_RUNTIME = sys::ZX_INFO_TASK_RUNTIME;
53    PROCESS_MAPS = sys::ZX_INFO_PROCESS_MAPS;
54    PROCESS_VMOS = sys::ZX_INFO_PROCESS_VMOS;
55    THREAD_STATS = sys::ZX_INFO_THREAD_STATS;
56    CPU_STATS = sys::ZX_INFO_CPU_STATS;
57    KMEM_STATS = sys::ZX_INFO_KMEM_STATS;
58    KMEM_STATS_EXTENDED = sys::ZX_INFO_KMEM_STATS_EXTENDED;
59    KMEM_STATS_COMPRESSION = sys::ZX_INFO_KMEM_STATS_COMPRESSION;
60    RESOURCE = sys::ZX_INFO_RESOURCE;
61    HANDLE_COUNT = sys::ZX_INFO_HANDLE_COUNT;
62    BTI = sys::ZX_INFO_BTI;
63    PROCESS_HANDLE_STATS = sys::ZX_INFO_PROCESS_HANDLE_STATS;
64    SOCKET = sys::ZX_INFO_SOCKET;
65    TIMER = sys::ZX_INFO_TIMER;
66    VMO = sys::ZX_INFO_VMO;
67    JOB = sys::ZX_INFO_JOB;
68    IOB = sys::ZX_INFO_IOB;
69    IOB_REGIONS = sys::ZX_INFO_IOB_REGIONS;
70    MEMORY_STALL = sys::ZX_INFO_MEMORY_STALL;
71    CLOCK_MAPPED_SIZE = sys::ZX_INFO_CLOCK_MAPPED_SIZE;
72]);
73
74/// Query information about a zircon object. Returns a valid slice and any remaining capacity on
75/// success, along with a count of how many infos the kernel had available.
76pub(crate) fn object_get_info<'a, Q: ObjectQuery>(
77    handle: HandleRef<'_>,
78    out: &'a mut [MaybeUninit<Q::InfoTy>],
79) -> Result<(&'a mut [Q::InfoTy], &'a mut [MaybeUninit<Q::InfoTy>], usize), Status>
80where
81    Q::InfoTy: FromBytes + Immutable,
82{
83    let mut actual = 0;
84    let mut avail = 0;
85
86    // SAFETY: The slice pointer is known valid to write to for `size_of_val` because it came from
87    // a mutable reference.
88    let status = unsafe {
89        sys::zx_object_get_info(
90            handle.raw_handle(),
91            *Q::TOPIC,
92            out.as_mut_ptr().cast::<u8>(),
93            std::mem::size_of_val(out),
94            &mut actual,
95            &mut avail,
96        )
97    };
98    ok(status)?;
99
100    let (initialized, uninit) = out.split_at_mut(actual);
101
102    // TODO(https://fxbug.dev/352398385) switch to MaybeUninit::slice_assume_init_mut
103    // SAFETY: these values have been initialized by the kernel and implement the right zerocopy
104    // traits to be instantiated from arbitrary bytes.
105    let initialized: &mut [Q::InfoTy] = unsafe {
106        std::slice::from_raw_parts_mut(
107            initialized.as_mut_ptr().cast::<Q::InfoTy>(),
108            initialized.len(),
109        )
110    };
111
112    Ok((initialized, uninit, avail))
113}
114
115/// Query information about a zircon object, expecting only a single info in the return.
116pub(crate) fn object_get_info_single<Q: ObjectQuery>(
117    handle: HandleRef<'_>,
118) -> Result<Q::InfoTy, Status>
119where
120    Q::InfoTy: Copy + FromBytes + Immutable,
121{
122    let mut info = MaybeUninit::<Q::InfoTy>::uninit();
123    let (info, _, _) = object_get_info::<Q>(handle, std::slice::from_mut(&mut info))?;
124    Ok(info[0])
125}
126
127/// Query multiple records of information about a zircon object.
128/// Returns a vec of Q::InfoTy on success.
129/// Intended for calls that return multiple small objects.
130pub(crate) fn object_get_info_vec<Q: ObjectQuery>(
131    handle: HandleRef<'_>,
132) -> Result<Vec<Q::InfoTy>, Status> {
133    // Start with a few slots
134    let mut out = Vec::<Q::InfoTy>::with_capacity(INFO_VEC_SIZE_INITIAL);
135    loop {
136        let (init, _uninit, avail) =
137            object_get_info::<Q>(handle.clone(), out.spare_capacity_mut())?;
138        let num_initialized = init.len();
139        if num_initialized == avail {
140            // SAFETY: the kernel has initialized all of these values.
141            unsafe { out.set_len(num_initialized) };
142            return Ok(out);
143        } else {
144            if avail > out.capacity() {
145                out.reserve_exact(avail - out.len());
146            }
147        }
148    }
149}