Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tracking: HIL methods that can fail should have ErrorCodes #1052

Open
2 of 9 tasks
ppannuto opened this issue Jun 30, 2018 · 6 comments
Open
2 of 9 tasks

Tracking: HIL methods that can fail should have ErrorCodes #1052

ppannuto opened this issue Jun 30, 2018 · 6 comments
Labels
HIL This affects a Tock HIL interface. tracking

Comments

@ppannuto
Copy link
Member

ppannuto commented Jun 30, 2018

Several of the older HILs just drop errors on the floor, and callers will assume they succeeded when they actually failed.

I seeded this tracking issue with a quick skim of the existing HILs. Some of these that are questions may not actually need changes, some may be missing. Please edit this comment as appropriate.

  • GPIO: Some pins don't have interrupt support, so enable_interrupt should fail. Maybe also make_[out/in]put.
  • I2C: Any bus operations that could fail
  • RNG: Maybe get can fail?
  • SPI: Why can read_write_bytes fail, but read_write_byte, write_byte, and read_byte can't?
  • symmetric_encryption: start_message should return EBUSY rather than dropping the new request
  • time: Are there cases where the tics value for set_alarm should return EINVAL or ESIZE? Should repeat be able to fail if the interval is too small?
  • Uart: Add ReturnCodes to UART HIL, change abort policy #1049
  • USB: At a minimum attach can fail
  • Watchdog: Should start be able to reject impossible periods?
@phil-levis
Copy link
Contributor

Generally speaking, almost every call in a HIL can have a failure condition. E.g., suppose that the operation is performed by a separate chip over a bus. E.g., an external encryption accelerator, a GPIO MUX, etc. This will involve an interaction over the bus to turn on/configure the other chip; what if the external chip does not respond correctly, e.g., there is a power problem. The interfaces to specific implementations might not have failure conditions, but the HIL needs to represent the union of all possible implementations.

Also, callbacks usually need to have ReturnCodes. If the call could fail, then it's possible the failure isn't detected until later, at which point it has to be signaled through the callback. E.g., suppose a call to symmetric encryption might fail because the data is the wrong length. The symmetric encryption engine is virtualized, so the fact that it's the wrong length isn't detected until after the initial call is made (and the call is forwarded to the underlying engine). If the virtualizer can detect it's the wrong length, this means the virtualizer has to repeat encryption-specific logic that's in the encryption implementation.

@alevy
Copy link
Member

alevy commented Jul 4, 2018

E.g., suppose that the operation is performed by a separate chip over a bus. E.g., an external encryption accelerator, a GPIO MUX, etc.

Maybe there are other examples of this that don't involve a chip over a bus, but in general, whether a particular HIL supports operations for a bus is explicit (e.g. gpio vs. gpio_async), and I think we don't want to change that.

So, for example, I think it's certainly fine for GPIO#set not to have a ReturnCode.

Even for some cases that are over a bus, like an external encryption accelerator, I'm not entirely sure how a client of the HIL would deal with an error like the peripheral chip not responding correctly in a reasonable way. I'm not saying suggesting one way or another whether encryption HIL's methods or callbacks should have a ReturnCode, just that I don't think it's that clear cut.

In general, having error cases greatly complicates writing client code, so it should be avoided if it's not necessary or useful.

@ppannuto
Copy link
Member Author

ppannuto commented Jul 4, 2018

I've been thinking about this a little, and I wonder if it's suboptimal for HIL methods to return generic ReturnCodes. There are currently 13 different types of failures in enum ReturnCode, but most HIL interfaces specify (in documentation only) that the HIL can only return 1-3 of these.

I don't have this idea totally fleshed out, but perhaps we could add some form of macro that would look something like:

return_codes![RNG::get,
    /// If SUCCESS is returned then the implementation MUST issue a randomness_available callback sometime in the future.
    SUCCESS,

    /// Indicates that the RNG is not currently powered/available. No callback will be generated.
    EOFF,

    /// Indicates a more general failure condition.
    FAIL,
]

pub trait RNG<'a> {
    fn get(&self) -> RNG::get::ReturnCode;
    ...
}

Where the macro enforces that the return codes supplied are all kernel ReturnCode types, and automatically implements from/to methods as appropriate. Now, however, callers could match over the HIL return and guarantee that they're handling all of the error cases.

Too complex to be useful / worth the effort, or worthwhile to help ease error handling / ensure correctness?

@bradjc
Copy link
Contributor

bradjc commented Jul 6, 2018

Handling ReturnCodes is hard, but if there is no mechanism to report errors that writing reliable long-running applications is hard too, so in general I think we do need a way to signal errors, but, I agree that we don't in the cases where something can't realistically fail.

Too complex to be useful / worth the effort, or worthwhile to help ease error handling / ensure correctness?

I'm not sure. I wonder how this could be implemented, because I imagine that in a lot of cases the handler of the HIL error is simply going to pass it to userspace.

@ppannuto
Copy link
Member Author

ppannuto commented Jul 6, 2018

I think the pass-through case is actually the easiest, since the syscall interface already takes the generic ReturnCode, the macros that would generate the HIL-specific types can implement from/to to allow casting from the HIL-specific return type to the generic ReturnCode, which can then be passed off to syscall response.

I think where this would really see use is where callers of the HIL do want to handle errors, so they match over the possible HIL return types, then if the HIL changes you get compiler assistance for cleaning up. If you don't match (or even if you do and you include a _ case) then you won't get help because you aren't really using the types. It's a sort of niche aide, but perhaps a useful one for letting people make guarantees about implementing the interface correctly/completely.

@bradjc bradjc added the HIL This affects a Tock HIL interface. label Jul 6, 2018
@phil-levis
Copy link
Contributor

phil-levis commented Jul 6, 2018 via email

@alevy alevy mentioned this issue Jul 6, 2018
2 tasks
@bradjc bradjc changed the title Tracking: HIL methods that can fail should have ReturnCodes Tracking: HIL methods that can fail should have ErrorCodes Apr 23, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
HIL This affects a Tock HIL interface. tracking
Projects
None yet
Development

No branches or pull requests

4 participants