-
Notifications
You must be signed in to change notification settings - Fork 164
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
Poll-based interface for DmaFile #446
base: master
Are you sure you want to change the base?
Conversation
Signed-off-by: Ruihang Xia <[email protected]>
Greetings @waynexia! It looks like your PR added a new or changed an existing dependency, and CI has failed to validate your changes.
Thank you! |
Unrelated change. Fix patch in #447 |
Hi @waynexia How is this better than using
I understand the above is obviously more code, but we don't expose a poll interface to anything, and the above is a idiomatic way how those things are usually done in Rust to the best of my knowledge Also @duarten , if you want to chime in, please do! |
Thanks @glommer. To use those async methods in the "poll" context, we need to store the future somewhere (to poll the same future again). And it's hard to write down the generated async future's type for keeping it without But this is not a big overhead after all. However exposing the poll-based interface obviously adds a lot of methods and structures. So this is just a draft proposal to bring a discussion on it. |
Can you post a concrete example where you had issues with this ? |
Signed-off-by: Ruihang Xia <[email protected]>
pub fn poll_read_aligned(file: &DmaFile, pos: u64, size: usize) -> PollReadAligned<'_> {
PollReadAligned {
task: Box::pin(file.read_at_aligned(pos, size)),
}
}
pub struct PollReadAligned<'a> {
task: Pin<Box<dyn Future<Output = Result<ReadResult>> + 'a>>,
}
impl Future for PollReadAligned<'_> {
type Output = Result<ReadResult>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.get_mut().task.as_mut().poll(cx)
}
} Something like this wraps the async API back to return
Correction: we can replace the async API with the poll-based version as ce17478 does. This only adds the new Future structs and the API can still be used like before. |
Greetings @waynexia! It looks like your PR added a new or changed an existing dependency, and CI has failed to validate your changes.
Thank you! |
I'm a bit confused because the PR just seems to manually writes out the future that Maybe I missed the actual goal here. Is it to have a non-future based interface where you periodically |
It just so happens that I'm dealing with a similar issue with some Glommio app myself. My case is slightly different but ends up being essentially the same. I am trying to compose multiple Glommio streams ( Of course, I want this API to be zero-copy, so I can't use
Except that it's an async function: I can't use it directly from Now back to the topic at hand: I could box the opaque type returned, store it on my stream struct, and call it a day. But I would have to use I understand @glommer's argument that this works just fine when you store the future on the stack, but that's not an option here. I am not sure the approach @waynexia is pushing for is the correct one. But I do see that none of the functions in |
Why can't you call an
Why would you need to use |
Greeting @duarten!
You can, but you can't
Using For the proposed poll api, you can either use the |
Howdy! :)
But it's the same thing with a non-async function: you also need to store the returned future.
That is true for the async version too: you can async fn f() {}
struct Pollable<F: Future> {
f: Pin<Box<F>>,
}
impl<F: Future> Pollable<F> {
pub fn poll(&mut self, cx: &mut Context<'_>) -> Poll<F::Output> {
self.f.as_mut().poll(cx)
}
}
fn as_pollable<F: Future>(f: F) -> Pollable<F> {
Pollable { f: Box::pin(f) }
}
fn main() {
let waker = noop_waker_ref();
let mut cx = std::task::Context::from_waker(waker);
let mut f = as_pollable(f());
let _ = f.poll(&mut cx);
} |
@duarten your example works because you use the stack for storage. Try to make this work with a stream, and you'll realize you can't always do that. I'm looking for a solution where boxing is a no-go (I don't want to allocate) and where
That's not always true. My stream struct is already pinned (via the |
Hum.. not sure I understand. Fundamentally, using a generated type vs a named typed implies you have to use generics, but that should be orthogonal to storage?
I don't quite understand that either. I thought (To be clear, I'm not pushing back on anything, I'm just trying to understand the issue. As you see, I don't have a lot of experience with the lower levels of async rust.) |
I think it's the right approach too! I've been trying to get this stream struct of mine working, and it's been a pain so far 😆. I find that not having a I did some additional investigation yesterday, and I came to the conclusion that what waynexia suggest is better than a named future for the following reason:
If this is useful, maybe @waynexia and I can write some small code examples to demonstrate our point? |
Ah, yes, I certainly see how those |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is a net improvement, and I'm ready to merge this, but before, I would like to ask that:
- The equivalent interface be written for the non-aligned variant
read_at
; - The
ImmutableFile
functions reflect this change too (should be a matter of changing the function signatures)
Hum.. I understand adding the |
Okay, I chatted with @HippoBaro and now I understand the issues. The goal is to make asynchronous functions more composable, either by providing Until then, named futures seem like a good approach. Maybe we can introduce a macro that will generate the future to avoid repeating this boilerplate all over the codebase. |
Thanks @duarten you definitely say it better than I do 😅
@waynexia how do you feel about giving this a try? There is potential to limit the boilerplate here. |
Sorry for the delay!
I'd like to😉. Let me try DmaFile first and see what happens. |
Signed-off-by: Ruihang Xia <[email protected]>
Signed-off-by: Ruihang Xia <[email protected]>
Greetings @waynexia! It looks like your PR added a new or changed an existing dependency, and CI has failed to validate your changes.
Thank you! |
1 similar comment
Greetings @waynexia! It looks like your PR added a new or changed an existing dependency, and CI has failed to validate your changes.
Thank you! |
/// Future of [`DmaFile::read_at_aligned`]. | ||
#[derive(Debug)] | ||
#[must_use = "future has no effect unless you .await or poll it"] | ||
pub struct PollDmaReadAtAligned<'a> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't figure out a good way to cover these structs into a macro 🤦♂️ Both the members and fn poll()
's bodies are different...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I put these structs in here for now. We can consider moving them to a separate file if more are added.
@@ -264,6 +264,15 @@ impl Source { | |||
}) | |||
.await | |||
} | |||
|
|||
pub(crate) fn poll_collect_rw(&self, cx: &mut Context<'_>) -> Poll<io::Result<usize>> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering whether we can make more use of this, like dma write or other files/resources' operation. Maybe we can track the progress in #445.
616409a
to
d480c63
Compare
Signed-off-by: Ruihang Xia [email protected]
What does this PR do?
Expose poll-based interface for DmaFile.
Motivation
#445
Related issues
#445
Additional Notes
Anything else we should know when reviewing?
Checklist
[] I have added unit tests to the code I am submitting
[] My unit tests cover both failure and success scenarios
[] If applicable, I have discussed my architecture