-
Notifications
You must be signed in to change notification settings - Fork 410
Implement futex_wait and futex_wake. #1568
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
Conversation
|
Before today I was only vaguely aware of the existence of |
This does not support futex_wait with a timeout yet.
futex_wake doesn't access the futex itself, so should accept pointers to memory that's no longer there.
|
Updated! Handling the |
RalfJung
left a comment
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.
We're getting there. :) In fact modulo comments I'd be fine landing this, though it does not yet entirely match the semantics you describe. But we can leave FIXMEs and do that later, whatever you prefer.
It would be good to have a test as well that directly probes the API -- but again we can leave that to the future, for now libstd itself serves as a test.
src/shims/posix/linux/sync.rs
Outdated
| // The first three arguments (after the syscall number itself) are the same to all futex operations: | ||
| // (int *addr, int op, int val). | ||
| // Although note that the first one is often passed as a different pointer type, e.g. `*const AtomicU32` or `*mut u32`. | ||
| let addr = this.deref_operand(args[1])?; |
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.
Wait, didn't you say that this point may in fact be dangling? That won't work like this. deref_operand requires that the pointer be dereferncable for the given type.
I am okay leaving this as a FIXME though. But eventually we should have a test for this.
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.
Wait, didn't you say that this point may in fact be dangling?
I did! I (mis)interpreted your comment above ..
Then later you can use
this.read_scalar(futex_val_place.offset)to read the actual data, andfutex_val_place.ptr.assert_ptr()to get thePointer. (deref_operanddoes the necessary int-to-ptr conversion.)
.. as that only read_scalar() requires the address to be readable, and that deref_operand only does the conversion to a pointer.
Anyway, this was the reason I kept the original addr around as a TyOp, separate from the Pointer, such that the FUTEX_WAIT path can still call deref_operand (or read_scalar_at_offset, which already does deref_operand) on it.
What's a good way to do this? Both operations need addr as Pointer, but one also needs to dereference the pointer (as i32).
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'm using force_ptr now instead of deref_operand. But using that Pointer to read the i32 pointee in FUTEX_WAIT seems tricky.
Now I'm using check_ptr_access followed by this.memory.get_raw(addr.alloc_id)?.read_scalar, but I don't know if that's a proper way to do it.
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.
Yes this is a tricky situation which I do not think we've had before. But get_raw feels like going down way too far the stack of abstractions.
I think the best way is to delay part of the decision: here at the top, just do let futex_val = this.read_immediate. Then also get the ptr value via force_ptr(futex_val.to_scalar()?). In the futex_wait branch, do deref_operand(futex_val.into())?. At least I think that should work.
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.
That only works if I do:
this.read_scalar(this.deref_operand(addr.into())?.offset(Size::ZERO, MemPlaceMeta::None, this.machine.layouts.i32, this)?.into())?.to_i32()?or
this.read_scalar_at_offset(addr.into(), 0, this.machine.layouts.i32)?.to_i32()?in the futex_wait branch. Otherwise it refuses to read a AtomicI32 as i32 again.
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.
Hm, now it fails if somebody calls syscall() with that futex address as a usize. Neither parking_lot nor std do that, but it might make sense as in Rust *const i32 is not Send, while usize is. And since this pointer may dangle, sending it to another thread might make sense.
I am confused actually, why does this fail? Without deref_operand I think this should work, but I might forget some check somewhere.
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.
Or was the actual problem that you passed 0usize? In that case the value would have been the problem, not the type -- i.e., 0usize as *const () would not work either. That is what the last comment that I added is about.
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 am confused actually, why does this fail?
Because in the example I also used the usize for the wait operation, which does dereference it.
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.
But it doesn't do that with deref_operand. So as long as the pointer points to something valid, with your current code, I think it should work fine both with usize and with a pointer type.
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.
Oh, read_scalar_at_offset uses deref_operand internally...
|
Added support FUTEX_WAIT with a timeout, and a test for park/park_timeout/unpark. Many of The Backtrace:Edit: Ah. I returned an |
|
All tests of
Many tests do result in Miri reporting a memory leak, but that's probably just a consequence of how parking_lot works. |
That's really cool. :)
So looks like this is not checked by the libstd user then? |
Otherwise `FUTEX_WAIT with timeout` will look weird.
Yup,
Yes, definitely. |
Added a test. |
6988f0c to
47128fa
Compare
Co-authored-by: Ralf Jung <post@ralfj.de>
Co-authored-by: Ralf Jung <post@ralfj.de>
|
Thanks a lot. :) @bors r+ |
|
📌 Commit 68776d2 has been approved by |
|
☀️ Test successful - checks-travis, status-appveyor |
Fixes rust-lang/rust#77406 and fixes #1562.
This makes std's park(), park_timeout(), and unpark() work. That means std::sync::Once is usable again and the test pass again with the latest rustc.
This also makes parking_lot work.