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

epoll: iterate through output buffer then fetch an event from ready list #3818

Merged
merged 1 commit into from
Aug 18, 2024

Conversation

tiif
Copy link
Contributor

@tiif tiif commented Aug 17, 2024

Fixes #3812

@tiif tiif mentioned this pull request Aug 17, 2024
if let Some(des) = array_iter.next(this)? {
while let Some(des) = array_iter.next(this)? {
// Fetch an event from the ready list.
if let Some((epoll_key, epoll_return)) = ready_list.pop_first() {
Copy link
Contributor

Choose a reason for hiding this comment

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

This will cause empty entries whenever a FD was already closed. You'll need to use a for loop here and exit it only if you actually write an entry.

This will cause us to finish iterating over the array_iter and never doing anything once the ready list is empty. That's fine, but we could also ensure we continue to the outer loop (by giving it a label) and unconditionally breaking after the ready list loop

Copy link
Contributor

Choose a reason for hiding this comment

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

(fwiw: this is why we abandoned this approach before, but forgot that in abandoning it we'd not fix this issue)

Copy link
Member

Choose a reason for hiding this comment

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

Indeed, this needs to be a loop getting the next entry from the ready list that refers to an FD that is still open.

(I assume there's a test covering this case? That test would generate an interesting event on an FD, and then close the FD, and only then call epoll_wait and expect to not see that event.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right, the test that I added initially failed because there is empty entry where it shouldn't. I added a condition to check if the entry is actually written, also terminate earlier if the ready list is empty (although this won't affect correctness).

while let Some(des) = array_iter.next(this)?
&& !ready_list.is_empty()
{
let mut entry_written = false;
Copy link
Member

@RalfJung RalfJung Aug 17, 2024

Choose a reason for hiding this comment

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

I don't think using mutable state is necessary here. That makes reasoning about the code harder. The !is_empty check above also adds extra complexity that should not be needed.

Instead, I suggest you add a function like ready_list_next that returns the next item from the ready list that someone is still interested in:

while let Some((epoll_key, epoll_return)) = ready_list.pop_first() {
  // Ensure we are still interested in this event. The FD might have been closed since
  // the event was generated, in which case we are not interested any more.
  if this.machine.epoll_interests.get_epoll_interest(epoll_key.0).is_some() {
    return Some((epoll_key, epoll_return));
  }
}
return None;

Then you just use that function here, using a simple for loop.

Copy link
Contributor Author

@tiif tiif Aug 17, 2024

Choose a reason for hiding this comment

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

Updated, thanks for the detailed suggestion. By the way, if the for loop you meant is for while let Some(des) = array_iter.next(this)? , it might not be possible because ArrayIterator, which is the type of array_iter, doesn't implement IntoIterator.

Copy link
Member

Choose a reason for hiding this comment

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

Ah right this has to remain while let, good point.

@tiif
Copy link
Contributor Author

tiif commented Aug 17, 2024

@rustbot ready

@rustbot rustbot added the S-waiting-on-review Status: Waiting for a review to complete label Aug 17, 2024
}
}
Ok(Scalar::from_i32(num_of_events))
}

/// This function takes in ready list and returns EpollEventInstance with file description
/// that is not closed.
fn ready_list_next(
Copy link
Member

Choose a reason for hiding this comment

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

You are adding this as a public function that can be called everywhere in Miri -- that's not the intention, as this is just a private helper. Please make the function private.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I moved this out and turned this a free function. Alternatively, we can create a wrapper type for ready_list and make this a method of that type.

Copy link
Member

Choose a reason for hiding this comment

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

A free function sounds good for this!

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 Outdated Show resolved Hide resolved
tests/pass-dep/libc/libc-epoll.rs Outdated Show resolved Hide resolved
@bors
Copy link
Contributor

bors commented Aug 17, 2024

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

@RalfJung
Copy link
Member

Looks good, thanks. :) Please squash the commits.

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

bors commented Aug 18, 2024

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

@tiif
Copy link
Contributor Author

tiif commented Aug 18, 2024

@RalfJung The CI is green here, would you like to land this first? I will go back #3820 to resolve potential merge conflict after this landed.

@RalfJung
Copy link
Member

Okay :)
@bors r+

@bors
Copy link
Contributor

bors commented Aug 18, 2024

📌 Commit d9e152b has been approved by RalfJung

It is now in the queue for this repository.

@bors
Copy link
Contributor

bors commented Aug 18, 2024

⌛ Testing commit d9e152b with merge 6c93473...

@bors
Copy link
Contributor

bors commented Aug 18, 2024

☀️ Test successful - checks-actions
Approved by: RalfJung
Pushing 6c93473 to master...

@bors bors merged commit 6c93473 into rust-lang:master Aug 18, 2024
8 checks passed
@tiif tiif deleted the loseevents branch August 18, 2024 10:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-author Status: Waiting for the PR author to address review comments
Projects
None yet
Development

Successfully merging this pull request may close these issues.

epoll_wait can lose events when they do not all fit into the output buffer
5 participants