Update comments, rearrange code

This commit is contained in:
David Cook 2020-04-05 12:09:31 -05:00
parent ac8c98da8e
commit 79f3307f30
6 changed files with 151 additions and 163 deletions

View file

@ -217,6 +217,8 @@ pub struct Evaluator<'tcx> {
pub(crate) time_anchor: Instant,
/// Cached `TyLayout`s for primitive data types that are commonly used inside Miri.
/// FIXME: Search through the rest of the codebase for more layout_of() calls that
/// could be cached here.
primitive_layouts: PrimitiveLayouts<'tcx>,
}

View file

@ -233,6 +233,64 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
this.write_null(dest)?;
}
// Synchronization primitives
"pthread_mutexattr_init" => {
let result = this.pthread_mutexattr_init(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_mutexattr_settype" => {
let result = this.pthread_mutexattr_settype(args[0], args[1])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_mutexattr_destroy" => {
let result = this.pthread_mutexattr_destroy(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_mutex_init" => {
let result = this.pthread_mutex_init(args[0], args[1])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_mutex_lock" => {
let result = this.pthread_mutex_lock(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_mutex_trylock" => {
let result = this.pthread_mutex_trylock(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_mutex_unlock" => {
let result = this.pthread_mutex_unlock(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_mutex_destroy" => {
let result = this.pthread_mutex_destroy(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_rwlock_rdlock" => {
let result = this.pthread_rwlock_rdlock(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_rwlock_tryrdlock" => {
let result = this.pthread_rwlock_tryrdlock(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_rwlock_wrlock" => {
let result = this.pthread_rwlock_wrlock(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_rwlock_trywrlock" => {
let result = this.pthread_rwlock_trywrlock(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_rwlock_unlock" => {
let result = this.pthread_rwlock_unlock(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_rwlock_destroy" => {
let result = this.pthread_rwlock_destroy(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
// Better error for attempts to create a thread
"pthread_create" => {
throw_unsup_format!("Miri does not support threading");
@ -270,76 +328,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
this.write_null(dest)?;
}
"pthread_mutexattr_init" => {
let result = this.pthread_mutexattr_init(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_mutexattr_settype" => {
let result = this.pthread_mutexattr_settype(args[0], args[1])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_mutexattr_destroy" => {
let result = this.pthread_mutexattr_destroy(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_mutex_init" => {
let result = this.pthread_mutex_init(args[0], args[1])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_mutex_lock" => {
let result = this.pthread_mutex_lock(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_mutex_trylock" => {
let result = this.pthread_mutex_trylock(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_mutex_unlock" => {
let result = this.pthread_mutex_unlock(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_mutex_destroy" => {
let result = this.pthread_mutex_destroy(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_rwlock_rdlock" => {
let result = this.pthread_rwlock_rdlock(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_rwlock_tryrdlock" => {
let result = this.pthread_rwlock_tryrdlock(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_rwlock_wrlock" => {
let result = this.pthread_rwlock_wrlock(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_rwlock_trywrlock" => {
let result = this.pthread_rwlock_trywrlock(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_rwlock_unlock" => {
let result = this.pthread_rwlock_unlock(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_rwlock_destroy" => {
let result = this.pthread_rwlock_destroy(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
| "signal"
| "sigaction"
| "sigaltstack"

View file

@ -20,8 +20,9 @@ fn assert_ptr_target_min_size<'mir, 'tcx: 'mir>(
// pthread_mutexattr_t is either 4 or 8 bytes, depending on the platform.
// Our chosen memory layout: store an i32 in the first four bytes equal to the
// corresponding libc mutex kind constant (i.e. PTHREAD_MUTEX_NORMAL)
// Our chosen memory layout for emulation (does not have to match the platform layout!):
// store an i32 in the first four bytes equal to the corresponding libc mutex kind constant
// (e.g. PTHREAD_MUTEX_NORMAL).
fn mutexattr_get_kind<'mir, 'tcx: 'mir>(
ecx: &MiriEvalContext<'mir, 'tcx>,
@ -48,7 +49,7 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>(
// pthread_mutex_t is between 24 and 48 bytes, depending on the platform.
// Our chosen memory layout:
// Our chosen memory layout for the emulated mutex (does not have to match the platform layout!):
// bytes 0-3: reserved for signature on macOS
// (need to avoid this because it is set by static initializer macros)
// bytes 4-7: count of how many times this mutex has been locked, as a u32
@ -117,7 +118,7 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>(
// pthread_rwlock_t is between 32 and 56 bytes, depending on the platform.
// Our chosen memory layout:
// Our chosen memory layout for the emulated rwlock (does not have to match the platform layout!):
// bytes 0-3: reserved for signature on macOS
// (need to avoid this because it is set by static initializer macros)
// bytes 4-7: reader count, as a u32

View file

@ -42,7 +42,92 @@ fn test_posix_fadvise() {
assert_eq!(result, 0);
}
fn test_mutex_libc_init_recursive() {
unsafe {
let mut attr: libc::pthread_mutexattr_t = std::mem::zeroed();
assert_eq!(libc::pthread_mutexattr_init(&mut attr as *mut _), 0);
assert_eq!(libc::pthread_mutexattr_settype(&mut attr as *mut _, libc::PTHREAD_MUTEX_RECURSIVE), 0);
let mut mutex: libc::pthread_mutex_t = std::mem::zeroed();
assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mut attr as *mut _), 0);
assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), libc::EPERM);
assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutexattr_destroy(&mut attr as *mut _), 0);
}
}
fn test_mutex_libc_init_normal() {
unsafe {
let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed();
assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), 0);
let mut mutex: libc::pthread_mutex_t = std::mem::zeroed();
assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0);
assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), libc::EBUSY);
assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0);
}
}
// Only linux provides PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
// libc for macOS just has the default PTHREAD_MUTEX_INITIALIZER.
#[cfg(target_os = "linux")]
fn test_mutex_libc_static_initializer_recursive() {
let mutex = std::cell::UnsafeCell::new(libc::PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP);
unsafe {
assert_eq!(libc::pthread_mutex_lock(mutex.get()), 0);
assert_eq!(libc::pthread_mutex_trylock(mutex.get()), 0);
assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0);
assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0);
assert_eq!(libc::pthread_mutex_trylock(mutex.get()), 0);
assert_eq!(libc::pthread_mutex_lock(mutex.get()), 0);
assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0);
assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0);
assert_eq!(libc::pthread_mutex_unlock(mutex.get()), libc::EPERM);
assert_eq!(libc::pthread_mutex_destroy(mutex.get()), 0);
}
}
// Testing the behavior of std::sync::RwLock does not fully exercise the pthread rwlock shims, we
// need to go a layer deeper and test the behavior of the libc functions, because
// std::sys::unix::rwlock::RWLock itself keeps track of write_locked and num_readers.
fn test_rwlock_libc_static_initializer() {
let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER);
unsafe {
assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0);
assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0);
assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0);
assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), 0);
assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0);
assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY);
assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0);
assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0);
assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), libc::EBUSY);
assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY);
assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0);
assert_eq!(libc::pthread_rwlock_destroy(rw.get()), 0);
}
}
fn main() {
#[cfg(not(target_os = "macos"))]
test_posix_fadvise();
test_mutex_libc_init_recursive();
test_mutex_libc_init_normal();
test_rwlock_libc_static_initializer();
#[cfg(target_os = "linux")]
test_mutex_libc_static_initializer_recursive();
}

