-
Notifications
You must be signed in to change notification settings - Fork 340
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
Implement blocking eventfd #3939
base: master
Are you sure you want to change the base?
Conversation
@rustbot author |
Hmm...why is rustfmt complaining? Let me try rebase it instead. |
src/shims/unix/linux/eventfd.rs
Outdated
let mut blocked_read_tid = self.blocked_read_tid.borrow_mut(); | ||
*blocked_read_tid = Some(ecx.active_thread()); |
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.
let mut blocked_read_tid = self.blocked_read_tid.borrow_mut(); | |
*blocked_read_tid = Some(ecx.active_thread()); | |
*self.blocked_read_tid.borrow_mut() = Some(ecx.active_thread()); |
You can save yourself a lot of RefCell panic trouble by doing the entire op in one go and thus not keeping the lock for the rest of the function
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.
Shouldn't this be a vec? Multiple threads could write and thus end up being blocked. Maybe add a test for that
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.
Yea I missed that and that's indeed a possible case. Multithreaded case is a bit more complicated, I need more time to think about this, but this is the case I am considering:
If there are main thread + 2 additional threads:
let the counter be u64::max, so any write
happened after will block.
2. thread1 try to write, and get blocked.
3. thread2 try to write, also get blocked.
4. Main thread read. Now, will thread1 and thread2 both get unblocked?
If both are unblocked, and thread1 is executed first. if thread1 write a u64::max again, thread2 should be blocked again. But the current implementation won't allow this to happen because thread2 is currently calling the unblock callback.
It also doesn't make sense to only unblock one thread, because the moment read
happens, both thread1 and thread2 indeed can write.
I will check what actually happened in real system.
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 eventfd will unblock every thread at once. So something like this will happen:
If there are main thread + 2 additional threads:
- let the counter be (u64::max - 1), so any write happened after will block.
- thread1 try to write, and get blocked.
- thread2 try to write, also get blocked.
- main thread read, so all thread gets unblocked
- thread1 unblocked and writes (u64::max - 1)
- thread 2 unblocked and try to continue writing (u64::max - 1), it gets block again
So essentially, we need might need to check the counter value and continue to block the thread again in the blocking callback functions. I am not sure how we can approach this without overcomplicated it because if we need to block a thread multiple times, we might run into something like:
- block_thread
- in the blocking callback, block_thread
- In the second block_thread callback, block_thread again
... and it continues
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 can have a fn eventfd_write
that blocks the thread if necessary, and in the "unblock" callback calls eventfd_write
again. Recursion is a thing. :)
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.
Yea, I think this will work. I feel this has an unfortunate consequence of making it more complex, but I couldn't see another solution for this.
☔ The latest upstream changes (presumably #3951) made this pull request unmergeable. Please resolve the merge conflicts. |
EDIT: Resolved, there is @oli-obk When running error: there were 1 unmatched diagnostics that occurred outside the testfile and had no pattern
Error: deadlock: the evaluated program deadlocked
error: there were 1 unmatched diagnostics
--> tests/fail-dep/libc/eventfd_block_twice.rs:1:1
|
1 | //@only-target: linux
| ^ Error: deadlock: the evaluated program deadlocked
| |
It still panic on blocked_write_tid borrow
This reverts commit 42890a9.
let mut waiter = Vec::new(); | ||
let mut blocked_write_tid = eventfd.blocked_write_tid.borrow_mut(); | ||
while let Some(tid) = blocked_write_tid.pop() { | ||
waiter.push(tid); | ||
} | ||
drop(blocked_write_tid); | ||
|
||
waiter.sort(); | ||
waiter.dedup(); | ||
for thread_id in waiter { | ||
ecx.unblock_thread(thread_id, BlockReason::Eventfd)?; | ||
} |
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 couldn't think of a testcase that can actually produce thread id duplication in blocked_write/read_id, but I will just keep the dedup
here first.
@rustbot ready |
This PR
fail-dep
BlockReason::Eventfd
cc #3665