1
Fork 0

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 @@ impl Backtrace {
// Capture a backtrace which start just before the function addressed by // Capture a backtrace which start just before the function addressed by
// `ip` // `ip`
fn create(ip: usize) -> Backtrace { fn create(ip: usize) -> Backtrace {
// SAFETY: We don't attempt to lock this reentrantly. let _lock = lock();
let _lock = unsafe { lock() };
let mut frames = Vec::new(); let mut frames = Vec::new();
let mut actual_start = None; let mut actual_start = None;
unsafe { unsafe {
@ -469,8 +468,7 @@ impl Capture {
// Use the global backtrace lock to synchronize this as it's a // Use the global backtrace lock to synchronize this as it's a
// requirement of the `backtrace` crate, and then actually resolve // requirement of the `backtrace` crate, and then actually resolve
// everything. // everything.
// SAFETY: We don't attempt to lock this reentrantly. let _lock = lock();
let _lock = unsafe { lock() };
for frame in self.frames.iter_mut() { for frame in self.frames.iter_mut() {
let symbols = &mut frame.symbols; let symbols = &mut frame.symbols;
let frame = match &frame.frame { 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::fmt;
use crate::os::unix::ffi::OsStringExt;
use crate::ptr;
use crate::sync::atomic::{
AtomicIsize, AtomicPtr,
Ordering::{Acquire, Relaxed, Release},
};
use crate::vec; use crate::vec;
static ARGC: AtomicIsize = AtomicIsize::new(0);
static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut());
/// One-time global initialization. /// One-time global initialization.
pub unsafe fn init(argc: isize, argv: *const *const u8) { pub unsafe fn init(argc: isize, argv: *const *const u8) {
imp::init(argc, argv) ARGC.store(argc, Relaxed);
} // Use release ordering here to broadcast writes by the OS.
ARGV.store(argv as *mut *const u8, Release);
/// One-time global cleanup.
pub unsafe fn cleanup() {
imp::cleanup()
} }
/// Returns the command line arguments /// Returns the command line arguments
pub fn args() -> Args { 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 { pub struct Args {
@ -51,44 +68,3 @@ impl DoubleEndedIterator for Args {
self.iter.next_back() 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. // SAFETY: must be called only once during runtime cleanup.
// NOTE: this is not guaranteed to run, for example when the program aborts. // NOTE: this is not guaranteed to run, for example when the program aborts.
pub unsafe fn cleanup() { pub unsafe fn cleanup() {}
args::cleanup();
}
#[cfg(not(test))] #[cfg(not(test))]
#[no_mangle] #[no_mangle]

View file

@ -16,6 +16,7 @@ use crate::os::windows::ffi::{OsStrExt, OsStringExt};
use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle}; use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle};
use crate::path::{Path, PathBuf}; use crate::path::{Path, PathBuf};
use crate::ptr; use crate::ptr;
use crate::sync::Mutex;
use crate::sys::args::{self, Arg}; use crate::sys::args::{self, Arg};
use crate::sys::c; use crate::sys::c;
use crate::sys::c::NonZeroDWORD; use crate::sys::c::NonZeroDWORD;
@ -25,7 +26,6 @@ use crate::sys::handle::Handle;
use crate::sys::path; use crate::sys::path;
use crate::sys::pipe::{self, AnonPipe}; use crate::sys::pipe::{self, AnonPipe};
use crate::sys::stdio; use crate::sys::stdio;
use crate::sys_common::mutex::StaticMutex;
use crate::sys_common::process::{CommandEnv, CommandEnvs}; use crate::sys_common::process::{CommandEnv, CommandEnvs};
use crate::sys_common::IntoInner; use crate::sys_common::IntoInner;
@ -301,9 +301,9 @@ impl Command {
// //
// For more information, msdn also has an article about this race: // For more information, msdn also has an article about this race:
// https://support.microsoft.com/kb/315939 // 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 mut pipes = StdioPipes { stdin: None, stdout: None, stderr: None };
let null = Stdio::Null; let null = Stdio::Null;

View file

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

View file

@ -1,49 +1,5 @@
use crate::sys::locks as imp; 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. /// An OS-based mutual exclusion lock.
/// ///
/// This mutex cleans up its resources in its `Drop` implementation, may safely /// This mutex cleans up its resources in its `Drop` implementation, may safely

View file

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