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

Support blocking for epoll #3804

Merged
merged 13 commits into from
Aug 27, 2024
Merged

Support blocking for epoll #3804

merged 13 commits into from
Aug 27, 2024

Conversation

tiif
Copy link
Contributor

@tiif tiif commented Aug 14, 2024

This PR enabled epoll to have blocking operation.

The changes introduced by this PR are:

  • Refactored part of the logic in epoll_wait to blocking_epoll_callback
  • Added a new field thread_ids in Epoll for blocked thread ids
  • Added a new BlockReason::Epoll

@RalfJung
Copy link
Member

RalfJung commented Aug 14, 2024

place: &'tcx MPlaceTy<'tcx> is required to be annotated with 'tcx.

This should be place: MPlaceTy<'tcx>. (Use clone if needed.) I have no idea how you even got a reference with 'tcx lifetime...

EDIT: Ah, you don't. And it is indeed impossible, this approach is a dead end. Just using an owned MPlaceTy should fix that. :)

@bors
Copy link
Contributor

bors commented Aug 14, 2024

☔ The latest upstream changes (presumably #3712) made this pull request unmergeable. Please resolve the merge conflicts.

@tiif
Copy link
Contributor Author

tiif commented Aug 15, 2024

Just using an owned MPlaceTy should fix that.

This works, thanks!

src/shims/unix/fd.rs Outdated Show resolved Hide resolved
src/shims/unix/linux/epoll.rs Outdated Show resolved Hide resolved
@bors
Copy link
Contributor

bors commented Aug 16, 2024

☔ The latest upstream changes (presumably #3809) made this pull request unmergeable. Please resolve the merge conflicts.

@RalfJung
Copy link
Member

I wonder if it would make sense to implement #3665 first, as that's a much easier case of blocking? That might be a good way to learn how Miri deals with blocking.

@oli-obk
Copy link
Contributor

oli-obk commented Aug 17, 2024

That's what I said, too, in our last meeting, and we realized it is not easier, as you need to refactor all read/write methods instead of just focussing on this one

@oli-obk
Copy link
Contributor

oli-obk commented Aug 17, 2024

(If those are done first, I'd like to have a PR that passes dest to r/w and writes directly from there instead of returning the io result.)

@RalfJung
Copy link
Member

RalfJung commented Aug 17, 2024

That's what I said, too, in our last meeting, and we realized it is not easier, as you need to refactor all read/write methods instead of just focussing on this one

Oh wait, so that does not have to happen for this one? Ah right, the blocking is in epoll_wait, not in read/write... makes sense.

src/shims/unix/fd.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@oli-obk oli-obk left a comment

Choose a reason for hiding this comment

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

Please bless and fix the tokio sleep test

// Collect all thread id of blocked threads that received notification.
let thread_id = epoll_event_interest.thread_id;
if this.has_blocked_on_epoll(thread_id) {
waiters.push(thread_id);
Copy link
Contributor

Choose a reason for hiding this comment

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

could also just wake here and record in a hashset whether the thread id was already woken

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For the new change in 9cb087d, I was trying to avoid using this.unblock_thread inside

if let Some(epoll_interests) = this.machine.epoll_interests.get_epoll_interest(id) { }

because it will trigger this error:

error[E0502]: cannot borrow `*this` as mutable because it is also borrowed as immutable
   --> src/shims/unix/linux/epoll.rs:594:29
    |
568 |         if let Some(epoll_interests) = this.machine.epoll_interests.get_epoll_interest(id) {
    |                                        ---------------------------- immutable borrow occurs here
...
573 |             for weak_epoll_interest in epoll_interests {
    |                                        --------------- immutable borrow later used here
...
594 |                             this.unblock_thread(thread_id, BlockReason::Epoll)?;
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here

So instead I just store the ThreadIds that I want to unblock into a Vec then unblock them altogether outside of the block.

src/shims/unix/linux/epoll.rs Outdated Show resolved Hide resolved
src/shims/unix/linux/epoll.rs Outdated Show resolved Hide resolved
src/shims/unix/linux/epoll.rs Show resolved Hide resolved
@tiif
Copy link
Contributor Author

tiif commented Aug 23, 2024

This is how it currently works:
Edge-triggered notification (which is what we currently supporting) will only unblock one thread when a notification is received, even when multiple threads are blocked on the same epoll instance. So before we call this.block_thread, we record the ThreadId in Epoll file description using the thread_id field:

struct Epoll {
    /// A map of EpollEventInterests registered under this epoll instance.
    /// Each entry is differentiated using FdId and file descriptor value.
    interest_list: RefCell<BTreeMap<(FdId, i32), Rc<RefCell<EpollEventInterest>>>>,
    /// A map of EpollEventInstance that will be returned when `epoll_wait` is called.
    /// Similar to interest_list, the entry is also differentiated using FdId
    /// and file descriptor value.
    // This is an Rc because EpollInterest need to hold a reference to update
    // it.
    ready_list: Rc<RefCell<BTreeMap<(FdId, i32), EpollEventInstance>>>,
    /// A list of thread ids blocked on this epoll instance.
    thread_id: RefCell<Vec<ThreadId>>, // < this is newly added
}

Later in check_and_update_readiness, when we return a notification, we retrieve the list of blocked thread in that epoll instance, then unblock one of them.

@tiif
Copy link
Contributor Author

tiif commented Aug 24, 2024

@rustbot ready

@rustbot rustbot added S-waiting-on-review Status: Waiting for a review to complete and removed S-waiting-on-author Status: Waiting for the PR author to address review comments labels Aug 24, 2024
@oli-obk
Copy link
Contributor

oli-obk commented Aug 24, 2024

The PR's main message is a bit outdated

@tiif
Copy link
Contributor Author

tiif commented Aug 25, 2024

Do we want another test for triggering a notification after the epoll_wait times out or is the sleep.rs test good enough?

@RalfJung
Copy link
Member

RalfJung commented Aug 25, 2024 via email

@tiif
Copy link
Contributor Author

tiif commented Aug 25, 2024

But doesn't test_epoll_block_without_notification do that?

No, that test only epoll_wait, then timeout without notification. A notification need to be sent after timeout to trigger the bug. Also there is an error on the comment for that test, sorry for the confusion.

@RalfJung
Copy link
Member

Okay, just make sure the test has a comment explaining the exact scenario. :)

@tiif tiif mentioned this pull request Aug 27, 2024
@oli-obk
Copy link
Contributor

oli-obk commented Aug 27, 2024

@bors r+

@bors
Copy link
Contributor

bors commented Aug 27, 2024

📌 Commit 2523c17 has been approved by oli-obk

It is now in the queue for this repository.

@bors
Copy link
Contributor

bors commented Aug 27, 2024

⌛ Testing commit 2523c17 with merge 297482d...

@bors
Copy link
Contributor

bors commented Aug 27, 2024

☀️ Test successful - checks-actions
Approved by: oli-obk
Pushing 297482d to master...

@bors bors merged commit 297482d into rust-lang:master Aug 27, 2024
8 checks passed
bors added a commit that referenced this pull request Aug 28, 2024
Add tokio io test

After #3804 landed, these tests passed.
@tiif tiif deleted the blockit branch October 26, 2024 17:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Waiting for a review to complete
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants