-
Notifications
You must be signed in to change notification settings - Fork 355
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
Add callback support to FileDescription::read #4110
base: master
Are you sure you want to change the base?
Conversation
abfa97f
to
88cbd55
Compare
Hi @RalfJung, I wanted to share some updates and seek your guidance on a few points:
Thanks in advance for your help and guidance! Looking forward to your insights. |
@rustbot ready |
So this is blocked on #4106, I assume.
I would prefer if you could split this into two separate PRs. Refactoring an existing interface should not be done in the same changeset as adding new functionality, if it can be avoided. Splitting changes in smaller PRs greatly helps with making them easier to review. |
88cbd55
to
fb2d16a
Compare
Hi @RalfJung, Thank you for your feedback and for highlighting the review challenges—I completely understand. This PR focuses on two key changes:
Let me know if there's anything else you'd like me to adjust. Thanks! 🙂 |
@rustbot ready |
fb2d16a
to
59f70e8
Compare
This comment has been minimized.
This comment has been minimized.
src/shims/files.rs
Outdated
/// Represents an atomic I/O operation that handles data transfer between memory regions. | ||
/// Supports contiguous memory layouts for efficient I/O operations. | ||
#[derive(Clone)] | ||
pub struct IoTransferOperation<'tcx> { |
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 don't understand the point of all the new things you added here.
What I would expect is simply a new argument to read
that has a type like DynMachineCallback<Result<u64, IoError>>
. This can replace the existing dest: &MPlaceTy<'tcx>
.
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 don't understand the point of all the new things you added here.
What I would expect is simply a new argument to
read
that has a type likeDynMachineCallback<Result<u64, IoError>>
. This can replace the existingdest: &MPlaceTy<'tcx>
.
I need your guidance on the following:
-
I have not modified the signature of the
FileDescription::read()
function. Instead, I introduced a new function,FileDescription::read_with_callback()
, and integratedDynMachineCallback<Result<u64, IoError>>
as a replacement fordest: &MPlaceTy<'tcx>
. Below is the function definition for reference:fn read_with_callback<'tcx>( self: FileDescriptionRef<Self>, _communicate_allowed: bool, _ptr: Pointer, _len: usize, _completion_callback: DynFileIOCallback<'tcx>, _ecx: &mut MiriInterpCx<'tcx>, ) -> InterpResult<'tcx> { }
-
Modifying the signature of
FileDescription::read()
will affect the following modules. I need your input on how to adapt the signature changes for these modules:FileDescription for io::Stdin FileDescription for io::Stdout FileDescription for io::Stderr FileDescription for NullOutput FileDescription for AnonSocket FileDescription for Epoll FileDescription for EventFd
Let me know your thoughts and suggestions on how to proceed.
@rustbot ready
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.
Modifying the signature of FileDescription::read() will affect the following modules.
Correct, that's why this is a non-trivial change. But we don't want to have two read
functions for everything, so this work is necessary.
I have sketched the new signature above: replace dest: &MPlaceTy<'tcx>
by finish: DynMachineCallback<Result<u64, IoError>>
. The existing implementations should be adjusted to call the callback instead of writing to dest
.
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 would like your input on the top-level integration changes and testing strategy.
-
The integration of the updated
fn read()
signature has been completed for the following modules. Recent updates are now included as part of this patch:impl FileDescription for io::Stdin impl FileDescription for FileHandle impl FileDescription for AnonSocket impl FileDescription for EventFd
-
I ran the following command to test the changes, and the results align with the
upstream master
test results:
$ MIRIFLAGS=-Zmiri-disable-isolation MIRI_BACKTRACE=1 ./miri test
FAILURES:
tests/pass/alloc-access-tracking.rs
tests/pass/getpid.rs (revision with_isolation)
tests/pass/shims/time-with-isolation.rs
tests/pass/shims/env/var.rs
tests/pass/panic/thread_panic.rs
tests/pass/panic/concurrent-panic.rs
tests/pass/panic/nested_panic_caught.rs
tests/pass/panic/catch_panic.rs
test result: FAIL. 8 failed; 350 passed; 6 ignored
Error:
0: ui tests in tests/pass for x86_64-unknown-linux-gnu failed
1: tests failed
-
Integration for
FileHandle
is complete, but I am currently blocked on integrating the updatedfn read()
signature for the other modules (io::Stdin
,AnonSocket
, andEventFd
). -
Do we need to make any updates to
fn emulate_foreign_item_inner()
insrc/shims/unix/foreign_items.rs
to accommodate the changes in thefn read()
signature?
Now that #4106 landed, please rebase this over the latest miri HEAD. |
59f70e8
to
a54505c
Compare
src/concurrency/init_once.rs
Outdated
@@ -2,7 +2,7 @@ use std::collections::VecDeque; | |||
|
|||
use rustc_index::Idx; | |||
|
|||
use super::thread::DynUnblockCallback; | |||
use super::thread::DyMachineCallback; |
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.
You have changes in the first commit which are undone by the second commit -- please clea that up by squashing the two commits.
d98f7a2
to
dd7bea4
Compare
- Implementing atomic reads for contiguous buffers - Supports read operations with callback-based completion. Signed-off-by: shamb0 <[email protected]>
dd7bea4
to
2226854
Compare
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.
You have again dome some large-scale changes, this time adding a Mutex
, without asking any questions. There shouldn't be any large-scale changes needed, other than the direct consequences of changing the signature, just changing a few lines here and there. If you find yourself doing anything else, stop and reconsider. Maybe ask questions on Zulip. It's a waste of effort to implement a bunch of stuff that shouldn't exist in the first place.
I ran the following command to test the changes, and the results align with the upstream master test results:
The command to test Miri is ./miri test
; do not set MIRIFLAGS
. All tests should pass.
Do we need to make any updates to fn emulate_foreign_item_inner() in src/shims/unix/foreign_items.rs to accommodate the changes in the fn read() signature?
I don't know, you will notice that as you push the changes through the repo. But I expect no, the changes likely end here.
I would like your input on the top-level integration changes and testing strategy.
I don't have the time to prepare detailed mentoring instructions for you here, unfortunately. I described the intended design of the change and gave some feedback on your concrete implementation; if that is not sufficient for you to implement the PR (modulo issues with the Miri/rustc APIs) I suggest you pick something easier. Miri is a challenging codebase to contribute to. :)
@@ -121,6 +121,10 @@ impl<T: FileDescription + 'static> FileDescriptionExt for T { | |||
|
|||
pub type DynFileDescriptionRef = FileDescriptionRef<dyn FileDescription>; | |||
|
|||
/// Represents a dynamic callback for file I/O operations that is invoked upon completion. | |||
/// The callback receives either the number of bytes successfully read (u64) or an IoError. | |||
pub type DynFileDescriptionCallback<'tcx> = DynMachineCallback<'tcx, Result<u64, IoError>>; |
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.
DynFileOpFinishCallback
would be a better name IMO.
// Write the successfully read bytes to the destination pointer | ||
ecx.write_bytes_ptr(ptr, bytes[..actual_read_size].iter().copied())?; | ||
|
||
let Ok(read_size) = u64::try_from(actual_read_size) else { | ||
throw_unsup_format!( | ||
"Read operation returned size {} which exceeds maximum allowed value", | ||
actual_read_size | ||
) | ||
}; |
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.
Please keep using return_read_success
; that function should now take the callback instead of dest
.
The PR shouldn't change any of the logic nor add new logic; this kind of reshuffling of code just makes it unnecessarily hard to review. For instance, why did you move the let mut bytes
around, or add a new comment in code that you didn't change?
@@ -203,7 +203,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { | |||
interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?)) | |||
} | |||
|
|||
/// Read data from `fd` into buffer specified by `buf` and `count`. | |||
/// Reads data from a file descriptor using callback-based completion. |
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.
Why did you change this comment?
Err(_err_code) => { | ||
this.set_last_error_and_return(LibcError("EIO"), &result_destination) |
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.
Why EIO? And why are you ignoring err_code
here?
// We want to read at most `count` bytes. We are sure that `count` is not negative | ||
// because it was a target's `usize`. Also we are sure that its smaller than | ||
// `usize::MAX` because it is bounded by the host's `isize`. | ||
|
||
// Clone the result destination for use in the completion callback | ||
let result_destination = dest.clone(); |
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.
Please just call this dest
as we usually do.
@@ -23,6 +26,92 @@ use crate::*; | |||
struct FileHandle { | |||
file: File, | |||
writable: bool, | |||
/// Mutex for synchronizing file access across threads. | |||
file_lock: MutexRef, |
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.
Uh, what is this? No mutex should be added, please undo all that.
} else { | ||
// Synchronize with all prior `write` calls to this FD. | ||
ecx.acquire_clock(&eventfd.clock.borrow()); |
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.
These are more unnecessary changes. Why did you remove the else
and use an early return instead? Again, your PR should only change code that has to change for the callback to work. There are also a bunch of new comments and empty lines here for some reason.
But other than that, the changes in this file look exactly right!
Key Changes
IoTransferOperation
to manage atomic file transfersFileDescription::read
Context
This work completes stages 2 of the async file operations roadmap discussed here:
FileDescription::read
(this PR)readv()
using callbacks (this PR)