Skip to content

Implement reentrant mutexes and make stdio use them #24029

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 8, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 25 additions & 17 deletions src/libstd/io/stdio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use io::lazy::Lazy;
use io::{self, BufReader, LineWriter};
use sync::{Arc, Mutex, MutexGuard};
use sys::stdio;
use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};

/// Stdout used by print! and println! macros
thread_local! {
Expand Down Expand Up @@ -210,7 +211,7 @@ pub struct Stdout {
// FIXME: this should be LineWriter or BufWriter depending on the state of
// stdout (tty or not). Note that if this is not line buffered it
// should also flush-on-panic or some form of flush-on-abort.
inner: Arc<Mutex<LineWriter<StdoutRaw>>>,
inner: Arc<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>>,
}

/// A locked reference to the a `Stdout` handle.
Expand All @@ -219,7 +220,7 @@ pub struct Stdout {
/// method on `Stdout`.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct StdoutLock<'a> {
inner: MutexGuard<'a, LineWriter<StdoutRaw>>,
inner: ReentrantMutexGuard<'a, RefCell<LineWriter<StdoutRaw>>>,
}

/// Constructs a new reference to the standard output of the current process.
Expand All @@ -231,13 +232,13 @@ pub struct StdoutLock<'a> {
/// The returned handle implements the `Write` trait.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stdout() -> Stdout {
static INSTANCE: Lazy<Mutex<LineWriter<StdoutRaw>>> = lazy_init!(stdout_init);
static INSTANCE: Lazy<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>> = lazy_init!(stdout_init);
return Stdout {
inner: INSTANCE.get().expect("cannot access stdout during shutdown"),
};

fn stdout_init() -> Arc<Mutex<LineWriter<StdoutRaw>>> {
Arc::new(Mutex::new(LineWriter::new(stdout_raw())))
fn stdout_init() -> Arc<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>> {
Arc::new(ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw()))))
}
}

Expand All @@ -264,23 +265,26 @@ impl Write for Stdout {
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
self.lock().write_all(buf)
}
// Don't override write_fmt as it's possible to run arbitrary code during a
// write_fmt, allowing the possibility of a recursive lock (aka deadlock)
fn write_fmt(&mut self, args: fmt::Arguments) -> io::Result<()> {
self.lock().write_fmt(args)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> Write for StdoutLock<'a> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.inner.write(&buf[..cmp::min(buf.len(), OUT_MAX)])
self.inner.borrow_mut().write(&buf[..cmp::min(buf.len(), OUT_MAX)])
}
fn flush(&mut self) -> io::Result<()> {
self.inner.borrow_mut().flush()
}
fn flush(&mut self) -> io::Result<()> { self.inner.flush() }
}

/// A handle to the standard error stream of a process.
///
/// For more information, see `stderr`
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Stderr {
inner: Arc<Mutex<StderrRaw>>,
inner: Arc<ReentrantMutex<RefCell<StderrRaw>>>,
}

/// A locked reference to the a `Stderr` handle.
Expand All @@ -289,7 +293,7 @@ pub struct Stderr {
/// method on `Stderr`.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct StderrLock<'a> {
inner: MutexGuard<'a, StderrRaw>,
inner: ReentrantMutexGuard<'a, RefCell<StderrRaw>>,
}

/// Constructs a new reference to the standard error stream of a process.
Expand All @@ -300,13 +304,13 @@ pub struct StderrLock<'a> {
/// The returned handle implements the `Write` trait.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stderr() -> Stderr {
static INSTANCE: Lazy<Mutex<StderrRaw>> = lazy_init!(stderr_init);
static INSTANCE: Lazy<ReentrantMutex<RefCell<StderrRaw>>> = lazy_init!(stderr_init);
return Stderr {
inner: INSTANCE.get().expect("cannot access stderr during shutdown"),
};

fn stderr_init() -> Arc<Mutex<StderrRaw>> {
Arc::new(Mutex::new(stderr_raw()))
fn stderr_init() -> Arc<ReentrantMutex<RefCell<StderrRaw>>> {
Arc::new(ReentrantMutex::new(RefCell::new(stderr_raw())))
}
}

