Skip to main content

vpp_plugin/vlib/
main.rs

1//! VPP vlib main structure wrapper
2//!
3//! This module contains abstractions around VPP's `vlib_main_t` structure.
4//! It provides safe access to the main VPP library context.
5
6use std::ops::Deref;
7
8use crate::bindings::vlib_main_t;
9
10/// Reference to VPP per-thread main library context
11///
12/// This is a safe wrapper around `vlib_main_t`, providing access to its fields.
13///
14/// A `&mut MainRef` is equivalent to a `vlib_main_t *` in C (a `*mut vlib_main_t` in Rust).
15///
16/// See also [`BarrierHeldMainRef`] for a variant that indicates the caller holds the
17/// main thread barrier.
18#[repr(transparent)]
19pub struct MainRef(foreign_types::Opaque);
20
21impl MainRef {
22    /// Creates a `&mut MainRef` directly from a pointer
23    ///
24    /// # Safety
25    /// - The pointer must be valid and a properly initialised `vlib_main_t` for the thread.
26    /// - The pointer must stay valid and the contents must not be mutated for the duration of the
27    ///   lifetime of the returned object.
28    /// - The `vlib_main_t` must have been created by VPP at startup and not manually by the
29    ///   caller, as many datastructures size the memory they allocate by the number of threads
30    ///   at startup and are subsequently indexed by thread index.
31    pub unsafe fn from_ptr_mut<'a>(ptr: *mut vlib_main_t) -> &'a mut Self {
32        // SAFETY: caller must ensure the safety requirements are met
33        unsafe { &mut *(ptr as *mut _) }
34    }
35
36    /// Returns the raw pointer to the underlying `vlib_main_t`
37    pub fn as_ptr(&self) -> *mut vlib_main_t {
38        self as *const _ as *mut _
39    }
40
41    /// Returns the 0-based thread index of this VPP main context
42    pub fn thread_index(&self) -> u16 {
43        // SAFETY: as long as `self` is a valid `MainRef`, so is the pointer dereference
44        unsafe { (*self.as_ptr()).thread_index }
45    }
46}
47
48/// Reference to VPP per-thread main library context with barrier held
49///
50/// This is a safe wrapper around `vlib_main_t`, providing access to its fields.
51///
52/// A `&mut BarrierHeldMainRef` is equivalent to a `vlib_main_t *` in C (a `*mut vlib_main_t` in
53/// Rust).
54///
55/// See also [`MainRef`] for a variant without the constraint that the caller holds the
56/// main thread barrier.
57pub struct BarrierHeldMainRef(MainRef);
58
59impl BarrierHeldMainRef {
60    /// Creates a `&mut BarrierHeldMainRef` directly from a pointer
61    ///
62    /// # Safety
63    /// - All the safety requirements of [`MainRef::from_ptr_mut`] apply.
64    /// - Additionally, the caller must that no other thread is concurrently accessing VPP data
65    ///   structures. This is typically ensured by holding the main thread barrier, but also
66    ///   applies during initialisation before worker threads are started or shutdown after
67    ///   worker threads are stopped.
68    pub unsafe fn from_ptr_mut<'a>(ptr: *mut vlib_main_t) -> &'a mut Self {
69        // SAFETY: caller must ensure the safety requirements are met
70        unsafe {
71            // Sanity check: barrier should only ever be held on main thread
72            debug_assert!((*ptr).thread_index == 0);
73            &mut *(ptr as *mut _)
74        }
75    }
76}
77
78impl Deref for BarrierHeldMainRef {
79    type Target = MainRef;
80
81    fn deref(&self) -> &Self::Target {
82        &self.0
83    }
84}