-
Notifications
You must be signed in to change notification settings - Fork 353
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 futex_wait and futex_wake. #1568
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 |
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_operand
does 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.