Expand All @@ -333,14 +337,18 @@ impl Write for Stderr {
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
self.lock().write_all(buf)
}
// Don't override write_fmt for the same reasons as Stdout
fn write_fmt(&mut self, args: fmt::Arguments) -> io::Result<()> {
self.lock().write_fmt(args)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> Write for StderrLock<'a> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.inner.write(&buf[..cmp::min(buf.len(), OUT_MAX)])
self.inner.borrow_mut().write(&buf[..cmp::min(buf.len(), OUT_MAX)])
}
fn flush(&mut self) -> io::Result<()> {
self.inner.borrow_mut().flush()
}
fn flush(&mut self) -> io::Result<()> { self.inner.flush() }
}

/// Resets the task-local stderr handle to the specified writer
Expand Down
6 changes: 3 additions & 3 deletions src/libstd/sync/condvar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
use prelude::v1::*;

use sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
use sync::poison::{self, LockResult};
use sys::time::SteadyTime;
use sync::{mutex, MutexGuard, PoisonError};
use sys_common::condvar as sys;
use sys_common::mutex as sys_mutex;
use sys_common::poison::{self, LockResult};
use sys::time::SteadyTime;
use time::Duration;
use sync::{mutex, MutexGuard, PoisonError};

/// A Condition Variable
///
Expand Down
13 changes: 6 additions & 7 deletions src/libstd/sync/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@
pub use alloc::arc::{Arc, Weak};
pub use core::atomic;

pub use self::mutex::{Mutex, MutexGuard, StaticMutex};
pub use self::mutex::MUTEX_INIT;
pub use self::rwlock::{RwLock, StaticRwLock, RW_LOCK_INIT};
pub use self::rwlock::{RwLockReadGuard, RwLockWriteGuard};
pub use self::barrier::{Barrier, BarrierWaitResult};
pub use self::condvar::{Condvar, StaticCondvar, CONDVAR_INIT};
pub use self::mutex::MUTEX_INIT;
pub use self::mutex::{Mutex, MutexGuard, StaticMutex};
pub use self::once::{Once, ONCE_INIT};
pub use sys_common::poison::{PoisonError, TryLockError, TryLockResult, LockResult};
pub use self::rwlock::{RwLockReadGuard, RwLockWriteGuard};
pub use self::rwlock::{RwLock, StaticRwLock, RW_LOCK_INIT};
pub use self::semaphore::{Semaphore, SemaphoreGuard};
pub use self::barrier::{Barrier, BarrierWaitResult};
pub use self::poison::{PoisonError, TryLockError, TryLockResult, LockResult};

pub use self::future::Future;

Expand All @@ -39,6 +39,5 @@ mod condvar;
mod future;
mod mutex;
mod once;
mod poison;
mod rwlock;
mod semaphore;
6 changes: 3 additions & 3 deletions src/libstd/sync/mutex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
use prelude::v1::*;

use cell::UnsafeCell;
use fmt;
use marker;
use ops::{Deref, DerefMut};
use sync::poison::{self, TryLockError, TryLockResult, LockResult};
use sys_common::mutex as sys;
use fmt;
use sys_common::poison::{self, TryLockError, TryLockResult, LockResult};

/// A mutual exclusion primitive useful for protecting shared data
///
Expand Down Expand Up @@ -212,7 +212,7 @@ impl<T> Mutex<T> {

/// Attempts to acquire this lock.
///
/// If the lock could not be acquired at this time, then `None` is returned.
/// If the lock could not be acquired at this time, then `Err` is returned.
/// Otherwise, an RAII guard is returned. The lock will be unlocked when the
/// guard is dropped.
///
Expand Down
4 changes: 2 additions & 2 deletions src/libstd/sync/rwlock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
use prelude::v1::*;

use cell::UnsafeCell;
use fmt;
use marker;
use ops::{Deref, DerefMut};
use sync::poison::{self, LockResult, TryLockError, TryLockResult};
use sys_common::poison::{self, LockResult, TryLockError, TryLockResult};
use sys_common::rwlock as sys;
use fmt;

/// A reader-writer lock
///
Expand Down
2 changes: 2 additions & 0 deletions src/libstd/sys/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ pub mod condvar;
pub mod mutex;
pub mod net;
pub mod net2;
pub mod poison;
pub mod remutex;
pub mod rwlock;
pub mod stack;
pub mod thread;
Expand Down
File renamed without changes.
Loading