aboutsummaryrefslogtreecommitdiff
path: root/ctr-std/src/sys_common
diff options
context:
space:
mode:
authorFenrir <[email protected]>2018-08-19 17:48:00 -0600
committerFenrir <[email protected]>2018-08-19 17:56:18 -0600
commit5d28bfcfd6086c3328837de9695099ea39048d0d (patch)
treea514fde042ff2a504a03305bfe0894ff8cd8d47e /ctr-std/src/sys_common
parentUpdate for latest nightly 2018-06-09 (#70) (diff)
downloadctru-rs-5d28bfcfd6086c3328837de9695099ea39048d0d.tar.xz
ctru-rs-5d28bfcfd6086c3328837de9695099ea39048d0d.zip
Update for nightly-2018-08-18
Diffstat (limited to 'ctr-std/src/sys_common')
-rw-r--r--ctr-std/src/sys_common/at_exit_imp.rs36
-rw-r--r--ctr-std/src/sys_common/backtrace.rs21
-rw-r--r--ctr-std/src/sys_common/mutex.rs32
-rw-r--r--ctr-std/src/sys_common/poison.rs2
-rw-r--r--ctr-std/src/sys_common/remutex.rs4
-rw-r--r--ctr-std/src/sys_common/thread.rs2
-rw-r--r--ctr-std/src/sys_common/thread_local.rs5
-rw-r--r--ctr-std/src/sys_common/wtf8.rs14
8 files changed, 77 insertions, 39 deletions
diff --git a/ctr-std/src/sys_common/at_exit_imp.rs b/ctr-std/src/sys_common/at_exit_imp.rs
index 26da51c..76e5df2 100644
--- a/ctr-std/src/sys_common/at_exit_imp.rs
+++ b/ctr-std/src/sys_common/at_exit_imp.rs
@@ -14,17 +14,22 @@
use boxed::FnBox;
use ptr;
+use mem;
use sys_common::mutex::Mutex;
-type Queue = Vec<Box<FnBox()>>;
+type Queue = Vec<Box<dyn FnBox()>>;
// NB these are specifically not types from `std::sync` as they currently rely
// on poisoning and this module needs to operate at a lower level than requiring
// the thread infrastructure to be in place (useful on the borders of
// initialization/destruction).
+// We never call `LOCK.init()`, so it is UB to attempt to
+// acquire this mutex reentrantly!
static LOCK: Mutex = Mutex::new();
static mut QUEUE: *mut Queue = ptr::null_mut();
+const DONE: *mut Queue = 1_usize as *mut _;
+
// The maximum number of times the cleanup routines will be run. While running
// the at_exit closures new ones may be registered, and this count is the number
// of times the new closures will be allowed to register successfully. After
@@ -35,7 +40,7 @@ unsafe fn init() -> bool {
if QUEUE.is_null() {
let state: Box<Queue> = box Vec::new();
QUEUE = Box::into_raw(state);
- } else if QUEUE as usize == 1 {
+ } else if QUEUE == DONE {
// can't re-init after a cleanup
return false
}
@@ -44,20 +49,21 @@ unsafe fn init() -> bool {
}
pub fn cleanup() {
- for i in 0..ITERS {
+ for i in 1..=ITERS {
unsafe {
- LOCK.lock();
- let queue = QUEUE;
- QUEUE = if i == ITERS - 1 {1} else {0} as *mut _;
- LOCK.unlock();
+ let queue = {
+ let _guard = LOCK.lock();
+ mem::replace(&mut QUEUE, if i == ITERS { DONE } else { ptr::null_mut() })
+ };
// make sure we're not recursively cleaning up
- assert!(queue as usize != 1);
+ assert!(queue != DONE);
// If we never called init, not need to cleanup!
- if queue as usize != 0 {
+ if !queue.is_null() {
let queue: Box<Queue> = Box::from_raw(queue);
for to_run in *queue {
+ // We are not holding any lock, so reentrancy is fine.
to_run();
}
}
@@ -65,16 +71,16 @@ pub fn cleanup() {
}
}
-pub fn push(f: Box<FnBox()>) -> bool {
- let mut ret = true;
+pub fn push(f: Box<dyn FnBox()>) -> bool {
unsafe {
- LOCK.lock();
+ let _guard = LOCK.lock();
if init() {
+ // We are just moving `f` around, not calling it.
+ // There is no possibility of reentrancy here.
(*QUEUE).push(f);
+ true
} else {
- ret = false;
+ false
}
- LOCK.unlock();
}
- ret
}
diff --git a/ctr-std/src/sys_common/backtrace.rs b/ctr-std/src/sys_common/backtrace.rs
index 20109d2..7737178 100644
--- a/ctr-std/src/sys_common/backtrace.rs
+++ b/ctr-std/src/sys_common/backtrace.rs
@@ -49,7 +49,7 @@ pub struct Frame {
const MAX_NB_FRAMES: usize = 100;
/// Prints the current backtrace.
-pub fn print(w: &mut Write, format: PrintFormat) -> io::Result<()> {
+pub fn print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> {
static LOCK: Mutex = Mutex::new();
// Use a lock to prevent mixed output in multithreading context.
@@ -62,7 +62,7 @@ pub fn print(w: &mut Write, format: PrintFormat) -> io::Result<()> {
}
}
-fn _print(w: &mut Write, format: PrintFormat) -> io::Result<()> {
+fn _print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> {
let mut frames = [Frame {
exact_position: ptr::null(),
symbol_addr: ptr::null(),
@@ -156,16 +156,15 @@ pub fn log_enabled() -> Option<PrintFormat> {
_ => return Some(PrintFormat::Full),
}
- let val = match env::var_os("RUST_BACKTRACE") {
- Some(x) => if &x == "0" {
+ let val = env::var_os("RUST_BACKTRACE").and_then(|x|
+ if &x == "0" {
None
} else if &x == "full" {
Some(PrintFormat::Full)
} else {
Some(PrintFormat::Short)
- },
- None => None,
- };
+ }
+ );
ENABLED.store(match val {
Some(v) => v as isize,
None => 1,
@@ -177,7 +176,7 @@ pub fn log_enabled() -> Option<PrintFormat> {
///
/// These output functions should now be used everywhere to ensure consistency.
/// You may want to also use `output_fileline`.
-fn output(w: &mut Write, idx: usize, frame: Frame,
+fn output(w: &mut dyn Write, idx: usize, frame: Frame,
s: Option<&str>, format: PrintFormat) -> io::Result<()> {
// Remove the `17: 0x0 - <unknown>` line.
if format == PrintFormat::Short && frame.exact_position == ptr::null() {
@@ -202,7 +201,7 @@ fn output(w: &mut Write, idx: usize, frame: Frame,
///
/// See also `output`.
#[allow(dead_code)]
-fn output_fileline(w: &mut Write,
+fn output_fileline(w: &mut dyn Write,
file: &[u8],
line: u32,
format: PrintFormat) -> io::Result<()> {
@@ -254,7 +253,7 @@ fn output_fileline(w: &mut Write,
// Note that this demangler isn't quite as fancy as it could be. We have lots
// of other information in our symbols like hashes, version, type information,
// etc. Additionally, this doesn't handle glue symbols at all.
-pub fn demangle(writer: &mut Write, mut s: &str, format: PrintFormat) -> io::Result<()> {
+pub fn demangle(writer: &mut dyn Write, mut s: &str, format: PrintFormat) -> io::Result<()> {
// During ThinLTO LLVM may import and rename internal symbols, so strip out
// those endings first as they're one of the last manglings applied to
// symbol names.
@@ -263,7 +262,7 @@ pub fn demangle(writer: &mut Write, mut s: &str, format: PrintFormat) -> io::Res
let candidate = &s[i + llvm.len()..];
let all_hex = candidate.chars().all(|c| {
match c {
- 'A' ... 'F' | '0' ... '9' => true,
+ 'A' ..= 'F' | '0' ..= '9' => true,
_ => false,
}
});
diff --git a/ctr-std/src/sys_common/mutex.rs b/ctr-std/src/sys_common/mutex.rs
index d1a7387..c6d531c 100644
--- a/ctr-std/src/sys_common/mutex.rs
+++ b/ctr-std/src/sys_common/mutex.rs
@@ -24,11 +24,17 @@ impl Mutex {
///
/// Behavior is undefined if the mutex is moved after it is
/// first used with any of the functions below.
+ /// Also, until `init` is called, behavior is undefined if this
+ /// mutex is ever used reentrantly, i.e., `raw_lock` or `try_lock`
+ /// are called by the thread currently holding the lock.
pub const fn new() -> Mutex { Mutex(imp::Mutex::new()) }
/// Prepare the mutex for use.
///
/// This should be called once the mutex is at a stable memory address.
+ /// If called, this must be the very first thing that happens to the mutex.
+ /// Calling it in parallel with or after any operation (including another
+ /// `init()`) is undefined behavior.
#[inline]
pub unsafe fn init(&mut self) { self.0.init() }
@@ -37,7 +43,15 @@ impl Mutex {
/// Behavior is undefined if the mutex has been moved between this and any
/// previous function call.
#[inline]
- pub unsafe fn lock(&self) { self.0.lock() }
+ pub unsafe fn raw_lock(&self) { self.0.lock() }
+
+ /// Calls raw_lock() and then returns an RAII guard to guarantee the mutex
+ /// will be unlocked.
+ #[inline]
+ pub unsafe fn lock(&self) -> MutexGuard {
+ self.raw_lock();
+ MutexGuard(&self.0)
+ }
/// Attempts to lock the mutex without blocking, returning whether it was
/// successfully acquired or not.
@@ -51,8 +65,11 @@ impl Mutex {
///
/// Behavior is undefined if the current thread does not actually hold the
/// mutex.
+ ///
+ /// Consider switching from the pair of raw_lock() and raw_unlock() to
+ /// lock() whenever possible.
#[inline]
- pub unsafe fn unlock(&self) { self.0.unlock() }
+ pub unsafe fn raw_unlock(&self) { self.0.unlock() }
/// Deallocates all resources associated with this mutex.
///
@@ -64,3 +81,14 @@ impl Mutex {
// not meant to be exported to the outside world, just the containing module
pub fn raw(mutex: &Mutex) -> &imp::Mutex { &mutex.0 }
+
+#[must_use]
+/// A simple RAII utility for the above Mutex without the poisoning semantics.
+pub struct MutexGuard<'a>(&'a imp::Mutex);
+
+impl<'a> Drop for MutexGuard<'a> {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe { self.0.unlock(); }
+ }
+}
diff --git a/ctr-std/src/sys_common/poison.rs b/ctr-std/src/sys_common/poison.rs
index e74c40a..1625efe 100644
--- a/ctr-std/src/sys_common/poison.rs
+++ b/ctr-std/src/sys_common/poison.rs
@@ -251,7 +251,7 @@ impl<T> Error for TryLockError<T> {
}
}
- fn cause(&self) -> Option<&Error> {
+ fn cause(&self) -> Option<&dyn Error> {
match *self {
TryLockError::Poisoned(ref p) => Some(p),
_ => None
diff --git a/ctr-std/src/sys_common/remutex.rs b/ctr-std/src/sys_common/remutex.rs
index 022056f..071a3a2 100644
--- a/ctr-std/src/sys_common/remutex.rs
+++ b/ctr-std/src/sys_common/remutex.rs
@@ -13,6 +13,7 @@ use marker;
use ops::Deref;
use sys_common::poison::{self, TryLockError, TryLockResult, LockResult};
use sys::mutex as sys;
+use panic::{UnwindSafe, RefUnwindSafe};
/// A re-entrant mutual exclusion
///
@@ -28,6 +29,9 @@ pub struct ReentrantMutex<T> {
unsafe impl<T: Send> Send for ReentrantMutex<T> {}
unsafe impl<T: Send> Sync for ReentrantMutex<T> {}
+impl<T> UnwindSafe for ReentrantMutex<T> {}
+impl<T> RefUnwindSafe for ReentrantMutex<T> {}
+
/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
/// dropped (falls out of scope), the lock will be unlocked.
diff --git a/ctr-std/src/sys_common/thread.rs b/ctr-std/src/sys_common/thread.rs
index da6f58e..86a5e2b 100644
--- a/ctr-std/src/sys_common/thread.rs
+++ b/ctr-std/src/sys_common/thread.rs
@@ -21,7 +21,7 @@ pub unsafe fn start_thread(main: *mut u8) {
let _handler = stack_overflow::Handler::new();
// Finally, let's run some code.
- Box::from_raw(main as *mut Box<FnBox()>)()
+ Box::from_raw(main as *mut Box<dyn FnBox()>)()
}
pub fn min_stack() -> usize {
diff --git a/ctr-std/src/sys_common/thread_local.rs b/ctr-std/src/sys_common/thread_local.rs
index d0d6224..bb72cb0 100644
--- a/ctr-std/src/sys_common/thread_local.rs
+++ b/ctr-std/src/sys_common/thread_local.rs
@@ -161,14 +161,15 @@ impl StaticKey {
// Additionally a 0-index of a tls key hasn't been seen on windows, so
// we just simplify the whole branch.
if imp::requires_synchronized_create() {
+ // We never call `INIT_LOCK.init()`, so it is UB to attempt to
+ // acquire this mutex reentrantly!
static INIT_LOCK: Mutex = Mutex::new();
- INIT_LOCK.lock();
+ let _guard = INIT_LOCK.lock();
let mut key = self.key.load(Ordering::SeqCst);
if key == 0 {
key = imp::create(self.dtor) as usize;
self.key.store(key, Ordering::SeqCst);
}
- INIT_LOCK.unlock();
rtassert!(key != 0);
return key
}
diff --git a/ctr-std/src/sys_common/wtf8.rs b/ctr-std/src/sys_common/wtf8.rs
index 14a2555..45204b5 100644
--- a/ctr-std/src/sys_common/wtf8.rs
+++ b/ctr-std/src/sys_common/wtf8.rs
@@ -76,7 +76,7 @@ impl CodePoint {
#[inline]
pub fn from_u32(value: u32) -> Option<CodePoint> {
match value {
- 0 ... 0x10FFFF => Some(CodePoint { value: value }),
+ 0 ..= 0x10FFFF => Some(CodePoint { value: value }),
_ => None
}
}
@@ -101,7 +101,7 @@ impl CodePoint {
#[inline]
pub fn to_char(&self) -> Option<char> {
match self.value {
- 0xD800 ... 0xDFFF => None,
+ 0xD800 ..= 0xDFFF => None,
_ => Some(unsafe { char::from_u32_unchecked(self.value) })
}
}
@@ -305,7 +305,7 @@ impl Wtf8Buf {
/// like concatenating ill-formed UTF-16 strings effectively would.
#[inline]
pub fn push(&mut self, code_point: CodePoint) {
- if let trail @ 0xDC00...0xDFFF = code_point.to_u32() {
+ if let trail @ 0xDC00..=0xDFFF = code_point.to_u32() {
if let Some(lead) = (&*self).final_lead_surrogate() {
let len_without_lead_surrogate = self.len() - 3;
self.bytes.truncate(len_without_lead_surrogate);
@@ -525,7 +525,7 @@ impl Wtf8 {
#[inline]
pub fn ascii_byte_at(&self, position: usize) -> u8 {
match self.bytes[position] {
- ascii_byte @ 0x00 ... 0x7F => ascii_byte,
+ ascii_byte @ 0x00 ..= 0x7F => ascii_byte,
_ => 0xFF
}
}
@@ -630,7 +630,7 @@ impl Wtf8 {
return None
}
match &self.bytes[(len - 3)..] {
- &[0xED, b2 @ 0xA0...0xAF, b3] => Some(decode_surrogate(b2, b3)),
+ &[0xED, b2 @ 0xA0..=0xAF, b3] => Some(decode_surrogate(b2, b3)),
_ => None
}
}
@@ -642,7 +642,7 @@ impl Wtf8 {
return None
}
match &self.bytes[..3] {
- &[0xED, b2 @ 0xB0...0xBF, b3] => Some(decode_surrogate(b2, b3)),
+ &[0xED, b2 @ 0xB0..=0xBF, b3] => Some(decode_surrogate(b2, b3)),
_ => None
}
}
@@ -1245,7 +1245,7 @@ mod tests {
#[test]
fn wtf8_display() {
fn d(b: &[u8]) -> String {
- format!("{}", &unsafe { Wtf8::from_bytes_unchecked(b) })
+ (&unsafe { Wtf8::from_bytes_unchecked(b) }).to_string()
}
assert_eq!("", d("".as_bytes()));