std: use sync::Mutex for internal statics

This commit is contained in:
joboet 2022-09-03 14:21:38 +02:00
parent fa0ca783f8
commit 2d2c9e4493
No known key found for this signature in database
GPG Key ID: 704E0149B0194B3C
7 changed files with 47 additions and 123 deletions

View File

@ -325,8 +325,7 @@ pub const fn disabled() -> Backtrace {
// Capture a backtrace which start just before the function addressed by
// `ip`
fn create(ip: usize) -> Backtrace {
// SAFETY: We don't attempt to lock this reentrantly.
let _lock = unsafe { lock() };
let _lock = lock();
let mut frames = Vec::new();
let mut actual_start = None;
unsafe {
@ -469,8 +468,7 @@ fn resolve(&mut self) {
// Use the global backtrace lock to synchronize this as it's a
// requirement of the `backtrace` crate, and then actually resolve
// everything.
// SAFETY: We don't attempt to lock this reentrantly.
let _lock = unsafe { lock() };
let _lock = lock();
for frame in self.frames.iter_mut() {
let symbols = &mut frame.symbols;
let frame = match &frame.frame {

View File

@ -1,20 +1,37 @@
use crate::ffi::OsString;
use crate::ffi::{c_char, CStr, OsString};
use crate::fmt;
use crate::os::unix::ffi::OsStringExt;
use crate::ptr;
use crate::sync::atomic::{
AtomicIsize, AtomicPtr,
Ordering::{Acquire, Relaxed, Release},
};
use crate::vec;
static ARGC: AtomicIsize = AtomicIsize::new(0);
static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut());
/// One-time global initialization.
pub unsafe fn init(argc: isize, argv: *const *const u8) {
imp::init(argc, argv)
}
/// One-time global cleanup.
pub unsafe fn cleanup() {
imp::cleanup()
ARGC.store(argc, Relaxed);
// Use release ordering here to broadcast writes by the OS.
ARGV.store(argv as *mut *const u8, Release);
}
/// Returns the command line arguments
pub fn args() -> Args {
imp::args()
// Synchronize with the store above.
let argv = ARGV.load(Acquire);
// If argv has not been initialized yet, do not return any arguments.
let argc = if argv.is_null() { 0 } else { ARGC.load(Relaxed) };
let args: Vec<OsString> = (0..argc)
.map(|i| unsafe {
let cstr = CStr::from_ptr(*argv.offset(i) as *const c_char);
OsStringExt::from_vec(cstr.to_bytes().to_vec())
})
.collect();
Args { iter: args.into_iter() }
}
pub struct Args {
@ -51,44 +68,3 @@ fn next_back(&mut self) -> Option<OsString> {
self.iter.next_back()
}
}
mod imp {
use super::Args;
use crate::ffi::{CStr, OsString};
use crate::os::unix::ffi::OsStringExt;
use crate::ptr;
use crate::sys_common::mutex::StaticMutex;
static mut ARGC: isize = 0;
static mut ARGV: *const *const u8 = ptr::null();
static LOCK: StaticMutex = StaticMutex::new();
pub unsafe fn init(argc: isize, argv: *const *const u8) {
let _guard = LOCK.lock();
ARGC = argc;
ARGV = argv;
}
pub unsafe fn cleanup() {
let _guard = LOCK.lock();
ARGC = 0;
ARGV = ptr::null();
}
pub fn args() -> Args {
Args { iter: clone().into_iter() }
}
fn clone() -> Vec<OsString> {
unsafe {
let _guard = LOCK.lock();
(0..ARGC)
.map(|i| {
let cstr = CStr::from_ptr(*ARGV.offset(i) as *const i8);
OsStringExt::from_vec(cstr.to_bytes().to_vec())
})
.collect()
}
}
}

View File

@ -106,9 +106,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
// SAFETY: must be called only once during runtime cleanup.
// NOTE: this is not guaranteed to run, for example when the program aborts.
pub unsafe fn cleanup() {
args::cleanup();
}
pub unsafe fn cleanup() {}
#[cfg(not(test))]
#[no_mangle]

View File

@ -16,6 +16,7 @@
use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle};
use crate::path::{Path, PathBuf};
use crate::ptr;
use crate::sync::Mutex;
use crate::sys::args::{self, Arg};
use crate::sys::c;
use crate::sys::c::NonZeroDWORD;
@ -25,7 +26,6 @@
use crate::sys::path;
use crate::sys::pipe::{self, AnonPipe};
use crate::sys::stdio;
use crate::sys_common::mutex::StaticMutex;
use crate::sys_common::process::{CommandEnv, CommandEnvs};
use crate::sys_common::IntoInner;
@ -301,9 +301,9 @@ pub fn spawn(
//
// For more information, msdn also has an article about this race:
// https://support.microsoft.com/kb/315939
static CREATE_PROCESS_LOCK: StaticMutex = StaticMutex::new();
static CREATE_PROCESS_LOCK: Mutex<()> = Mutex::new(());
let _guard = unsafe { CREATE_PROCESS_LOCK.lock() };
let _guard = CREATE_PROCESS_LOCK.lock();
let mut pipes = StdioPipes { stdin: None, stdout: None, stderr: None };
let null = Stdio::Null;

View File

@ -7,15 +7,14 @@
use crate::io;
use crate::io::prelude::*;
use crate::path::{self, Path, PathBuf};
use crate::sys_common::mutex::StaticMutex;
use crate::sync::{Mutex, PoisonError};
/// Max number of frames to print.
const MAX_NB_FRAMES: usize = 100;
// SAFETY: Don't attempt to lock this reentrantly.
pub unsafe fn lock() -> impl Drop {
static LOCK: StaticMutex = StaticMutex::new();
LOCK.lock()
pub fn lock() -> impl Drop {
static LOCK: Mutex<()> = Mutex::new(());
LOCK.lock().unwrap_or_else(PoisonError::into_inner)
}
/// Prints the current backtrace.

View File

@ -1,49 +1,5 @@
use crate::sys::locks as imp;
/// An OS-based mutual exclusion lock, meant for use in static variables.
///
/// This mutex has a const constructor ([`StaticMutex::new`]), does not
/// implement `Drop` to cleanup resources, and causes UB when used reentrantly.
///
/// This mutex does not implement poisoning.
///
/// This is a wrapper around `imp::Mutex` that does *not* call `init()` and
/// `destroy()`.
pub struct StaticMutex(imp::Mutex);
unsafe impl Sync for StaticMutex {}
impl StaticMutex {
/// Creates a new mutex for use.
#[inline]
pub const fn new() -> Self {
Self(imp::Mutex::new())
}
/// Calls raw_lock() and then returns an RAII guard to guarantee the mutex
/// will be unlocked.
///
/// It is undefined behaviour to call this function while locked by the
/// same thread.
#[inline]
pub unsafe fn lock(&'static self) -> StaticMutexGuard {
self.0.lock();
StaticMutexGuard(&self.0)
}
}
#[must_use]
pub struct StaticMutexGuard(&'static imp::Mutex);
impl Drop for StaticMutexGuard {
#[inline]
fn drop(&mut self) {
unsafe {
self.0.unlock();
}
}
}
/// An OS-based mutual exclusion lock.
///
/// This mutex cleans up its resources in its `Drop` implementation, may safely

View File

@ -1118,24 +1118,21 @@ fn exhausted() -> ! {
}
}
} else {
use crate::sys_common::mutex::StaticMutex;
use crate::sync::{Mutex, PoisonError};
// It is UB to attempt to acquire this mutex reentrantly!
static GUARD: StaticMutex = StaticMutex::new();
static mut COUNTER: u64 = 0;
static COUNTER: Mutex<u64> = Mutex::new(0);
unsafe {
let guard = GUARD.lock();
let mut counter = COUNTER.lock().unwrap_or_else(PoisonError::into_inner);
let Some(id) = counter.checked_add(1) else {
// in case the panic handler ends up calling `ThreadId::new()`,
// avoid reentrant lock acquire.
drop(counter);
exhausted();
};
let Some(id) = COUNTER.checked_add(1) else {
drop(guard); // in case the panic handler ends up calling `ThreadId::new()`, avoid reentrant lock acquire.
exhausted();
};
COUNTER = id;
drop(guard);
ThreadId(NonZeroU64::new(id).unwrap())
}
*counter = id;
drop(counter);
ThreadId(NonZeroU64::new(id).unwrap())
}
}
}