-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Make sure Mutex and RwLock can't be re-locked on the same thread #33861
Conversation
I don't have any tests for this because I'm not sure how I can write a test to ensure that an operation successfully deadlocks... |
pub struct RWLock { inner: UnsafeCell<libc::pthread_rwlock_t> } | ||
pub struct RWLock { | ||
inner: UnsafeCell<libc::pthread_rwlock_t>, | ||
write_locked: Cell<bool>, |
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.
This is technically accessed concurrently so could this switch to being an UnsafeCell
as well?
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.
Doesn't Cell
also allow concurrent access? Neither of them have the Sync
marker, but that doesn't matter since that marker added to RWLock
4 lines later.
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.
Semantically the usage here is fine, but Cell
is not Sync
and it's technically used in an unsafe fashion here. It's not normally safe to access it on many threads, but the readers will read it concurrently here.
But yeah this would just to be a bit "more correct", it wouldn't actually change anything about the implementation.
Thanks @Amanieu! My digging around indicates, though, that this only may fix the problem for rwlocks. The standard no longer explicitly says that relocking is undefined behavior, but it doesn't say what the behavior is beyond that it might deadlock. In that sense it could be possible that this is still undefined, in which case we may need to find another solution. In any case though this seems like the best solution for now as it should be guaranteed to fix mutexes and it likely fixes rwlocks on all implementations. |
@@ -30,6 +30,20 @@ impl Mutex { | |||
Mutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) } | |||
} | |||
#[inline] | |||
pub unsafe fn init(&mut self) { | |||
// We need to set the mutex type to PTHREAD_MUTEX_NORMAL to avoid | |||
// undefined behavior when re-locking in the same 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.
Could this expand a bit and link to the lock elision issue and perhaps a link to the standard as well? Something along the lines of the default being DEFAULT which has recursive locking as undefined behavior, but we need to guarantee somehow that a recursive lock never returns (either deadlock or panic)
This actually seems subtle enough that we should probably add some tests. The semantics here aren't actually really testing for deadlock more so that the second lock never returns. Perhaps a test could be added like: let lock = ..;
let _l1 = lock.lock();
let _l2 = lock.lock();
println!("oops!"); The test can then exec itself, capturing output. If after something like a second has passed and the process hasn't exited we can also send it a kill signal. Then the test could just be that the output doesn't contain "oops!". Not exactly a foolproof test, but we should run it dozens of times a day on bors, so if it's ever spurious we'll pick up on that and it'll be pretty obvious what the fix is :) |
efc8732
to
b003f2e
Compare
OK this should handle all of the cases, but the code is now quite ugly :/ |
⌛ Testing commit 8999243 with merge 85c9847... |
💔 Test failed - auto-linux-64-opt-rustbuild |
@bors retry |
⌛ Testing commit 8999243 with merge 1312a32... |
💔 Test failed - auto-linux-cross-opt |
Updated libc, should work now |
@bors: r+ 5708cf7b691b752798098ce1bf3117a682f76668 |
⌛ Testing commit 5708cf7 with merge be4ac33... |
💔 Test failed - auto-linux-64-cross-armhf |
@bors: reetry On Tue, May 31, 2016 at 3:37 PM, bors notifications@github.com wrote:
|
@bors: retry On Tue, May 31, 2016 at 4:14 PM, Alex Crichton alex@alexcrichton.com
|
Travis fails |
@Manishearth Travis is busted again, apt-get can't get llvm, AFAICT. |
⌛ Testing commit 5708cf7 with merge 03dd3a9... |
💔 Test failed - auto-win-msvc-64-opt-rustbuild |
The only applies to pthread mutexes. We solve this by creating the mutex with the PTHREAD_MUTEX_NORMAL type, which guarantees that re-locking from the same thread will deadlock.
This is allowed by POSIX and can happen on glibc with processors that support hardware lock elision.
Fixed the test on windows |
@bors r=alexcrichton |
📌 Commit fc4b356 has been approved by |
Make sure Mutex and RwLock can't be re-locked on the same thread Fixes #33770 r? @alexcrichton
Fixes #33770
r? @alexcrichton