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

Use zero-cost method to construct Errors #335

Closed

Conversation

TheSven73
Copy link
Collaborator

When constructing an Error, avoid the runtime check which verifies the errno invariant, by:

  • trusting that negative return values from certain kernel C functions always satisfy the invariant, and
  • using pre-constructed const Errors if an error return is needed in Rust code.

For the time being, no explicit Error invariant runtime checks are used or required anywhere, so we can eliminate the function which carries out the check.

@ksquirrel

This comment has been minimized.

@TheSven73 TheSven73 force-pushed the rust-for-linux-error-invariant branch from 4f424b2 to c23f634 Compare June 3, 2021 16:39
@ksquirrel

This comment has been minimized.

@TheSven73 TheSven73 force-pushed the rust-for-linux-error-invariant branch from c23f634 to 2f2c5ef Compare June 3, 2021 16:46
@ksquirrel

This comment has been minimized.

@ojeda
Copy link
Member

ojeda commented Jun 3, 2021

The first two commits have the same title and mostly the same message, which is a bit confusing: perhaps: "rust: introduce zero-cost from_kernel_int_result_uint" or something like that to see the difference between them?

(I noted to add a @ksquirrel check for this)

@ojeda
Copy link
Member

ojeda commented Jun 3, 2021

The third commit is related to #324 (comment) and #283 -- so not sure what to do. Also, I think @foxhlchen was going to send a PR to discuss moving it to return Result<Error> (i.e. Result<Error, Error>).

I think this is a good candidate for discussion this Saturday (and likely also in a technical meeting next week or so).

@TheSven73
Copy link
Collaborator Author

so not sure what to do. Also, I think @foxhlchen was going to send a PR to discuss moving it to return Result<Error> (i.e. Result<Error, Error>).

Perhaps we can bypass this whole discussion by not removing the runtime check function? That will of course generate a warning, as the function is now unused. I can add a dead-code marker. How does that sound?

Comment on lines 268 to 297
match retval {
success if success >= 0 => Ok(()),
// SAFETY: Safety above and match arm guarantee that `errno` is a valid negative `errno`.
errno => Err(Error::from_kernel_errno_unchecked(errno)),
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

match statements are great, but I think for cases like this where it reduces to a single condition it looks easier to read:

Suggested change
match retval {
success if success >= 0 => Ok(()),
// SAFETY: Safety above and match arm guarantee that `errno` is a valid negative `errno`.
errno => Err(Error::from_kernel_errno_unchecked(errno)),
}
if retval < 0 {
// SAFETY: Safety above and match arm guarantee that `errno` is a valid negative `errno`.
return Err(Error::from_kernel_errno_unchecked(errno));
}
Ok(())

pub(crate) unsafe fn from_kernel_int_result(retval: c_types::c_int) -> Result {
match retval {
success if success >= 0 => Ok(()),
// SAFETY: Safety above and match arm guarantee that `errno` is a valid negative `errno`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the comment, perhaps:

Suggested change
// SAFETY: Safety above and match arm guarantee that `errno` is a valid negative `errno`.
// SAFETY: This condition together with the function precondition guarantee
// `errno` is a valid negative `errno`.

rust/kernel/error.rs Outdated Show resolved Hide resolved
rust/kernel/error.rs Show resolved Hide resolved
@ojeda
Copy link
Member

ojeda commented Jun 3, 2021

Perhaps we can bypass this whole discussion by not removing the runtime check function? That will of course generate a warning, as the function is now unused. I can add a dead-code marker. How does that sound?

Sure, feel free to split the PR.

Sven Van Asbroeck added 3 commits June 3, 2021 20:04
In a previous PR, the type invariant for `Error` is enforced using
a runtime check. This is non-zero cost.

However we may decide to trust the return value of certain kernel C
functions. In such cases, no runtime check is required to enforce the
type invariant. So we can return to zero-cost.

This patch removes invariant checks from kernel C functions that
return 0 on success, or a non-zero errno on failure.

Signed-off-by: Sven Van Asbroeck <[email protected]>
In a previous PR, the type invariant for `Error` is enforced using
a runtime check. This is non-zero cost.

However we may decide to trust the return value of certain kernel C
functions. In such cases, no runtime check is required to enforce the
type invariant. So we can return to zero-cost.

This patch removes invariant checks from kernel C functions that
return a positive value on success, or a non-zero errno on failure.

Signed-off-by: Sven Van Asbroeck <[email protected]>
It turns out that we don't need an `Error` constructor that
checks the `errno` invariant at runtime. This is because we
trust return values originating from kernel C. And any return
values originating from Rust code can be constucted using
`Error::` constants, which also do not need a runtime check:

```rust
    return Err(Error::EBUSY);
```

However, there is still ongoing discussion about the merits and
purpose of this function. To facilitate this discussion, keep the
function for the time being, and remove the "dead code" warning.

Signed-off-by: Sven Van Asbroeck <[email protected]>
@TheSven73 TheSven73 force-pushed the rust-for-linux-error-invariant branch from 2f2c5ef to ec1faf3 Compare June 4, 2021 00:06
@ksquirrel
Copy link
Member

Review of ec1faf3ac524:

  • ✔️ Commit 5e932f0: Looks fine!
  • ✔️ Commit 79fcf6b: Looks fine!
  • ✔️ Commit ec1faf3: Looks fine!

@TheSven73
Copy link
Collaborator Author

v1 -> v2:

ojeda:

  • fix commit titles
  • keep function and remove dead code warning instead of removing function
  • use if instead of match to clarify control flow
  • clarify function docs
  • add unsafe blocks inside unsafe functions
  • clarify various comments

@foxhlchen
Copy link

The third commit is related to #324 (comment) and #283 -- so not sure what to do. Also, I think @foxhlchen was going to send a PR to discuss moving it to return Result<Error> (i.e. Result<Error, Error>).

I think this is a good candidate for discussion this Saturday (and likely also in a technical meeting next week or so).

You have a call on Saturday?? Can you send me an invitation??

@ojeda
Copy link
Member

ojeda commented Jun 4, 2021

Of course! We have informal calls every first Saturday of a month. I will send a remainder to the mailing list.

@foxhlchen
Copy link

Of course! We have informal calls every first Saturday of a month. I will send a remainder to the mailing list.

Great, Thank you!

@TheSven73
Copy link
Collaborator Author

@ojeda How can I assign a "Prio: low" label to this PR?

@TheSven73 TheSven73 closed this Jul 2, 2021
@TheSven73 TheSven73 deleted the rust-for-linux-error-invariant branch July 8, 2021 13:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

4 participants