| use super::abi; | |
| use crate::{fmt, io}; | |
| /// Wraps a μITRON error code. | |
| #[derive(Debug, Copy, Clone)] | |
| pub struct ItronError { | |
| er: abi::ER, | |
| } | |
| impl ItronError { | |
| /// Constructs `ItronError` from the specified error code. Returns `None` if the | |
| /// error code does not represent a failure or warning. | |
| #[inline] | |
| pub fn new(er: abi::ER) -> Option<Self> { | |
| if er < 0 { Some(Self { er }) } else { None } | |
| } | |
| /// Returns `Ok(er)` if `er` represents a success or `Err(_)` otherwise. | |
| #[inline] | |
| pub fn err_if_negative(er: abi::ER) -> Result<abi::ER, Self> { | |
| if let Some(error) = Self::new(er) { Err(error) } else { Ok(er) } | |
| } | |
| /// Gets the raw error code. | |
| #[inline] | |
| pub fn as_raw(&self) -> abi::ER { | |
| self.er | |
| } | |
| } | |
| impl fmt::Display for ItronError { | |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| // Allow the platforms to extend `error_name` | |
| if let Some(name) = crate::sys::error::error_name(self.er) { | |
| write!(f, "{} ({})", name, self.er) | |
| } else { | |
| write!(f, "{}", self.er) | |
| } | |
| } | |
| } | |
| /// Describe the specified μITRON error code. Returns `None` if it's an | |
| /// undefined error code. | |
| pub fn error_name(er: abi::ER) -> Option<&'static str> { | |
| match er { | |
| // Success | |
| er if er >= 0 => None, | |
| // μITRON 4.0 | |
| abi::E_SYS => Some("system error"), | |
| abi::E_NOSPT => Some("unsupported function"), | |
| abi::E_RSFN => Some("reserved function code"), | |
| abi::E_RSATR => Some("reserved attribute"), | |
| abi::E_PAR => Some("parameter error"), | |
| abi::E_ID => Some("invalid ID number"), | |
| abi::E_CTX => Some("context error"), | |
| abi::E_MACV => Some("memory access violation"), | |
| abi::E_OACV => Some("object access violation"), | |
| abi::E_ILUSE => Some("illegal service call use"), | |
| abi::E_NOMEM => Some("insufficient memory"), | |
| abi::E_NOID => Some("no ID number available"), | |
| abi::E_OBJ => Some("object state error"), | |
| abi::E_NOEXS => Some("non-existent object"), | |
| abi::E_QOVR => Some("queue overflow"), | |
| abi::E_RLWAI => Some("forced release from waiting"), | |
| abi::E_TMOUT => Some("polling failure or timeout"), | |
| abi::E_DLT => Some("waiting object deleted"), | |
| abi::E_CLS => Some("waiting object state changed"), | |
| abi::E_WBLK => Some("non-blocking code accepted"), | |
| abi::E_BOVR => Some("buffer overflow"), | |
| // The TOPPERS third generation kernels | |
| abi::E_NORES => Some("insufficient system resources"), | |
| abi::E_RASTER => Some("termination request raised"), | |
| abi::E_COMM => Some("communication failure"), | |
| _ => None, | |
| } | |
| } | |
| #[inline] | |
| pub fn is_interrupted(er: abi::ER) -> bool { | |
| er == abi::E_RLWAI | |
| } | |
| pub fn decode_error_kind(er: abi::ER) -> io::ErrorKind { | |
| match er { | |
| // Success | |
| er if er >= 0 => io::ErrorKind::Uncategorized, | |
| // μITRON 4.0 | |
| // abi::E_SYS | |
| abi::E_NOSPT => io::ErrorKind::Unsupported, // Some("unsupported function"), | |
| abi::E_RSFN => io::ErrorKind::InvalidInput, // Some("reserved function code"), | |
| abi::E_RSATR => io::ErrorKind::InvalidInput, // Some("reserved attribute"), | |
| abi::E_PAR => io::ErrorKind::InvalidInput, // Some("parameter error"), | |
| abi::E_ID => io::ErrorKind::NotFound, // Some("invalid ID number"), | |
| // abi::E_CTX | |
| abi::E_MACV => io::ErrorKind::PermissionDenied, // Some("memory access violation"), | |
| abi::E_OACV => io::ErrorKind::PermissionDenied, // Some("object access violation"), | |
| // abi::E_ILUSE | |
| abi::E_NOMEM => io::ErrorKind::OutOfMemory, // Some("insufficient memory"), | |
| abi::E_NOID => io::ErrorKind::OutOfMemory, // Some("no ID number available"), | |
| // abi::E_OBJ | |
| abi::E_NOEXS => io::ErrorKind::NotFound, // Some("non-existent object"), | |
| // abi::E_QOVR | |
| abi::E_RLWAI => io::ErrorKind::Interrupted, // Some("forced release from waiting"), | |
| abi::E_TMOUT => io::ErrorKind::TimedOut, // Some("polling failure or timeout"), | |
| // abi::E_DLT | |
| // abi::E_CLS | |
| // abi::E_WBLK | |
| // abi::E_BOVR | |
| // The TOPPERS third generation kernels | |
| abi::E_NORES => io::ErrorKind::OutOfMemory, // Some("insufficient system resources"), | |
| // abi::E_RASTER | |
| // abi::E_COMM | |
| _ => io::ErrorKind::Uncategorized, | |
| } | |
| } | |
| /// Similar to `ItronError::err_if_negative(er).expect()` except that, while | |
| /// panicking, it prints the message to `panic_output` and aborts the program | |
| /// instead. This ensures the error message is not obscured by double | |
| /// panicking. | |
| /// | |
| /// This is useful for diagnosing creation failures of synchronization | |
| /// primitives that are used by `std`'s internal mechanisms. Such failures | |
| /// are common when the system is mis-configured to provide a too-small pool for | |
| /// kernel objects. | |
| #[inline] | |
| pub fn expect_success(er: abi::ER, msg: &&str) -> abi::ER { | |
| match ItronError::err_if_negative(er) { | |
| Ok(x) => x, | |
| Err(e) => fail(e, msg), | |
| } | |
| } | |
| /// Similar to `ItronError::err_if_negative(er).expect()` but aborts instead. | |
| /// | |
| /// Use this where panicking is not allowed or the effect of the failure | |
| /// would be persistent. | |
| #[inline] | |
| pub fn expect_success_aborting(er: abi::ER, msg: &&str) -> abi::ER { | |
| match ItronError::err_if_negative(er) { | |
| Ok(x) => x, | |
| Err(e) => fail_aborting(e, msg), | |
| } | |
| } | |
| #[cold] | |
| pub fn fail(e: impl fmt::Display, msg: &&str) -> ! { | |
| if crate::thread::panicking() { | |
| fail_aborting(e, msg) | |
| } else { | |
| panic!("{} failed: {}", *msg, e) | |
| } | |
| } | |
| #[cold] | |
| pub fn fail_aborting(e: impl fmt::Display, msg: &&str) -> ! { | |
| rtabort!("{} failed: {}", *msg, e) | |
| } |