ax-task 0.7.0

OS-independent IRQ-safe SMP task scheduling core
Documentation
use core::{any::type_name, panic::Location};

use super::base::BaseSpinLock;
pub use crate::sync::lockdep::{
    DEFAULT_LOCK_SUBCLASS, LockdepMap, PreparedAcquire, current_task_held_lock_snapshot,
};
use crate::sync::{
    context::GuardState,
    lockdep::{LockdepMapView, prepare_acquire_with_snapshot_view_nested_with_sleep},
};

#[derive(Clone, Copy)]
pub(crate) struct Lockdep {
    addr: usize,
    inner: crate::sync::lockdep::Lockdep,
    prepared: Option<PreparedAcquire>,
}

pub(crate) struct LockdepAcquireRequest<'map> {
    pub map: LockdepMapView<'map>,
    pub lock_kind: &'static str,
    pub trace_kind: &'static str,
    pub addr: usize,
    pub is_try: bool,
    pub subclass: u32,
    pub caller: &'static Location<'static>,
    pub detail: &'static str,
    pub track_task_lock: bool,
}

impl Lockdep {
    #[inline(always)]
    #[track_caller]
    pub(crate) fn prepare<G: GuardState, T: ?Sized>(
        lock: &BaseSpinLock<G, T>,
        is_try: bool,
    ) -> Self {
        Self::prepare_nested(lock, is_try, DEFAULT_LOCK_SUBCLASS)
    }

    #[inline(always)]
    #[track_caller]
    pub(crate) fn prepare_nested<G: GuardState, T: ?Sized>(
        lock: &BaseSpinLock<G, T>,
        is_try: bool,
        subclass: u32,
    ) -> Self {
        let addr = lock as *const _ as *const () as usize;
        Self::prepare_map::<G>(
            lock.lockdep_map(),
            "spin lock",
            "spin",
            addr,
            is_try,
            subclass,
            true,
        )
    }

    #[inline(always)]
    #[track_caller]
    pub(crate) fn prepare_map<G: GuardState>(
        map: &LockdepMap,
        lock_kind: &'static str,
        trace_kind: &'static str,
        addr: usize,
        is_try: bool,
        subclass: u32,
        track_task_lock: bool,
    ) -> Self {
        Self::prepare_view(LockdepAcquireRequest {
            map: map.view(),
            lock_kind,
            trace_kind,
            addr,
            is_try,
            subclass,
            caller: Location::caller(),
            detail: type_name::<G>(),
            track_task_lock: track_task_lock && tracks_task_locks::<G>(),
        })
    }

    #[inline(always)]
    pub(crate) fn prepare_view(request: LockdepAcquireRequest<'_>) -> Self {
        let prepared = request.track_task_lock.then(|| {
            prepare_acquire_with_snapshot_view_nested_with_sleep(
                request.map,
                request.lock_kind,
                request.addr,
                request.caller,
                current_task_held_lock_snapshot(),
                request.subclass,
                true,
            )
        });
        Self {
            addr: request.addr,
            inner: crate::sync::lockdep::Lockdep::prepare(
                request.trace_kind,
                request.addr,
                request.is_try,
                Some(request.detail),
            ),
            prepared,
        }
    }

    #[inline(always)]
    pub(crate) fn finish(&self, acquired: bool) {
        self.inner.finish(acquired);
        if let (true, Some(prepared)) = (acquired, self.prepared) {
            crate::sync::lockdep::finish_acquire_task(prepared, self.addr);
        }
    }

    #[inline(always)]
    pub(crate) fn lock_addr(&self) -> usize {
        self.addr
    }
}

#[inline(always)]
pub(crate) fn release<G: GuardState>(addr: usize) {
    release_kind::<G>("spin", addr);
}

#[inline(always)]
pub(crate) fn release_kind<G: GuardState>(kind: &'static str, addr: usize) {
    release_external(kind, addr, type_name::<G>(), tracks_task_locks::<G>());
}

#[inline(always)]
pub(crate) fn release_trace_only<G: GuardState>(kind: &'static str, addr: usize) {
    release_external(kind, addr, type_name::<G>(), false);
}

#[inline(always)]
pub(crate) fn force_release<G: GuardState>(addr: usize) {
    force_release_external("spin", addr, type_name::<G>(), tracks_task_locks::<G>());
}

#[inline(always)]
pub(crate) fn release_external(
    kind: &'static str,
    addr: usize,
    detail: &'static str,
    track_task_lock: bool,
) {
    if track_task_lock {
        crate::sync::lockdep::release_task(addr);
    }
    crate::sync::lockdep::Lockdep::release(kind, addr, Some(detail));
}

#[inline(always)]
pub(crate) fn force_release_external(
    kind: &'static str,
    addr: usize,
    detail: &'static str,
    track_task_lock: bool,
) {
    if track_task_lock {
        crate::sync::lockdep::force_release_task(addr);
    }
    crate::sync::lockdep::Lockdep::release(kind, addr, Some(detail));
}

fn is_noop_guard<G: GuardState>() -> bool {
    type_name::<G>() == type_name::<crate::sync::context::RawState>()
}

fn tracks_task_locks<G: GuardState>() -> bool {
    is_noop_guard::<G>() || G::lockdep_enabled()
}