Skip to content

Conversation

@tiif
Copy link
Member

@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
Member Author

tiif commented Aug 15, 2024

Just using an owned MPlaceTy should fix that.

This works, thanks!

@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.

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
Member 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.

@tiif
Copy link
Member 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
Member 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
Member 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
Member 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
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