moana_std 0.1.2

moana 用户标准库
Documentation
//! futex 系列 syscall 用户态接口

use moa_uapi::{
    error::{ERR_FAULT, ERR_INVAL, ERR_TIMEOUT},
    futex::FutexWaiter,
    sysnr::{
        SYSNR_FUTEX_REQUEUE, SYSNR_FUTEX_WAIT, SYSNR_FUTEX_WAITV, SYSNR_FUTEX_WAKE,
        SYSNR_ROBUST_LIST_SET,
    },
    types::Timeout,
};

/// futex 系列 syscall 返回类型
pub type Result<T> = core::result::Result<T, FutexError>;

define_syscall_error! {
    /// futex 系列 syscall 错误
    pub enum FutexError {
        /// 无效参数(`*uaddr != expected` 或参数错误)
        Inval = ERR_INVAL,
        /// 无效指针
        Fault = ERR_FAULT,
        /// 超时
        Timeout = ERR_TIMEOUT,
    }
}

/// 检查 `*uaddr == expected` 则阻塞
#[allow(clippy::cast_possible_truncation)]
pub fn futex_wait(uaddr: *const u32, expected: u32, timeout: Timeout) -> Result<()> {
    let ret = unsafe {
        super::arch::syscall3(
            SYSNR_FUTEX_WAIT,
            uaddr as usize,
            expected as usize,
            timeout.raw() as usize,
        )
    };
    if ret < 0 { Err(FutexError::from_raw(ret)) } else { Ok(()) }
}

/// 等待多个 futex 中任意一个被唤醒
///
/// 任一 `*uaddr != expected` 则立即返回不阻塞。
/// 返回被唤醒的 waiter 索引。
#[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
pub fn futex_waitv(waiters: &[FutexWaiter], timeout: Timeout) -> Result<u32> {
    let ret = unsafe {
        super::arch::syscall3(
            SYSNR_FUTEX_WAITV,
            waiters.as_ptr() as usize,
            waiters.len(),
            timeout.raw() as usize,
        )
    };
    if ret < 0 { Err(FutexError::from_raw(ret)) } else { Ok(ret as u32) }
}

/// 唤醒 `uaddr` 上最多 `nr_wake` 个等待者
///
/// 返回实际唤醒的数量。
#[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
pub fn futex_wake(uaddr: *const u32, nr_wake: u32) -> Result<u32> {
    let ret = unsafe { super::arch::syscall2(SYSNR_FUTEX_WAKE, uaddr as usize, nr_wake as usize) };
    if ret < 0 { Err(FutexError::from_raw(ret)) } else { Ok(ret as u32) }
}

/// 唤醒 `nr_wake` 个 + 转移 `nr_move` 个到 `dst` 等待队列
///
/// 返回实际唤醒的数量。
#[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
pub fn futex_requeue(src: *const u32, dst: *const u32, nr_wake: u32, nr_move: u32) -> Result<u32> {
    let ret = unsafe {
        super::arch::syscall4(
            SYSNR_FUTEX_REQUEUE,
            src as usize,
            dst as usize,
            nr_wake as usize,
            nr_move as usize,
        )
    };
    if ret < 0 { Err(FutexError::from_raw(ret)) } else { Ok(ret as u32) }
}

/// 注册当前任务的 robust futex 链表头
///
/// 任务退出时内核遍历链表,标记 `FUTEX_OWNER_DIED` 并唤醒等待者。
pub fn robust_list_set(head: *const u8) -> Result<()> {
    let ret = unsafe { super::arch::syscall1(SYSNR_ROBUST_LIST_SET, head as usize) };
    if ret < 0 { Err(FutexError::from_raw(ret)) } else { Ok(()) }
}