perf-event-open 0.5.1

Full-featured support for the `perf_event_open` syscall.
Documentation
use std::fs::File;
use std::io::{Error, Result};
use std::mem::MaybeUninit;
use std::os::fd::{AsRawFd, FromRawFd};
use std::ptr::NonNull;
use std::slice;

use libc::epoll_event;

use super::Attr;

pub fn perf_event_open(attr: &Attr, pid: i32, cpu: i32, group_fd: i32, flags: u64) -> Result<File> {
    let num = libc::SYS_perf_event_open;
    let fd = unsafe { libc::syscall(num, attr, pid, cpu, group_fd, flags) };
    if fd != -1 {
        Ok(unsafe { File::from_raw_fd(fd as _) })
    } else {
        Err(Error::last_os_error())
    }
}

pub unsafe fn ioctl_arg(file: &File, op: u64, arg: u64) -> Result<i32> {
    let fd = file.as_raw_fd();
    let result = unsafe { libc::ioctl(fd, op as _, arg) };
    if result != -1 {
        Ok(result)
    } else {
        Err(Error::last_os_error())
    }
}

pub fn read(file: &File, buf: &mut [u8]) -> Result<usize> {
    let fd = file.as_raw_fd();
    let count = buf.len();
    let buf = buf.as_mut_ptr() as _;
    let bytes = unsafe { libc::read(fd, buf, count) };
    if bytes != -1 {
        Ok(bytes as _)
    } else {
        Err(Error::last_os_error())
    }
}

pub unsafe fn mmap(
    ptr: *mut (),
    len: usize,
    prot: i32,
    flags: i32,
    file: &File,
    offset: i64,
) -> Result<NonNull<()>> {
    let fd = file.as_raw_fd();
    let ptr = libc::mmap(ptr as _, len, prot, flags, fd, offset);
    if ptr != libc::MAP_FAILED {
        Ok(unsafe { NonNull::new_unchecked(ptr as _) })
    } else {
        Err(Error::last_os_error())
    }
}

pub unsafe fn munmap(ptr: *mut (), len: usize) -> Result<()> {
    let result = libc::munmap(ptr as _, len);
    if result != -1 {
        Ok(())
    } else {
        Err(Error::last_os_error())
    }
}

pub fn epoll_create1(flags: i32) -> Result<File> {
    let fd = unsafe { libc::epoll_create1(flags) };
    if fd != -1 {
        Ok(unsafe { File::from_raw_fd(fd as _) })
    } else {
        Err(Error::last_os_error())
    }
}

pub fn epoll_ctl(epoll: &File, op: i32, file: &File, event: &mut epoll_event) -> Result<()> {
    let epfd = epoll.as_raw_fd();
    let fd = file.as_raw_fd();
    let result = unsafe { libc::epoll_ctl(epfd, op, fd, event as _) };
    if result != -1 {
        Ok(())
    } else {
        Err(Error::last_os_error())
    }
}

pub fn epoll_wait<'a>(
    epoll: &File,
    events: &'a mut [MaybeUninit<epoll_event>],
    timeout: i32,
) -> Result<&'a [epoll_event]> {
    let epfd = epoll.as_raw_fd();
    let events_ptr = events.as_mut_ptr() as *mut _;
    let events_len = events.len();
    let len = unsafe { libc::epoll_wait(epfd, events_ptr, events_len as _, timeout) };
    if len != -1 {
        Ok(unsafe { slice::from_raw_parts(events_ptr, len as _) })
    } else {
        Err(Error::last_os_error())
    }
}

pub fn eventfd(initval: u32, flags: i32) -> Result<File> {
    let fd = unsafe { libc::eventfd(initval, flags) };
    if fd != -1 {
        Ok(unsafe { File::from_raw_fd(fd as _) })
    } else {
        Err(Error::last_os_error())
    }
}

pub fn eventfd_write(event: &File, value: u64) -> Result<()> {
    let result = unsafe { libc::eventfd_write(event.as_raw_fd(), value) };
    if result == 0 {
        Ok(())
    } else {
        Err(Error::last_os_error())
    }
}

pub fn prctl(option: i32) -> Result<()> {
    let result = unsafe { libc::prctl(option) };
    if result != -1 {
        Ok(())
    } else {
        Err(Error::last_os_error())
    }
}