View file

@ -1,7 +1,7 @@
use std::fmt::{Display, Error, Formatter};
// This test case exercises std::sys_common::remutex::ReentrantMutex
// by calling println!() from inside fmt
// by calling println!() from inside fmt.
struct InterruptingCow;

View file

@ -2,20 +2,11 @@
use std::sync::{Mutex, TryLockError};
extern crate libc;
fn main() {
test_mutex_stdlib();
#[cfg(not(target_os = "windows"))] // TODO: implement RwLock on Windows
{
test_mutex_libc_init_recursive();
test_mutex_libc_init_normal();
test_rwlock_stdlib();
test_rwlock_libc_static_initializer();
}
#[cfg(target_os = "linux")]
{
test_mutex_libc_static_initializer_recursive();
}
}
@ -29,61 +20,6 @@ fn test_mutex_stdlib() {
drop(m);
}
#[cfg(not(target_os = "windows"))]
fn test_mutex_libc_init_recursive() {
unsafe {
let mut attr: libc::pthread_mutexattr_t = std::mem::zeroed();
assert_eq!(libc::pthread_mutexattr_init(&mut attr as *mut _), 0);
assert_eq!(libc::pthread_mutexattr_settype(&mut attr as *mut _, libc::PTHREAD_MUTEX_RECURSIVE), 0);
let mut mutex: libc::pthread_mutex_t = std::mem::zeroed();
assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mut attr as *mut _), 0);
assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), libc::EPERM);
assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutexattr_destroy(&mut attr as *mut _), 0);
}
}
#[cfg(not(target_os = "windows"))]
fn test_mutex_libc_init_normal() {
unsafe {
let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed();
assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), 0);
let mut mutex: libc::pthread_mutex_t = std::mem::zeroed();
assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0);
assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), libc::EBUSY);
assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0);
}
}
#[cfg(target_os = "linux")]
fn test_mutex_libc_static_initializer_recursive() {
let mutex = std::cell::UnsafeCell::new(libc::PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP);
unsafe {
assert_eq!(libc::pthread_mutex_lock(mutex.get()), 0);
assert_eq!(libc::pthread_mutex_trylock(mutex.get()), 0);
assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0);
assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0);
assert_eq!(libc::pthread_mutex_trylock(mutex.get()), 0);
assert_eq!(libc::pthread_mutex_lock(mutex.get()), 0);
assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0);
assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0);
assert_eq!(libc::pthread_mutex_unlock(mutex.get()), libc::EPERM);
assert_eq!(libc::pthread_mutex_destroy(mutex.get()), 0);
}
}
#[cfg(not(target_os = "windows"))]
fn test_rwlock_stdlib() {
use std::sync::RwLock;
@ -102,30 +38,6 @@ fn test_rwlock_stdlib() {
}
}
// need to go a layer deeper and test the behavior of libc functions, because
// std::sys::unix::rwlock::RWLock keeps track of write_locked and num_readers
#[cfg(not(target_os = "windows"))]
fn test_rwlock_libc_static_initializer() {
let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER);
unsafe {
assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0);
assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0);
assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0);
assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), 0);
assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0);
assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY);
assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0);
assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0);
assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), libc::EBUSY);
assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY);
assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0);
assert_eq!(libc::pthread_rwlock_destroy(rw.get()), 0);
}
}
trait TryLockErrorExt<T> {
fn would_block(&self) -> bool;
}