compio-driver 0.11.4

Low-level driver for compio
Documentation
use std::{
    ffi::c_void,
    io,
    os::windows::io::{AsRawHandle, FromRawHandle, OwnedHandle},
    ptr::null_mut,
    sync::Arc,
};

use windows_sys::Win32::Foundation::{
    GENERIC_READ, GENERIC_WRITE, HANDLE, NTSTATUS, RtlNtStatusToDosError, STATUS_PENDING,
    STATUS_SUCCESS,
};

use super::super::{Notify, RawFd};
use crate::ErasedKey;

unsafe extern "system" {
    fn NtCreateWaitCompletionPacket(
        WaitCompletionPacketHandle: *mut HANDLE,
        DesiredAccess: u32,
        ObjectAttributes: *mut c_void,
    ) -> NTSTATUS;

    fn NtAssociateWaitCompletionPacket(
        WaitCompletionPacketHandle: HANDLE,
        IoCompletionHandle: HANDLE,
        TargetObjectHandle: HANDLE,
        KeyContext: *mut c_void,
        ApcContext: *mut c_void,
        IoStatus: NTSTATUS,
        IoStatusInformation: usize,
        AlreadySignaled: *mut bool,
    ) -> NTSTATUS;

    fn NtCancelWaitCompletionPacket(
        WaitCompletionPacketHandle: HANDLE,
        RemoveSignaledPacket: bool,
    ) -> NTSTATUS;
}

pub struct Wait {
    handle: OwnedHandle,
    cancelled: bool,
}

fn check_status(status: NTSTATUS) -> io::Result<()> {
    if status >= 0 {
        Ok(())
    } else {
        Err(io::Error::from_raw_os_error(unsafe {
            RtlNtStatusToDosError(status) as _
        }))
    }
}

impl Wait {
    pub fn new(notify: Arc<Notify>, event: RawFd, key: ErasedKey) -> io::Result<Self> {
        let mut handle = null_mut();
        check_status(unsafe {
            NtCreateWaitCompletionPacket(&mut handle, GENERIC_READ | GENERIC_WRITE, null_mut())
        })?;
        let handle = unsafe { OwnedHandle::from_raw_handle(handle as _) };
        check_status(unsafe {
            NtAssociateWaitCompletionPacket(
                handle.as_raw_handle() as _,
                notify.port.as_raw_handle() as _,
                event,
                null_mut(),
                key.into_optr().cast(),
                STATUS_SUCCESS,
                0,
                null_mut(),
            )
        })?;
        Ok(Self {
            handle,
            cancelled: false,
        })
    }

    pub fn cancel(&mut self) -> io::Result<()> {
        let res = unsafe { NtCancelWaitCompletionPacket(self.handle.as_raw_handle() as _, false) };
        self.cancelled = res != STATUS_PENDING;
        check_status(res)
    }

    pub fn is_cancelled(&self) -> bool {
        self.cancelled
    }
}