diff options
| author | Fenrir <[email protected]> | 2018-08-19 17:48:00 -0600 |
|---|---|---|
| committer | Fenrir <[email protected]> | 2018-08-19 17:56:18 -0600 |
| commit | 5d28bfcfd6086c3328837de9695099ea39048d0d (patch) | |
| tree | a514fde042ff2a504a03305bfe0894ff8cd8d47e /ctr-std/src/sys_common | |
| parent | Update for latest nightly 2018-06-09 (#70) (diff) | |
| download | ctru-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.rs | 36 | ||||
| -rw-r--r-- | ctr-std/src/sys_common/backtrace.rs | 21 | ||||
| -rw-r--r-- | ctr-std/src/sys_common/mutex.rs | 32 | ||||
| -rw-r--r-- | ctr-std/src/sys_common/poison.rs | 2 | ||||
| -rw-r--r-- | ctr-std/src/sys_common/remutex.rs | 4 | ||||
| -rw-r--r-- | ctr-std/src/sys_common/thread.rs | 2 | ||||
| -rw-r--r-- | ctr-std/src/sys_common/thread_local.rs | 5 | ||||
| -rw-r--r-- | ctr-std/src/sys_common/wtf8.rs | 14 |
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())); |