Skip to main content

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