From b81da278623d9dcda1776008612bd42e1922e9c3 Mon Sep 17 00:00:00 2001 From: "NODA, Kai" Date: Sat, 9 Jun 2018 21:13:04 +0800 Subject: [PATCH] libstd: add an RAII utility for sys_common::mutex::Mutex Signed-off-by: NODA, Kai --- src/libstd/io/lazy.rs | 21 +++++++++++---------- src/libstd/sync/mutex.rs | 4 ++-- src/libstd/sys/redox/args.rs | 16 ++++++---------- src/libstd/sys/unix/args.rs | 14 +++++--------- src/libstd/sys/unix/os.rs | 26 +++++++++----------------- src/libstd/sys_common/at_exit_imp.rs | 27 ++++++++++++++------------- src/libstd/sys_common/mutex.rs | 26 ++++++++++++++++++++++++-- src/libstd/sys_common/thread_local.rs | 3 +-- src/libstd/thread/mod.rs | 5 +---- 9 files changed, 73 insertions(+), 69 deletions(-) diff --git a/src/libstd/io/lazy.rs b/src/libstd/io/lazy.rs index 9cef4e3cdf1..d357966be92 100644 --- a/src/libstd/io/lazy.rs +++ b/src/libstd/io/lazy.rs @@ -20,6 +20,9 @@ pub struct Lazy { init: fn() -> Arc, } +#[inline] +const fn done() -> *mut Arc { 1_usize as *mut _ } + unsafe impl Sync for Lazy {} impl Lazy { @@ -33,17 +36,15 @@ pub const fn new(init: fn() -> Arc) -> Lazy { pub fn get(&'static self) -> Option> { unsafe { - self.lock.lock(); + let _guard = self.lock.lock(); let ptr = self.ptr.get(); - let ret = if ptr.is_null() { + if ptr.is_null() { Some(self.init()) - } else if ptr as usize == 1 { + } else if ptr == done() { None } else { Some((*ptr).clone()) - }; - self.lock.unlock(); - return ret + } } } @@ -53,10 +54,10 @@ unsafe fn init(&'static self) -> Arc { // the at exit handler). Otherwise we just return the freshly allocated // `Arc`. let registered = sys_common::at_exit(move || { - self.lock.lock(); - let ptr = self.ptr.get(); - self.ptr.set(1 as *mut _); - self.lock.unlock(); + let ptr = { + let _guard = self.lock.lock(); + self.ptr.replace(done()) + }; drop(Box::from_raw(ptr)) }); let ret = (self.init)(); diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index f3503b0b3a6..e5a410644b9 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -227,7 +227,7 @@ impl Mutex { #[stable(feature = "rust1", since = "1.0.0")] pub fn lock(&self) -> LockResult> { unsafe { - self.inner.lock(); + self.inner.raw_lock(); MutexGuard::new(self) } } @@ -454,7 +454,7 @@ impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> { fn drop(&mut self) { unsafe { self.__lock.poison.done(&self.__poison); - self.__lock.inner.unlock(); + self.__lock.inner.raw_unlock(); } } } diff --git a/src/libstd/sys/redox/args.rs b/src/libstd/sys/redox/args.rs index 59ae2a74a6d..556ed77372e 100644 --- a/src/libstd/sys/redox/args.rs +++ b/src/libstd/sys/redox/args.rs @@ -73,17 +73,15 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) { CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec() }).collect(); - LOCK.lock(); + let _guard = LOCK.lock(); let ptr = get_global_ptr(); assert!((*ptr).is_none()); (*ptr) = Some(box args); - LOCK.unlock(); } pub unsafe fn cleanup() { - LOCK.lock(); + let _guard = LOCK.lock(); *get_global_ptr() = None; - LOCK.unlock(); } pub fn args() -> Args { @@ -96,16 +94,14 @@ pub fn args() -> Args { fn clone() -> Option>> { unsafe { - LOCK.lock(); + let _guard = LOCK.lock(); let ptr = get_global_ptr(); - let ret = (*ptr).as_ref().map(|s| (**s).clone()); - LOCK.unlock(); - return ret + (*ptr).as_ref().map(|s| (**s).clone()) } } - fn get_global_ptr() -> *mut Option>>> { - unsafe { mem::transmute(&GLOBAL_ARGS_PTR) } + unsafe fn get_global_ptr() -> *mut Option>>> { + mem::transmute(&GLOBAL_ARGS_PTR) } } diff --git a/src/libstd/sys/unix/args.rs b/src/libstd/sys/unix/args.rs index e1c7ffc19e5..dc1dba6f2f9 100644 --- a/src/libstd/sys/unix/args.rs +++ b/src/libstd/sys/unix/args.rs @@ -82,17 +82,15 @@ mod imp { static LOCK: Mutex = Mutex::new(); pub unsafe fn init(argc: isize, argv: *const *const u8) { - LOCK.lock(); + let _guard = LOCK.lock(); ARGC = argc; ARGV = argv; - LOCK.unlock(); } pub unsafe fn cleanup() { - LOCK.lock(); + let _guard = LOCK.lock(); ARGC = 0; ARGV = ptr::null(); - LOCK.unlock(); } pub fn args() -> Args { @@ -104,13 +102,11 @@ pub fn args() -> Args { fn clone() -> Vec { unsafe { - LOCK.lock(); - let ret = (0..ARGC).map(|i| { + let _guard = LOCK.lock(); + (0..ARGC).map(|i| { let cstr = CStr::from_ptr(*ARGV.offset(i) as *const libc::c_char); OsStringExt::from_vec(cstr.to_bytes().to_vec()) - }).collect(); - LOCK.unlock(); - return ret + }).collect() } } } diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 4c86fddee4b..82d05f78850 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -409,10 +409,9 @@ pub unsafe fn environ() -> *mut *const *const c_char { /// environment variables of the current process. pub fn env() -> Env { unsafe { - ENV_LOCK.lock(); + let _guard = ENV_LOCK.lock(); let mut environ = *environ(); if environ == ptr::null() { - ENV_LOCK.unlock(); panic!("os::env() failure getting env string from OS: {}", io::Error::last_os_error()); } @@ -423,12 +422,10 @@ pub fn env() -> Env { } environ = environ.offset(1); } - let ret = Env { + return Env { iter: result.into_iter(), _dont_send_or_sync_me: PhantomData, - }; - ENV_LOCK.unlock(); - return ret + } } fn parse(input: &[u8]) -> Option<(OsString, OsString)> { @@ -452,15 +449,14 @@ pub fn getenv(k: &OsStr) -> io::Result> { // always None as well let k = CString::new(k.as_bytes())?; unsafe { - ENV_LOCK.lock(); + let _guard = ENV_LOCK.lock(); let s = libc::getenv(k.as_ptr()) as *const libc::c_char; let ret = if s.is_null() { None } else { Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec())) }; - ENV_LOCK.unlock(); - return Ok(ret) + Ok(ret) } } @@ -469,10 +465,8 @@ pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { let v = CString::new(v.as_bytes())?; unsafe { - ENV_LOCK.lock(); - let ret = cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ()); - ENV_LOCK.unlock(); - return ret + let _guard = ENV_LOCK.lock(); + cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ()) } } @@ -480,10 +474,8 @@ pub fn unsetenv(n: &OsStr) -> io::Result<()> { let nbuf = CString::new(n.as_bytes())?; unsafe { - ENV_LOCK.lock(); - let ret = cvt(libc::unsetenv(nbuf.as_ptr())).map(|_| ()); - ENV_LOCK.unlock(); - return ret + let _guard = ENV_LOCK.lock(); + cvt(libc::unsetenv(nbuf.as_ptr())).map(|_| ()) } } diff --git a/src/libstd/sys_common/at_exit_imp.rs b/src/libstd/sys_common/at_exit_imp.rs index 26da51c9825..d268d9ad6f9 100644 --- a/src/libstd/sys_common/at_exit_imp.rs +++ b/src/libstd/sys_common/at_exit_imp.rs @@ -14,6 +14,7 @@ use boxed::FnBox; use ptr; +use mem; use sys_common::mutex::Mutex; type Queue = Vec>; @@ -25,6 +26,8 @@ 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 +38,7 @@ unsafe fn init() -> bool { if QUEUE.is_null() { let state: Box = 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,18 +47,18 @@ 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 = Box::from_raw(queue); for to_run in *queue { to_run(); @@ -66,15 +69,13 @@ pub fn cleanup() { } pub fn push(f: Box) -> bool { - let mut ret = true; unsafe { - LOCK.lock(); + let _guard = LOCK.lock(); if init() { (*QUEUE).push(f); + true } else { - ret = false; + false } - LOCK.unlock(); } - ret } diff --git a/src/libstd/sys_common/mutex.rs b/src/libstd/sys_common/mutex.rs index d1a738770d3..608355b7d70 100644 --- a/src/libstd/sys_common/mutex.rs +++ b/src/libstd/sys_common/mutex.rs @@ -37,7 +37,15 @@ pub unsafe fn init(&mut self) { self.0.init() } /// 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 +59,11 @@ pub unsafe fn try_lock(&self) -> bool { self.0.try_lock() } /// /// 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 +75,14 @@ pub unsafe fn destroy(&self) { self.0.destroy() } // 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/src/libstd/sys_common/thread_local.rs b/src/libstd/sys_common/thread_local.rs index d0d6224de0a..75f6b9ac7fd 100644 --- a/src/libstd/sys_common/thread_local.rs +++ b/src/libstd/sys_common/thread_local.rs @@ -162,13 +162,12 @@ unsafe fn lazy_init(&self) -> usize { // we just simplify the whole branch. if imp::requires_synchronized_create() { 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/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 1b976b79b4c..1dacf99b64b 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -935,20 +935,17 @@ fn new() -> ThreadId { static mut COUNTER: u64 = 0; unsafe { - GUARD.lock(); + let _guard = GUARD.lock(); // If we somehow use up all our bits, panic so that we're not // covering up subtle bugs of IDs being reused. if COUNTER == ::u64::MAX { - GUARD.unlock(); panic!("failed to generate unique thread ID: bitspace exhausted"); } let id = COUNTER; COUNTER += 1; - GUARD.unlock(); - ThreadId(id) } } -- GitLab