blob: 1f8bc81d85eb5fc99db6acc32ae8f527e2c6c6a3 [file] [log] [blame]
//@compile-flags: -Zmiri-genmc -Zmiri-disable-stacked-borrows -Zmiri-genmc-verbose
//@normalize-stderr-test: "Verification took .*s" -> "Verification took [TIME]s"
// Test various features of the `std::sync::Mutex` API with GenMC.
// Miri running with GenMC intercepts the Mutex functions `lock`, `try_lock` and `unlock`, instead of running their actual implementation.
// This interception should not break any functionality.
//
// FIXME(genmc): Once GenMC supports mixed size accesses, add stack/heap allocated Mutexes to the test.
// FIXME(genmc): Once the actual implementation of mutexes can be used in GenMC mode and there is a setting to disable Mutex interception: Add test revision without interception.
//
// Miri provides annotations to GenMC for the condition required to unblock a thread blocked on a Mutex lock call.
// This massively reduces the number of blocked executions we need to explore (in this test we require zero blocked execution).
// We use verbose output to check that this test always explores zero blocked executions.
#![no_main]
#![feature(abort_unwind)]
#[path = "../../../utils/genmc.rs"]
mod genmc;
use std::sync::Mutex;
use crate::genmc::*;
const REPS: u64 = 3;
static LOCK: Mutex<u64> = Mutex::new(0);
static OTHER_LOCK: Mutex<u64> = Mutex::new(1234);
#[unsafe(no_mangle)]
fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
std::panic::abort_unwind(main_);
0
}
fn main_() {
// Two mutexes should not interfere, holding this guard does not affect the other mutex.
let other_guard = OTHER_LOCK.lock().unwrap();
let guard = LOCK.lock().unwrap();
// Trying to lock should fail if the mutex is already held.
assert!(LOCK.try_lock().is_err());
// Dropping the guard should unlock the mutex correctly.
drop(guard);
// Trying to lock now should succeed.
assert!(LOCK.try_lock().is_ok());
// Spawn multiple threads interacting with the same mutex.
unsafe {
let ids = [
spawn_pthread_closure(|| {
for _ in 0..REPS {
*LOCK.lock().unwrap() += 2;
}
}),
spawn_pthread_closure(|| {
for _ in 0..REPS {
*LOCK.lock().unwrap() += 4;
}
}),
];
join_pthreads(ids);
}
// Due to the Mutex, all increments should be visible in every explored execution.
assert!(*LOCK.lock().unwrap() == REPS * 6);
drop(other_guard);
}