Skip to content

Commit 9bf68cd

Browse files
committed
implement the os_unfair_lock functions on macOS
1 parent 7184789 commit 9bf68cd

12 files changed

+201
-5
lines changed

src/concurrency/sync.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
269269
let this = self.eval_context_mut();
270270
if this.mutex_is_locked(mutex) {
271271
assert_ne!(this.mutex_get_owner(mutex), this.active_thread());
272-
this.mutex_enqueue_and_block(mutex, retval, dest);
272+
this.mutex_enqueue_and_block(mutex, Some(retval), dest);
273273
} else {
274274
// We can have it right now!
275275
this.mutex_lock(mutex);
@@ -392,7 +392,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
392392
/// Put the thread into the queue waiting for the mutex.
393393
/// Once the Mutex becomes available, `retval` will be written to `dest`.
394394
#[inline]
395-
fn mutex_enqueue_and_block(&mut self, id: MutexId, retval: Scalar, dest: MPlaceTy<'tcx>) {
395+
fn mutex_enqueue_and_block(
396+
&mut self,
397+
id: MutexId,
398+
retval: Option<Scalar>,
399+
dest: MPlaceTy<'tcx>,
400+
) {
396401
let this = self.eval_context_mut();
397402
assert!(this.mutex_is_locked(id), "queing on unlocked mutex");
398403
let thread = this.active_thread();
@@ -403,13 +408,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
403408
callback!(
404409
@capture<'tcx> {
405410
id: MutexId,
406-
retval: Scalar,
411+
retval: Option<Scalar>,
407412
dest: MPlaceTy<'tcx>,
408413
}
409414
@unblock = |this| {
410415
assert!(!this.mutex_is_locked(id));
411416
this.mutex_lock(id);
412-
this.write_scalar(retval, &dest)?;
417+
418+
if let Some(retval) = retval {
419+
this.write_scalar(retval, &dest)?;
420+
}
421+
413422
Ok(())
414423
}
415424
),

src/shims/unix/macos/foreign_items.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,70 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
174174
this.write_scalar(res, dest)?;
175175
}
176176

177+
"os_unfair_lock_lock" => {
178+
let [lock_op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
179+
let id =
180+
this.mutex_get_or_create_id(lock_op, this.libc_ty_layout("os_unfair_lock"), 0)?;
181+
182+
if this.mutex_is_locked(id) {
183+
if this.mutex_get_owner(id) == this.active_thread() {
184+
throw_machine_stop!(TerminationInfo::Abort(
185+
"attempted to lock an os_unfair_lock that is already locked by the current thread".to_owned()
186+
));
187+
}
188+
189+
this.mutex_enqueue_and_block(id, None, dest.clone());
190+
} else {
191+
this.mutex_lock(id);
192+
}
193+
}
194+
"os_unfair_lock_trylock" => {
195+
let [lock_op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
196+
let id =
197+
this.mutex_get_or_create_id(lock_op, this.libc_ty_layout("os_unfair_lock"), 0)?;
198+
199+
if this.mutex_is_locked(id) {
200+
this.write_scalar(Scalar::from_bool(false), dest)?;
201+
} else {
202+
this.mutex_lock(id);
203+
this.write_scalar(Scalar::from_bool(true), dest)?;
204+
}
205+
}
206+
"os_unfair_lock_unlock" => {
207+
let [lock_op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
208+
let id =
209+
this.mutex_get_or_create_id(lock_op, this.libc_ty_layout("os_unfair_lock"), 0)?;
210+
211+
if this.mutex_unlock(id)?.is_none() {
212+
throw_machine_stop!(TerminationInfo::Abort(
213+
"attempted to unlock an os_unfair_lock not owned by the current thread"
214+
.to_owned()
215+
));
216+
}
217+
}
218+
"os_unfair_lock_assert_owner" => {
219+
let [lock_op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
220+
let id =
221+
this.mutex_get_or_create_id(lock_op, this.libc_ty_layout("os_unfair_lock"), 0)?;
222+
223+
if !this.mutex_is_locked(id) || this.mutex_get_owner(id) != this.active_thread() {
224+
throw_machine_stop!(TerminationInfo::Abort(
225+
"called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread".to_owned()
226+
));
227+
}
228+
}
229+
"os_unfair_lock_assert_not_owner" => {
230+
let [lock_op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
231+
let id =
232+
this.mutex_get_or_create_id(lock_op, this.libc_ty_layout("os_unfair_lock"), 0)?;
233+
234+
if this.mutex_is_locked(id) && this.mutex_get_owner(id) == this.active_thread() {
235+
throw_machine_stop!(TerminationInfo::Abort(
236+
"called os_unfair_lock_assert_not_owner on an os_unfair_lock owned by the current thread".to_owned()
237+
));
238+
}
239+
}
240+
177241
_ => return Ok(EmulateItemResult::NotSupported),
178242
};
179243

src/shims/unix/sync.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
473473
let ret = if this.mutex_is_locked(id) {
474474
let owner_thread = this.mutex_get_owner(id);
475475
if owner_thread != this.active_thread() {
476-
this.mutex_enqueue_and_block(id, Scalar::from_i32(0), dest.clone());
476+
this.mutex_enqueue_and_block(id, Some(Scalar::from_i32(0)), dest.clone());
477477
return Ok(());
478478
} else {
479479
// Trying to acquire the same mutex again.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//@ only-target-darwin
2+
3+
use std::cell::UnsafeCell;
4+
5+
fn main() {
6+
let lock = UnsafeCell::new(libc::OS_UNFAIR_LOCK_INIT);
7+
8+
unsafe {
9+
libc::os_unfair_lock_lock(lock.get());
10+
libc::os_unfair_lock_assert_not_owner(lock.get());
11+
//~^ error: abnormal termination: called os_unfair_lock_assert_not_owner on an os_unfair_lock owned by the current thread
12+
}
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error: abnormal termination: called os_unfair_lock_assert_not_owner on an os_unfair_lock owned by the current thread
2+
--> $DIR/apple_os_unfair_lock_assert_not_owner.rs:LL:CC
3+
|
4+
LL | libc::os_unfair_lock_assert_not_owner(lock.get());
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ called os_unfair_lock_assert_not_owner on an os_unfair_lock owned by the current thread
6+
|
7+
= note: BACKTRACE:
8+
= note: inside `main` at $DIR/apple_os_unfair_lock_assert_not_owner.rs:LL:CC
9+
10+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
11+
12+
error: aborting due to 1 previous error
13+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//@ only-target-darwin
2+
3+
use std::cell::UnsafeCell;
4+
5+
fn main() {
6+
let lock = UnsafeCell::new(libc::OS_UNFAIR_LOCK_INIT);
7+
8+
unsafe {
9+
libc::os_unfair_lock_assert_owner(lock.get());
10+
//~^ error: abnormal termination: called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread
11+
}
12+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error: abnormal termination: called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread
2+
--> $DIR/apple_os_unfair_lock_assert_owner.rs:LL:CC
3+
|
4+
LL | libc::os_unfair_lock_assert_owner(lock.get());
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ called os_unfair_lock_assert_owner on an os_unfair_lock not owned by the current thread
6+
|
7+
= note: BACKTRACE:
8+
= note: inside `main` at $DIR/apple_os_unfair_lock_assert_owner.rs:LL:CC
9+
10+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
11+
12+
error: aborting due to 1 previous error
13+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//@ only-target-darwin
2+
3+
use std::cell::UnsafeCell;
4+
5+
fn main() {
6+
let lock = UnsafeCell::new(libc::OS_UNFAIR_LOCK_INIT);
7+
8+
unsafe {
9+
libc::os_unfair_lock_lock(lock.get());
10+
libc::os_unfair_lock_lock(lock.get());
11+
//~^ error: abnormal termination: attempted to lock an os_unfair_lock that is already locked by the current thread
12+
}
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error: abnormal termination: attempted to lock an os_unfair_lock that is already locked by the current thread
2+
--> $DIR/apple_os_unfair_lock_reentrant.rs:LL:CC
3+
|
4+
LL | libc::os_unfair_lock_lock(lock.get());
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to lock an os_unfair_lock that is already locked by the current thread
6+
|
7+
= note: BACKTRACE:
8+
= note: inside `main` at $DIR/apple_os_unfair_lock_reentrant.rs:LL:CC
9+
10+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
11+
12+
error: aborting due to 1 previous error
13+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//@ only-target-darwin
2+
3+
use std::cell::UnsafeCell;
4+
5+
fn main() {
6+
let lock = UnsafeCell::new(libc::OS_UNFAIR_LOCK_INIT);
7+
8+
unsafe {
9+
libc::os_unfair_lock_unlock(lock.get());
10+
//~^ error: abnormal termination: attempted to unlock an os_unfair_lock not owned by the current thread
11+
}
12+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error: abnormal termination: attempted to unlock an os_unfair_lock not owned by the current thread
2+
--> $DIR/apple_os_unfair_lock_unowned.rs:LL:CC
3+
|
4+
LL | libc::os_unfair_lock_unlock(lock.get());
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to unlock an os_unfair_lock not owned by the current thread
6+
|
7+
= note: BACKTRACE:
8+
= note: inside `main` at $DIR/apple_os_unfair_lock_unowned.rs:LL:CC
9+
10+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
11+
12+
error: aborting due to 1 previous error
13+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//@ only-target-darwin
2+
3+
use std::cell::UnsafeCell;
4+
5+
fn main() {
6+
let lock = UnsafeCell::new(libc::OS_UNFAIR_LOCK_INIT);
7+
8+
unsafe {
9+
libc::os_unfair_lock_lock(lock.get());
10+
libc::os_unfair_lock_assert_owner(lock.get());
11+
assert!(!libc::os_unfair_lock_trylock(lock.get()));
12+
libc::os_unfair_lock_unlock(lock.get());
13+
14+
libc::os_unfair_lock_assert_not_owner(lock.get());
15+
}
16+
17+
// `os_unfair_lock`s can be moved and leaked:
18+
let lock = lock;
19+
let locked = unsafe { libc::os_unfair_lock_trylock(lock.get()) };
20+
assert!(locked);
21+
}

0 commit comments

Comments
 (0)