Skip to content

Commit

Permalink
Rust: Use a tighter inner type for Error
Browse files Browse the repository at this point in the history
Use NonZeroI32 as the inner type. This allows Result<()> to fit in
32-bit, instead of 64-bit.

Signed-off-by: Fox Chen <[email protected]>
  • Loading branch information
foxhlchen committed Jun 6, 2021
1 parent 27d102f commit 4dd79c0
Showing 1 changed file with 34 additions and 19 deletions.
53 changes: 34 additions & 19 deletions rust/kernel/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{bindings, c_types};
use alloc::{alloc::AllocError, collections::TryReserveError};
use core::convert::From;
use core::fmt;
use core::num::TryFromIntError;
use core::num::{NonZeroI32, TryFromIntError};
use core::str::{self, Utf8Error};

/// Generic integer kernel error.
Expand All @@ -21,44 +21,49 @@ use core::str::{self, Utf8Error};
///
/// The value is a valid `errno` (i.e. `>= -MAX_ERRNO && < 0`).
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct Error(c_types::c_int);
pub struct Error(NonZeroI32);

/// DO NOT use this function outside of Error const initializations.
const fn kernel_const_to_error(val: u32) -> Error {
Error(unsafe { NonZeroI32::new_unchecked(-(val as i32)) })
}

impl Error {
/// Invalid argument.
pub const EINVAL: Self = Error(-(bindings::EINVAL as i32));
pub const EINVAL: Self = kernel_const_to_error(bindings::EINVAL);

/// Out of memory.
pub const ENOMEM: Self = Error(-(bindings::ENOMEM as i32));
pub const ENOMEM: Self = kernel_const_to_error(bindings::ENOMEM);

/// Bad address.
pub const EFAULT: Self = Error(-(bindings::EFAULT as i32));
pub const EFAULT: Self = kernel_const_to_error(bindings::EFAULT);

/// Illegal seek.
pub const ESPIPE: Self = Error(-(bindings::ESPIPE as i32));
pub const ESPIPE: Self = kernel_const_to_error(bindings::ESPIPE);

/// Try again.
pub const EAGAIN: Self = Error(-(bindings::EAGAIN as i32));
pub const EAGAIN: Self = kernel_const_to_error(bindings::EAGAIN);

/// Device or resource busy.
pub const EBUSY: Self = Error(-(bindings::EBUSY as i32));
pub const EBUSY: Self = kernel_const_to_error(bindings::EBUSY);

/// Restart the system call.
pub const ERESTARTSYS: Self = Error(-(bindings::ERESTARTSYS as i32));
pub const ERESTARTSYS: Self = kernel_const_to_error(bindings::ERESTARTSYS);

/// Operation not permitted.
pub const EPERM: Self = Error(-(bindings::EPERM as i32));
pub const EPERM: Self = kernel_const_to_error(bindings::EPERM);

/// No such process.
pub const ESRCH: Self = Error(-(bindings::ESRCH as i32));
pub const ESRCH: Self = kernel_const_to_error(bindings::ESRCH);

/// No such file or directory.
pub const ENOENT: Self = Error(-(bindings::ENOENT as i32));
pub const ENOENT: Self = kernel_const_to_error(bindings::ENOENT);

/// Interrupted system call.
pub const EINTR: Self = Error(-(bindings::EINTR as i32));
pub const EINTR: Self = kernel_const_to_error(bindings::EINTR);

/// Bad file number.
pub const EBADF: Self = Error(-(bindings::EBADF as i32));
pub const EBADF: Self = kernel_const_to_error(bindings::EBADF);

/// Creates an [`Error`] from a kernel error code.
///
Expand All @@ -76,7 +81,11 @@ impl Error {

// INVARIANT: the check above ensures the type invariant
// will hold.
Error(errno)
//
// Safety: `errno` must be non zero, which is guaranteed by the check
// above.
let nz_errno = unsafe { NonZeroI32::new_unchecked(errno) };
Error(nz_errno)
}

/// Creates an [`Error`] from a kernel error code.
Expand All @@ -87,12 +96,15 @@ impl Error {
pub(crate) unsafe fn from_kernel_errno_unchecked(errno: c_types::c_int) -> Error {
// INVARIANT: the contract ensures the type invariant
// will hold.
Error(errno)
//
// Safety: `errno` must not be zero, which is guaranteed by the contract
// of this function.
Error(unsafe { NonZeroI32::new_unchecked(errno) })
}

/// Returns the kernel error code.
pub fn to_kernel_errno(self) -> c_types::c_int {
self.0
self.0.get()
}
}

Expand All @@ -102,11 +114,14 @@ impl fmt::Debug for Error {
fn rust_helper_errname(err: c_types::c_int) -> *const c_types::c_char;
}
// SAFETY: FFI call.
let name = unsafe { rust_helper_errname(-self.0) };
let name = unsafe { rust_helper_errname(-self.to_kernel_errno()) };

if name.is_null() {
// Print out number if no name can be found.
return f.debug_tuple("Error").field(&-self.0).finish();
return f
.debug_tuple("Error")
.field(&-self.to_kernel_errno())
.finish();
}

// SAFETY: `'static` string from C, and is not NULL.
Expand Down

0 comments on commit 4dd79c0

Please sign in to comment.