Skip to content

Commit 42ce39d

Browse files
Rollup merge of rust-lang#100579 - joboet:sync_mutex_everywhere, r=thomcc
std: use `sync::Mutex` for internal statics Since `sync::Mutex` is now `const`-constructible, it can be used for internal statics, removing the need for `sys_common::StaticMutex`. This adds some extra allocations on platforms which need to box their mutexes (currently SGX and some UNIX), but these will become unnecessary with the lock improvements tracked in rust-lang#93740. I changed the program argument implementation on Hermit, it does not need `Mutex` but can use atomics like some UNIX systems (ping `@mkroening` `@stlankes).`
2 parents 3271760 + 2d2c9e4 commit 42ce39d

File tree

7 files changed

+47
-123
lines changed

7 files changed

+47
-123
lines changed

library/std/src/backtrace.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -325,8 +325,7 @@ impl Backtrace {
325325
// Capture a backtrace which start just before the function addressed by
326326
// `ip`
327327
fn create(ip: usize) -> Backtrace {
328-
// SAFETY: We don't attempt to lock this reentrantly.
329-
let _lock = unsafe { lock() };
328+
let _lock = lock();
330329
let mut frames = Vec::new();
331330
let mut actual_start = None;
332331
unsafe {
@@ -469,8 +468,7 @@ impl Capture {
469468
// Use the global backtrace lock to synchronize this as it's a
470469
// requirement of the `backtrace` crate, and then actually resolve
471470
// everything.
472-
// SAFETY: We don't attempt to lock this reentrantly.
473-
let _lock = unsafe { lock() };
471+
let _lock = lock();
474472
for frame in self.frames.iter_mut() {
475473
let symbols = &mut frame.symbols;
476474
let frame = match &frame.frame {

library/std/src/sys/hermit/args.rs

+25-49
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,37 @@
1-
use crate::ffi::OsString;
1+
use crate::ffi::{c_char, CStr, OsString};
22
use crate::fmt;
3+
use crate::os::unix::ffi::OsStringExt;
4+
use crate::ptr;
5+
use crate::sync::atomic::{
6+
AtomicIsize, AtomicPtr,
7+
Ordering::{Acquire, Relaxed, Release},
8+
};
39
use crate::vec;
410

11+
static ARGC: AtomicIsize = AtomicIsize::new(0);
12+
static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut());
13+
514
/// One-time global initialization.
615
pub unsafe fn init(argc: isize, argv: *const *const u8) {
7-
imp::init(argc, argv)
8-
}
9-
10-
/// One-time global cleanup.
11-
pub unsafe fn cleanup() {
12-
imp::cleanup()
16+
ARGC.store(argc, Relaxed);
17+
// Use release ordering here to broadcast writes by the OS.
18+
ARGV.store(argv as *mut *const u8, Release);
1319
}
1420

1521
/// Returns the command line arguments
1622
pub fn args() -> Args {
17-
imp::args()
23+
// Synchronize with the store above.
24+
let argv = ARGV.load(Acquire);
25+
// If argv has not been initialized yet, do not return any arguments.
26+
let argc = if argv.is_null() { 0 } else { ARGC.load(Relaxed) };
27+
let args: Vec<OsString> = (0..argc)
28+
.map(|i| unsafe {
29+
let cstr = CStr::from_ptr(*argv.offset(i) as *const c_char);
30+
OsStringExt::from_vec(cstr.to_bytes().to_vec())
31+
})
32+
.collect();
33+
34+
Args { iter: args.into_iter() }
1835
}
1936

2037
pub struct Args {
@@ -51,44 +68,3 @@ impl DoubleEndedIterator for Args {
5168
self.iter.next_back()
5269
}
5370
}
54-
55-
mod imp {
56-
use super::Args;
57-
use crate::ffi::{CStr, OsString};
58-
use crate::os::unix::ffi::OsStringExt;
59-
use crate::ptr;
60-
61-
use crate::sys_common::mutex::StaticMutex;
62-
63-
static mut ARGC: isize = 0;
64-
static mut ARGV: *const *const u8 = ptr::null();
65-
static LOCK: StaticMutex = StaticMutex::new();
66-
67-
pub unsafe fn init(argc: isize, argv: *const *const u8) {
68-
let _guard = LOCK.lock();
69-
ARGC = argc;
70-
ARGV = argv;
71-
}
72-
73-
pub unsafe fn cleanup() {
74-
let _guard = LOCK.lock();
75-
ARGC = 0;
76-
ARGV = ptr::null();
77-
}
78-
79-
pub fn args() -> Args {
80-
Args { iter: clone().into_iter() }
81-
}
82-
83-
fn clone() -> Vec<OsString> {
84-
unsafe {
85-
let _guard = LOCK.lock();
86-
(0..ARGC)
87-
.map(|i| {
88-
let cstr = CStr::from_ptr(*ARGV.offset(i) as *const i8);
89-
OsStringExt::from_vec(cstr.to_bytes().to_vec())
90-
})
91-
.collect()
92-
}
93-
}
94-
}

library/std/src/sys/hermit/mod.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
106106

107107
// SAFETY: must be called only once during runtime cleanup.
108108
// NOTE: this is not guaranteed to run, for example when the program aborts.
109-
pub unsafe fn cleanup() {
110-
args::cleanup();
111-
}
109+
pub unsafe fn cleanup() {}
112110

113111
#[cfg(not(test))]
114112
#[no_mangle]

library/std/src/sys/windows/process.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use crate::os::windows::ffi::{OsStrExt, OsStringExt};
1616
use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle};
1717
use crate::path::{Path, PathBuf};
1818
use crate::ptr;
19+
use crate::sync::Mutex;
1920
use crate::sys::args::{self, Arg};
2021
use crate::sys::c;
2122
use crate::sys::c::NonZeroDWORD;
@@ -25,7 +26,6 @@ use crate::sys::handle::Handle;
2526
use crate::sys::path;
2627
use crate::sys::pipe::{self, AnonPipe};
2728
use crate::sys::stdio;
28-
use crate::sys_common::mutex::StaticMutex;
2929
use crate::sys_common::process::{CommandEnv, CommandEnvs};
3030
use crate::sys_common::IntoInner;
3131

@@ -301,9 +301,9 @@ impl Command {
301301
//
302302
// For more information, msdn also has an article about this race:
303303
// https://support.microsoft.com/kb/315939
304-
static CREATE_PROCESS_LOCK: StaticMutex = StaticMutex::new();
304+
static CREATE_PROCESS_LOCK: Mutex<()> = Mutex::new(());
305305

306-
let _guard = unsafe { CREATE_PROCESS_LOCK.lock() };
306+
let _guard = CREATE_PROCESS_LOCK.lock();
307307

308308
let mut pipes = StdioPipes { stdin: None, stdout: None, stderr: None };
309309
let null = Stdio::Null;

library/std/src/sys_common/backtrace.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,14 @@ use crate::fmt;
77
use crate::io;
88
use crate::io::prelude::*;
99
use crate::path::{self, Path, PathBuf};
10-
use crate::sys_common::mutex::StaticMutex;
10+
use crate::sync::{Mutex, PoisonError};
1111

1212
/// Max number of frames to print.
1313
const MAX_NB_FRAMES: usize = 100;
1414

15-
// SAFETY: Don't attempt to lock this reentrantly.
16-
pub unsafe fn lock() -> impl Drop {
17-
static LOCK: StaticMutex = StaticMutex::new();
18-
LOCK.lock()
15+
pub fn lock() -> impl Drop {
16+
static LOCK: Mutex<()> = Mutex::new(());
17+
LOCK.lock().unwrap_or_else(PoisonError::into_inner)
1918
}
2019

2120
/// Prints the current backtrace.

library/std/src/sys_common/mutex.rs

-44
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,5 @@
11
use crate::sys::locks as imp;
22

3-
/// An OS-based mutual exclusion lock, meant for use in static variables.
4-
///
5-
/// This mutex has a const constructor ([`StaticMutex::new`]), does not
6-
/// implement `Drop` to cleanup resources, and causes UB when used reentrantly.
7-
///
8-
/// This mutex does not implement poisoning.
9-
///
10-
/// This is a wrapper around `imp::Mutex` that does *not* call `init()` and
11-
/// `destroy()`.
12-
pub struct StaticMutex(imp::Mutex);
13-
14-
unsafe impl Sync for StaticMutex {}
15-
16-
impl StaticMutex {
17-
/// Creates a new mutex for use.
18-
#[inline]
19-
pub const fn new() -> Self {
20-
Self(imp::Mutex::new())
21-
}
22-
23-
/// Calls raw_lock() and then returns an RAII guard to guarantee the mutex
24-
/// will be unlocked.
25-
///
26-
/// It is undefined behaviour to call this function while locked by the
27-
/// same thread.
28-
#[inline]
29-
pub unsafe fn lock(&'static self) -> StaticMutexGuard {
30-
self.0.lock();
31-
StaticMutexGuard(&self.0)
32-
}
33-
}
34-
35-
#[must_use]
36-
pub struct StaticMutexGuard(&'static imp::Mutex);
37-
38-
impl Drop for StaticMutexGuard {
39-
#[inline]
40-
fn drop(&mut self) {
41-
unsafe {
42-
self.0.unlock();
43-
}
44-
}
45-
}
46-
473
/// An OS-based mutual exclusion lock.
484
///
495
/// This mutex cleans up its resources in its `Drop` implementation, may safely

library/std/src/thread/mod.rs

+12-15
Original file line numberDiff line numberDiff line change
@@ -1118,24 +1118,21 @@ impl ThreadId {
11181118
}
11191119
}
11201120
} else {
1121-
use crate::sys_common::mutex::StaticMutex;
1121+
use crate::sync::{Mutex, PoisonError};
11221122

1123-
// It is UB to attempt to acquire this mutex reentrantly!
1124-
static GUARD: StaticMutex = StaticMutex::new();
1125-
static mut COUNTER: u64 = 0;
1123+
static COUNTER: Mutex<u64> = Mutex::new(0);
11261124

1127-
unsafe {
1128-
let guard = GUARD.lock();
1125+
let mut counter = COUNTER.lock().unwrap_or_else(PoisonError::into_inner);
1126+
let Some(id) = counter.checked_add(1) else {
1127+
// in case the panic handler ends up calling `ThreadId::new()`,
1128+
// avoid reentrant lock acquire.
1129+
drop(counter);
1130+
exhausted();
1131+
};
11291132

1130-
let Some(id) = COUNTER.checked_add(1) else {
1131-
drop(guard); // in case the panic handler ends up calling `ThreadId::new()`, avoid reentrant lock acquire.
1132-
exhausted();
1133-
};
1134-
1135-
COUNTER = id;
1136-
drop(guard);
1137-
ThreadId(NonZeroU64::new(id).unwrap())
1138-
}
1133+
*counter = id;
1134+
drop(counter);
1135+
ThreadId(NonZeroU64::new(id).unwrap())
11391136
}
11401137
}
11411138
}

0 commit comments

Comments
 (0)