forked from rust-lang/rust
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto merge of rust-lang#3745 - joboet:os_unfair_lock, r=RalfJung
Implement the `os_unfair_lock` functions on macOS These are needed for rust-lang#122408. See the documentation [here](https://developer.apple.com/documentation/os/synchronization?language=objc) and the implementation [here](https://github.com/apple-oss-distributions/libplatform/blob/a00a4cc36da2110578bcf3b8eeeeb93dcc7f4e11/src/os/lock.c#L645).
- Loading branch information
Showing
15 changed files
with
284 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
pub mod foreign_items; | ||
pub mod sync; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
//! Contains macOS-specific synchronization functions. | ||
//! | ||
//! For `os_unfair_lock`, see the documentation | ||
//! <https://developer.apple.com/documentation/os/synchronization?language=objc> | ||
//! and in case of underspecification its implementation | ||
//! <https://github.com/apple-oss-distributions/libplatform/blob/a00a4cc36da2110578bcf3b8eeeeb93dcc7f4e11/src/os/lock.c#L645>. | ||
//! | ||
//! Note that we don't emulate every edge-case behaviour of the locks. Notably, | ||
//! we don't abort when locking a lock owned by a thread that has already exited | ||
//! and we do not detect copying of the lock, but macOS doesn't guarantee anything | ||
//! in that case either. | ||
use crate::*; | ||
|
||
impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {} | ||
trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { | ||
fn os_unfair_lock_getid(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx, MutexId> { | ||
let this = self.eval_context_mut(); | ||
// os_unfair_lock holds a 32-bit value, is initialized with zero and | ||
// must be assumed to be opaque. Therefore, we can just store our | ||
// internal mutex ID in the structure without anyone noticing. | ||
this.mutex_get_or_create_id(lock_op, this.libc_ty_layout("os_unfair_lock"), 0) | ||
} | ||
} | ||
|
||
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} | ||
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { | ||
fn os_unfair_lock_lock(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> { | ||
let this = self.eval_context_mut(); | ||
|
||
let id = this.os_unfair_lock_getid(lock_op)?; | ||
if this.mutex_is_locked(id) { | ||
if this.mutex_get_owner(id) == this.active_thread() { | ||
// Matching the current macOS implementation: abort on reentrant locking. | ||
throw_machine_stop!(TerminationInfo::Abort( | ||
"attempted to lock an os_unfair_lock that is already locked by the current thread".to_owned() | ||
)); | ||
} | ||
|
||
this.mutex_enqueue_and_block(id, None); | ||
} else { | ||
this.mutex_lock(id); | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
fn os_unfair_lock_trylock( | ||
&mut self, | ||
lock_op: &OpTy<'tcx>, | ||
dest: &MPlaceTy<'tcx>, | ||
) -> InterpResult<'tcx> { | ||
let this = self.eval_context_mut(); | ||
|
||
let id = this.os_unfair_lock_getid(lock_op)?; | ||
if this.mutex_is_locked(id) { | ||
// Contrary to the blocking lock function, this does not check for | ||
// reentrancy. | ||
this.write_scalar(Scalar::from_bool(false), dest)?; | ||
} else { | ||
this.mutex_lock(id); | ||
this.write_scalar(Scalar::from_bool(true), dest)?; | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
fn os_unfair_lock_unlock(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> { | ||
let this = self.eval_context_mut(); | ||
|
||
let id = this.os_unfair_lock_getid(lock_op)?; | ||
if this.mutex_unlock(id)?.is_none() { | ||
// Matching the current macOS implementation: abort. | ||
throw_machine_stop!(TerminationInfo::Abort( | ||
"attempted to unlock an os_unfair_lock not owned by the current thread".to_owned() | ||
)); | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
fn os_unfair_lock_assert_owner(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> { | ||
let this = self.eval_context_mut(); | ||
|
||
let id = this.os_unfair_lock_getid(lock_op)?; | ||
if !this.mutex_is_locked(id) || this.mutex_get_owner(id) != this.active_thread() { | ||
throw_machine_stop!(TerminationInfo::Abort( | ||
"called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread".to_owned() | ||
)); | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
fn os_unfair_lock_assert_not_owner(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> { | ||
let this = self.eval_context_mut(); | ||
|
||
let id = this.os_unfair_lock_getid(lock_op)?; | ||
if this.mutex_is_locked(id) && this.mutex_get_owner(id) == this.active_thread() { | ||
throw_machine_stop!(TerminationInfo::Abort( | ||
"called os_unfair_lock_assert_not_owner on an os_unfair_lock owned by the current thread".to_owned() | ||
)); | ||
} | ||
|
||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
13 changes: 13 additions & 0 deletions
13
src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
//@ only-target-darwin | ||
|
||
use std::cell::UnsafeCell; | ||
|
||
fn main() { | ||
let lock = UnsafeCell::new(libc::OS_UNFAIR_LOCK_INIT); | ||
|
||
unsafe { | ||
libc::os_unfair_lock_lock(lock.get()); | ||
libc::os_unfair_lock_assert_not_owner(lock.get()); | ||
//~^ error: abnormal termination: called os_unfair_lock_assert_not_owner on an os_unfair_lock owned by the current thread | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_not_owner.stderr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
error: abnormal termination: called os_unfair_lock_assert_not_owner on an os_unfair_lock owned by the current thread | ||
--> $DIR/apple_os_unfair_lock_assert_not_owner.rs:LL:CC | ||
| | ||
LL | libc::os_unfair_lock_assert_not_owner(lock.get()); | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ called os_unfair_lock_assert_not_owner on an os_unfair_lock owned by the current thread | ||
| | ||
= note: BACKTRACE: | ||
= note: inside `main` at $DIR/apple_os_unfair_lock_assert_not_owner.rs:LL:CC | ||
|
||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace | ||
|
||
error: aborting due to 1 previous error | ||
|
12 changes: 12 additions & 0 deletions
12
src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
//@ only-target-darwin | ||
|
||
use std::cell::UnsafeCell; | ||
|
||
fn main() { | ||
let lock = UnsafeCell::new(libc::OS_UNFAIR_LOCK_INIT); | ||
|
||
unsafe { | ||
libc::os_unfair_lock_assert_owner(lock.get()); | ||
//~^ error: abnormal termination: called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_assert_owner.stderr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
error: abnormal termination: called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread | ||
--> $DIR/apple_os_unfair_lock_assert_owner.rs:LL:CC | ||
| | ||
LL | libc::os_unfair_lock_assert_owner(lock.get()); | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread | ||
| | ||
= note: BACKTRACE: | ||
= note: inside `main` at $DIR/apple_os_unfair_lock_assert_owner.rs:LL:CC | ||
|
||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace | ||
|
||
error: aborting due to 1 previous error | ||
|
13 changes: 13 additions & 0 deletions
13
src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
//@ only-target-darwin | ||
|
||
use std::cell::UnsafeCell; | ||
|
||
fn main() { | ||
let lock = UnsafeCell::new(libc::OS_UNFAIR_LOCK_INIT); | ||
|
||
unsafe { | ||
libc::os_unfair_lock_lock(lock.get()); | ||
libc::os_unfair_lock_lock(lock.get()); | ||
//~^ error: abnormal termination: attempted to lock an os_unfair_lock that is already locked by the current thread | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_reentrant.stderr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
error: abnormal termination: attempted to lock an os_unfair_lock that is already locked by the current thread | ||
--> $DIR/apple_os_unfair_lock_reentrant.rs:LL:CC | ||
| | ||
LL | libc::os_unfair_lock_lock(lock.get()); | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to lock an os_unfair_lock that is already locked by the current thread | ||
| | ||
= note: BACKTRACE: | ||
= note: inside `main` at $DIR/apple_os_unfair_lock_reentrant.rs:LL:CC | ||
|
||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace | ||
|
||
error: aborting due to 1 previous error | ||
|
12 changes: 12 additions & 0 deletions
12
src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
//@ only-target-darwin | ||
|
||
use std::cell::UnsafeCell; | ||
|
||
fn main() { | ||
let lock = UnsafeCell::new(libc::OS_UNFAIR_LOCK_INIT); | ||
|
||
unsafe { | ||
libc::os_unfair_lock_unlock(lock.get()); | ||
//~^ error: abnormal termination: attempted to unlock an os_unfair_lock not owned by the current thread | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
src/tools/miri/tests/fail-dep/concurrency/apple_os_unfair_lock_unowned.stderr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
error: abnormal termination: attempted to unlock an os_unfair_lock not owned by the current thread | ||
--> $DIR/apple_os_unfair_lock_unowned.rs:LL:CC | ||
| | ||
LL | libc::os_unfair_lock_unlock(lock.get()); | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to unlock an os_unfair_lock not owned by the current thread | ||
| | ||
= note: BACKTRACE: | ||
= note: inside `main` at $DIR/apple_os_unfair_lock_unowned.rs:LL:CC | ||
|
||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace | ||
|
||
error: aborting due to 1 previous error | ||
|
25 changes: 25 additions & 0 deletions
25
src/tools/miri/tests/pass-dep/concurrency/apple-os-unfair-lock.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
//@ only-target-darwin | ||
|
||
use std::cell::UnsafeCell; | ||
|
||
fn main() { | ||
let lock = UnsafeCell::new(libc::OS_UNFAIR_LOCK_INIT); | ||
|
||
unsafe { | ||
libc::os_unfair_lock_lock(lock.get()); | ||
libc::os_unfair_lock_assert_owner(lock.get()); | ||
assert!(!libc::os_unfair_lock_trylock(lock.get())); | ||
libc::os_unfair_lock_unlock(lock.get()); | ||
|
||
libc::os_unfair_lock_assert_not_owner(lock.get()); | ||
} | ||
|
||
// `os_unfair_lock`s can be moved and leaked. | ||
// In the real implementation, even moving it while locked is possible | ||
// (and "forks" the lock, i.e. old and new location have independent wait queues); | ||
// Miri behavior differs here and anyway none of this is documented. | ||
let lock = lock; | ||
let locked = unsafe { libc::os_unfair_lock_trylock(lock.get()) }; | ||
assert!(locked); | ||
let _lock = lock; | ||
} |