Add more from the std

This commit is contained in:
2026-03-18 00:25:34 +01:00
parent fd0770f813
commit 9413fba265
51 changed files with 17246 additions and 26 deletions

View File

@@ -8,6 +8,8 @@ pub mod buffered;
pub mod copy;
pub mod cursor;
pub mod impls;
pub mod pipe;
// pub mod stdio;
pub mod prelude;
pub mod util;

View File

@@ -0,0 +1,147 @@
use crate::cmp::{max, min};
use alloc_crate::collections::VecDeque;
use crate::io;
use crate::io::*;
#[test]
fn copy_copies() {
let mut r = repeat(0).take(4);
let mut w = sink();
assert_eq!(copy(&mut r, &mut w).unwrap(), 4);
let mut r = repeat(0).take(1 << 17);
assert_eq!(copy(&mut r as &mut dyn Read, &mut w as &mut dyn Write).unwrap(), 1 << 17);
}
struct ShortReader {
cap: usize,
read_size: usize,
observed_buffer: usize,
}
impl Read for ShortReader {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
let bytes = min(self.cap, self.read_size).min(buf.len());
self.cap -= bytes;
self.observed_buffer = max(self.observed_buffer, buf.len());
Ok(bytes)
}
}
struct WriteObserver {
observed_buffer: usize,
}
impl Write for WriteObserver {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
self.observed_buffer = max(self.observed_buffer, buf.len());
Ok(buf.len())
}
fn flush(&mut self) -> Result<()> {
Ok(())
}
}
#[test]
fn copy_specializes_bufwriter() {
let cap = 117 * 1024;
let buf_sz = 16 * 1024;
let mut r = ShortReader { cap, observed_buffer: 0, read_size: 1337 };
let mut w = BufWriter::with_capacity(buf_sz, WriteObserver { observed_buffer: 0 });
assert_eq!(
copy(&mut r, &mut w).unwrap(),
cap as u64,
"expected the whole capacity to be copied"
);
assert_eq!(r.observed_buffer, buf_sz, "expected a large buffer to be provided to the reader");
assert!(w.get_mut().observed_buffer > DEFAULT_BUF_SIZE, "expected coalesced writes");
}
#[test]
fn copy_specializes_bufreader() {
let mut source = vec![0; 768 * 1024];
source[1] = 42;
let mut buffered = BufReader::with_capacity(256 * 1024, Cursor::new(&mut source));
let mut sink = Vec::new();
assert_eq!(crate::io::copy(&mut buffered, &mut sink).unwrap(), source.len() as u64);
assert_eq!(source.as_slice(), sink.as_slice());
let buf_sz = 71 * 1024;
assert!(buf_sz > DEFAULT_BUF_SIZE, "test precondition");
let mut buffered = BufReader::with_capacity(buf_sz, Cursor::new(&mut source));
let mut sink = WriteObserver { observed_buffer: 0 };
assert_eq!(crate::io::copy(&mut buffered, &mut sink).unwrap(), source.len() as u64);
assert_eq!(
sink.observed_buffer, buf_sz,
"expected a large buffer to be provided to the writer"
);
}
#[test]
fn copy_specializes_to_vec() {
let cap = DEFAULT_BUF_SIZE * 10;
let mut source = ShortReader { cap, observed_buffer: 0, read_size: DEFAULT_BUF_SIZE };
let mut sink = Vec::new();
let copied = io::copy(&mut source, &mut sink).unwrap();
assert_eq!(cap as u64, copied);
assert_eq!(sink.len() as u64, copied);
assert!(
source.observed_buffer > DEFAULT_BUF_SIZE,
"expected a large buffer to be provided to the reader, got {}",
source.observed_buffer
);
}
#[test]
fn copy_specializes_from_vecdeque() {
let mut source = VecDeque::with_capacity(100 * 1024);
for _ in 0..20 * 1024 {
source.push_front(0);
}
for _ in 0..20 * 1024 {
source.push_back(0);
}
let mut sink = WriteObserver { observed_buffer: 0 };
assert_eq!(40 * 1024u64, io::copy(&mut source, &mut sink).unwrap());
assert_eq!(20 * 1024, sink.observed_buffer);
}
#[test]
fn copy_specializes_from_slice() {
let mut source = [1; 60 * 1024].as_slice();
let mut sink = WriteObserver { observed_buffer: 0 };
assert_eq!(60 * 1024u64, io::copy(&mut source, &mut sink).unwrap());
assert_eq!(60 * 1024, sink.observed_buffer);
}
#[cfg(unix)]
mod io_benches {
use test::Bencher;
use crate::fs::{File, OpenOptions};
use crate::io::BufReader;
use crate::io::prelude::*;
#[bench]
#[cfg_attr(target_os = "emscripten", ignore)] // no /dev
fn bench_copy_buf_reader(b: &mut Bencher) {
let mut file_in = File::open("/dev/zero").expect("opening /dev/zero failed");
// use dyn to avoid specializations unrelated to readbuf
let dyn_in = &mut file_in as &mut dyn Read;
let mut reader = BufReader::with_capacity(256 * 1024, dyn_in.take(0));
let mut writer =
OpenOptions::new().write(true).open("/dev/null").expect("opening /dev/null failed");
const BYTES: u64 = 1024 * 1024;
b.bytes = BYTES;
b.iter(|| {
reader.get_mut().set_limit(BYTES);
crate::io::copy(&mut reader, &mut writer).unwrap()
});
}
}

View File

@@ -0,0 +1,50 @@
//! This is a fairly simple unpacked error representation that's used on
//! non-64bit targets, where the packed 64 bit representation wouldn't work, and
//! would have no benefit.
use super::{Custom, ErrorData, ErrorKind, RawOsError, SimpleMessage};
type Inner = ErrorData<Box<Custom>>;
pub(super) struct Repr(Inner);
impl Repr {
#[inline]
pub(super) fn new_custom(b: Box<Custom>) -> Self {
Self(Inner::Custom(b))
}
#[inline]
pub(super) fn new_os(code: RawOsError) -> Self {
Self(Inner::Os(code))
}
#[inline]
pub(super) fn new_simple(kind: ErrorKind) -> Self {
Self(Inner::Simple(kind))
}
#[inline]
pub(super) const fn new_simple_message(m: &'static SimpleMessage) -> Self {
Self(Inner::SimpleMessage(m))
}
#[inline]
pub(super) fn into_data(self) -> ErrorData<Box<Custom>> {
self.0
}
#[inline]
pub(super) fn data(&self) -> ErrorData<&Custom> {
match &self.0 {
Inner::Os(c) => ErrorData::Os(*c),
Inner::Simple(k) => ErrorData::Simple(*k),
Inner::SimpleMessage(m) => ErrorData::SimpleMessage(*m),
Inner::Custom(m) => ErrorData::Custom(&*m),
}
}
#[inline]
pub(super) fn data_mut(&mut self) -> ErrorData<&mut Custom> {
match &mut self.0 {
Inner::Os(c) => ErrorData::Os(*c),
Inner::Simple(k) => ErrorData::Simple(*k),
Inner::SimpleMessage(m) => ErrorData::SimpleMessage(*m),
Inner::Custom(m) => ErrorData::Custom(&mut *m),
}
}
}

View File

@@ -0,0 +1,191 @@
use super::{Custom, Error, ErrorData, ErrorKind, Repr, SimpleMessage, const_error};
use crate::sys::io::{decode_error_kind, error_string};
use crate::{assert_matches, error, fmt};
#[test]
fn test_size() {
assert!(size_of::<Error>() <= size_of::<[usize; 2]>());
}
#[test]
fn test_debug_error() {
let code = 6;
let msg = error_string(code);
let kind = decode_error_kind(code);
let err = Error {
repr: Repr::new_custom(Box::new(Custom {
kind: ErrorKind::InvalidInput,
error: Box::new(Error { repr: super::Repr::new_os(code) }),
})),
};
let expected = format!(
"Custom {{ \
kind: InvalidInput, \
error: Os {{ \
code: {:?}, \
kind: {:?}, \
message: {:?} \
}} \
}}",
code, kind, msg
);
assert_eq!(format!("{err:?}"), expected);
}
#[test]
fn test_downcasting() {
#[derive(Debug)]
struct TestError;
impl fmt::Display for TestError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("asdf")
}
}
impl error::Error for TestError {}
// we have to call all of these UFCS style right now since method
// resolution won't implicitly drop the Send+Sync bounds
let mut err = Error::new(ErrorKind::Other, TestError);
assert!(err.get_ref().unwrap().is::<TestError>());
assert_eq!("asdf", err.get_ref().unwrap().to_string());
assert!(err.get_mut().unwrap().is::<TestError>());
let extracted = err.into_inner().unwrap();
extracted.downcast::<TestError>().unwrap();
}
#[test]
fn test_const() {
const E: Error = const_error!(ErrorKind::NotFound, "hello");
assert_eq!(E.kind(), ErrorKind::NotFound);
assert_eq!(E.to_string(), "hello");
assert!(format!("{E:?}").contains("\"hello\""));
assert!(format!("{E:?}").contains("NotFound"));
}
#[test]
fn test_os_packing() {
for code in -20..20 {
let e = Error::from_raw_os_error(code);
assert_eq!(e.raw_os_error(), Some(code));
assert_matches!(
e.repr.data(),
ErrorData::Os(c) if c == code,
);
}
}
#[test]
fn test_errorkind_packing() {
assert_eq!(Error::from(ErrorKind::NotFound).kind(), ErrorKind::NotFound);
assert_eq!(Error::from(ErrorKind::PermissionDenied).kind(), ErrorKind::PermissionDenied);
assert_eq!(Error::from(ErrorKind::Uncategorized).kind(), ErrorKind::Uncategorized);
// Check that the innards look like what we want.
assert_matches!(
Error::from(ErrorKind::OutOfMemory).repr.data(),
ErrorData::Simple(ErrorKind::OutOfMemory),
);
}
#[test]
fn test_simple_message_packing() {
use super::ErrorKind::*;
use super::SimpleMessage;
macro_rules! check_simple_msg {
($err:expr, $kind:ident, $msg:literal) => {{
let e = &$err;
// Check that the public api is right.
assert_eq!(e.kind(), $kind);
assert!(format!("{e:?}").contains($msg));
// and we got what we expected
assert_matches!(
e.repr.data(),
ErrorData::SimpleMessage(SimpleMessage { kind: $kind, message: $msg })
);
}};
}
let not_static = const_error!(Uncategorized, "not a constant!");
check_simple_msg!(not_static, Uncategorized, "not a constant!");
const CONST: Error = const_error!(NotFound, "definitely a constant!");
check_simple_msg!(CONST, NotFound, "definitely a constant!");
static STATIC: Error = const_error!(BrokenPipe, "a constant, sort of!");
check_simple_msg!(STATIC, BrokenPipe, "a constant, sort of!");
}
#[derive(Debug, PartialEq)]
struct Bojji(bool);
impl error::Error for Bojji {}
impl fmt::Display for Bojji {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ah! {:?}", self)
}
}
#[test]
fn test_custom_error_packing() {
use super::Custom;
let test = Error::new(ErrorKind::Uncategorized, Bojji(true));
assert_matches!(
test.repr.data(),
ErrorData::Custom(Custom {
kind: ErrorKind::Uncategorized,
error,
}) if error.downcast_ref::<Bojji>().as_deref() == Some(&Bojji(true)),
);
}
#[derive(Debug)]
struct E;
impl fmt::Display for E {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
Ok(())
}
}
impl error::Error for E {}
#[test]
fn test_std_io_error_downcast() {
// Case 1: custom error, downcast succeeds
let io_error = Error::new(ErrorKind::Other, Bojji(true));
let e: Bojji = io_error.downcast().unwrap();
assert!(e.0);
// Case 2: custom error, downcast fails
let io_error = Error::new(ErrorKind::Other, Bojji(true));
let io_error = io_error.downcast::<E>().unwrap_err();
// ensures that the custom error is intact
assert_eq!(ErrorKind::Other, io_error.kind());
let e: Bojji = io_error.downcast().unwrap();
assert!(e.0);
// Case 3: os error
let errno = 20;
let io_error = Error::from_raw_os_error(errno);
let io_error = io_error.downcast::<E>().unwrap_err();
assert_eq!(errno, io_error.raw_os_error().unwrap());
// Case 4: simple
let kind = ErrorKind::OutOfMemory;
let io_error: Error = kind.into();
let io_error = io_error.downcast::<E>().unwrap_err();
assert_eq!(kind, io_error.kind());
// Case 5: simple message
const SIMPLE_MESSAGE: SimpleMessage =
SimpleMessage { kind: ErrorKind::Other, message: "simple message error test" };
let io_error = Error::from_static_message(&SIMPLE_MESSAGE);
let io_error = io_error.downcast::<E>().unwrap_err();
assert_eq!(SIMPLE_MESSAGE.kind, io_error.kind());
assert_eq!(SIMPLE_MESSAGE.message, format!("{io_error}"));
}

295
crates/std/src/io/pipe.rs Normal file
View File

@@ -0,0 +1,295 @@
use crate::io;
use crate::sys::{FromInner, IntoInner, pipe as imp};
/// Creates an anonymous pipe.
///
/// # Behavior
///
/// A pipe is a one-way data channel provided by the OS, which works across processes. A pipe is
/// typically used to communicate between two or more separate processes, as there are better,
/// faster ways to communicate within a single process.
///
/// In particular:
///
/// * A read on a [`PipeReader`] blocks until the pipe is non-empty.
/// * A write on a [`PipeWriter`] blocks when the pipe is full.
/// * When all copies of a [`PipeWriter`] are closed, a read on the corresponding [`PipeReader`]
/// returns EOF.
/// * [`PipeWriter`] can be shared, and multiple processes or threads can write to it at once, but
/// writes (above a target-specific threshold) may have their data interleaved.
/// * [`PipeReader`] can be shared, and multiple processes or threads can read it at once. Any
/// given byte will only get consumed by one reader. There are no guarantees about data
/// interleaving.
/// * Portable applications cannot assume any atomicity of messages larger than a single byte.
///
/// # Platform-specific behavior
///
/// This function currently corresponds to the `pipe` function on Unix and the
/// `CreatePipe` function on Windows.
///
/// Note that this [may change in the future][changes].
///
/// # Capacity
///
/// Pipe capacity is platform dependent. To quote the Linux [man page]:
///
/// > Different implementations have different limits for the pipe capacity. Applications should
/// > not rely on a particular capacity: an application should be designed so that a reading process
/// > consumes data as soon as it is available, so that a writing process does not remain blocked.
///
/// # Example
///
/// ```no_run
/// # #[cfg(miri)] fn main() {}
/// # #[cfg(not(miri))]
/// # fn main() -> std::io::Result<()> {
/// use std::io::{Read, Write, pipe};
/// use std::process::Command;
/// let (ping_reader, mut ping_writer) = pipe()?;
/// let (mut pong_reader, pong_writer) = pipe()?;
///
/// // Spawn a child process that echoes its input.
/// let mut echo_command = Command::new("cat");
/// echo_command.stdin(ping_reader);
/// echo_command.stdout(pong_writer);
/// let mut echo_child = echo_command.spawn()?;
///
/// // Send input to the child process. Note that because we're writing all the input before we
/// // read any output, this could deadlock if the child's input and output pipe buffers both
/// // filled up. Those buffers are usually at least a few KB, so "hello" is fine, but for longer
/// // inputs we'd need to read and write at the same time, e.g. using threads.
/// ping_writer.write_all(b"hello")?;
///
/// // `cat` exits when it reads EOF from stdin, but that can't happen while any ping writer
/// // remains open. We need to drop our ping writer, or read_to_string will deadlock below.
/// drop(ping_writer);
///
/// // The pong reader can't report EOF while any pong writer remains open. Our Command object is
/// // holding a pong writer, and again read_to_string will deadlock if we don't drop it.
/// drop(echo_command);
///
/// let mut buf = String::new();
/// // Block until `cat` closes its stdout (a pong writer).
/// pong_reader.read_to_string(&mut buf)?;
/// assert_eq!(&buf, "hello");
///
/// // At this point we know `cat` has exited, but we still need to wait to clean up the "zombie".
/// echo_child.wait()?;
/// # Ok(())
/// # }
/// ```
/// [changes]: io#platform-specific-behavior
/// [man page]: https://man7.org/linux/man-pages/man7/pipe.7.html
#[stable(feature = "anonymous_pipe", since = "1.87.0")]
#[inline]
pub fn pipe() -> io::Result<(PipeReader, PipeWriter)> {
imp::pipe().map(|(reader, writer)| (PipeReader(reader), PipeWriter(writer)))
}
/// Read end of an anonymous pipe.
#[stable(feature = "anonymous_pipe", since = "1.87.0")]
#[derive(Debug)]
pub struct PipeReader(pub(crate) imp::Pipe);
/// Write end of an anonymous pipe.
#[stable(feature = "anonymous_pipe", since = "1.87.0")]
#[derive(Debug)]
pub struct PipeWriter(pub(crate) imp::Pipe);
impl FromInner<imp::Pipe> for PipeReader {
fn from_inner(inner: imp::Pipe) -> Self {
Self(inner)
}
}
impl IntoInner<imp::Pipe> for PipeReader {
fn into_inner(self) -> imp::Pipe {
self.0
}
}
impl FromInner<imp::Pipe> for PipeWriter {
fn from_inner(inner: imp::Pipe) -> Self {
Self(inner)
}
}
impl IntoInner<imp::Pipe> for PipeWriter {
fn into_inner(self) -> imp::Pipe {
self.0
}
}
impl PipeReader {
/// Creates a new [`PipeReader`] instance that shares the same underlying file description.
///
/// # Examples
///
/// ```no_run
/// # #[cfg(miri)] fn main() {}
/// # #[cfg(not(miri))]
/// # fn main() -> std::io::Result<()> {
/// use std::fs;
/// use std::io::{pipe, Write};
/// use std::process::Command;
/// const NUM_SLOT: u8 = 2;
/// const NUM_PROC: u8 = 5;
/// const OUTPUT: &str = "work.txt";
///
/// let mut jobs = vec![];
/// let (reader, mut writer) = pipe()?;
///
/// // Write NUM_SLOT characters the pipe.
/// writer.write_all(&[b'|'; NUM_SLOT as usize])?;
///
/// // Spawn several processes that read a character from the pipe, do some work, then
/// // write back to the pipe. When the pipe is empty, the processes block, so only
/// // NUM_SLOT processes can be working at any given time.
/// for _ in 0..NUM_PROC {
/// jobs.push(
/// Command::new("bash")
/// .args(["-c",
/// &format!(
/// "read -n 1\n\
/// echo -n 'x' >> '{OUTPUT}'\n\
/// echo -n '|'",
/// ),
/// ])
/// .stdin(reader.try_clone()?)
/// .stdout(writer.try_clone()?)
/// .spawn()?,
/// );
/// }
///
/// // Wait for all jobs to finish.
/// for mut job in jobs {
/// job.wait()?;
/// }
///
/// // Check our work and clean up.
/// let xs = fs::read_to_string(OUTPUT)?;
/// fs::remove_file(OUTPUT)?;
/// assert_eq!(xs, "x".repeat(NUM_PROC.into()));
/// # Ok(())
/// # }
/// ```
#[stable(feature = "anonymous_pipe", since = "1.87.0")]
pub fn try_clone(&self) -> io::Result<Self> {
self.0.try_clone().map(Self)
}
}
impl PipeWriter {
/// Creates a new [`PipeWriter`] instance that shares the same underlying file description.
///
/// # Examples
///
/// ```no_run
/// # #[cfg(miri)] fn main() {}
/// # #[cfg(not(miri))]
/// # fn main() -> std::io::Result<()> {
/// use std::process::Command;
/// use std::io::{pipe, Read};
/// let (mut reader, writer) = pipe()?;
///
/// // Spawn a process that writes to stdout and stderr.
/// let mut peer = Command::new("bash")
/// .args([
/// "-c",
/// "echo -n foo\n\
/// echo -n bar >&2"
/// ])
/// .stdout(writer.try_clone()?)
/// .stderr(writer)
/// .spawn()?;
///
/// // Read and check the result.
/// let mut msg = String::new();
/// reader.read_to_string(&mut msg)?;
/// assert_eq!(&msg, "foobar");
///
/// peer.wait()?;
/// # Ok(())
/// # }
/// ```
#[stable(feature = "anonymous_pipe", since = "1.87.0")]
pub fn try_clone(&self) -> io::Result<Self> {
self.0.try_clone().map(Self)
}
}
#[stable(feature = "anonymous_pipe", since = "1.87.0")]
impl io::Read for &PipeReader {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.0.read_vectored(bufs)
}
#[inline]
fn is_read_vectored(&self) -> bool {
self.0.is_read_vectored()
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.0.read_to_end(buf)
}
fn read_buf(&mut self, buf: io::BorrowedCursor<'_>) -> io::Result<()> {
self.0.read_buf(buf)
}
}
#[stable(feature = "anonymous_pipe", since = "1.87.0")]
impl io::Read for PipeReader {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.0.read_vectored(bufs)
}
#[inline]
fn is_read_vectored(&self) -> bool {
self.0.is_read_vectored()
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.0.read_to_end(buf)
}
fn read_buf(&mut self, buf: io::BorrowedCursor<'_>) -> io::Result<()> {
self.0.read_buf(buf)
}
}
#[stable(feature = "anonymous_pipe", since = "1.87.0")]
impl io::Write for &PipeWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.0.write_vectored(bufs)
}
#[inline]
fn is_write_vectored(&self) -> bool {
self.0.is_write_vectored()
}
}
#[stable(feature = "anonymous_pipe", since = "1.87.0")]
impl io::Write for PipeWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.0.write_vectored(bufs)
}
#[inline]
fn is_write_vectored(&self) -> bool {
self.0.is_write_vectored()
}
}

View File

@@ -0,0 +1,18 @@
use crate::io::{Read, Write, pipe};
#[test]
#[cfg(all(any(unix, windows), not(miri)))]
fn pipe_creation_clone_and_rw() {
let (rx, tx) = pipe().unwrap();
tx.try_clone().unwrap().write_all(b"12345").unwrap();
drop(tx);
let mut rx2 = rx.try_clone().unwrap();
drop(rx);
let mut s = String::new();
rx2.read_to_string(&mut s).unwrap();
drop(rx2);
assert_eq!(s, "12345");
}

1290
crates/std/src/io/stdio.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,185 @@
use crate::fmt;
use crate::io::prelude::*;
use crate::io::{
BorrowedBuf, Empty, ErrorKind, IoSlice, IoSliceMut, Repeat, SeekFrom, Sink, empty, repeat, sink,
};
use crate::mem::MaybeUninit;
struct ErrorDisplay;
impl fmt::Display for ErrorDisplay {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
Err(fmt::Error)
}
}
struct PanicDisplay;
impl fmt::Display for PanicDisplay {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
panic!()
}
}
#[track_caller]
fn test_sinking<W: Write>(mut w: W) {
assert_eq!(w.write(&[]).unwrap(), 0);
assert_eq!(w.write(&[0]).unwrap(), 1);
assert_eq!(w.write(&[0; 1024]).unwrap(), 1024);
w.write_all(&[]).unwrap();
w.write_all(&[0]).unwrap();
w.write_all(&[0; 1024]).unwrap();
let mut bufs =
[IoSlice::new(&[]), IoSlice::new(&[0]), IoSlice::new(&[0; 1024]), IoSlice::new(&[])];
assert!(w.is_write_vectored());
assert_eq!(w.write_vectored(&[]).unwrap(), 0);
assert_eq!(w.write_vectored(&bufs).unwrap(), 1025);
w.write_all_vectored(&mut []).unwrap();
w.write_all_vectored(&mut bufs).unwrap();
assert!(w.flush().is_ok());
assert_eq!(w.by_ref().write(&[0; 1024]).unwrap(), 1024);
// Ignores fmt arguments
w.write_fmt(format_args!("{}", ErrorDisplay)).unwrap();
w.write_fmt(format_args!("{}", PanicDisplay)).unwrap();
}
#[test]
fn sink_sinks() {
test_sinking(sink());
}
#[test]
fn empty_reads() {
let mut e = empty();
assert_eq!(e.read(&mut []).unwrap(), 0);
assert_eq!(e.read(&mut [0]).unwrap(), 0);
assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0);
assert_eq!(Read::by_ref(&mut e).read(&mut [0; 1024]).unwrap(), 0);
e.read_exact(&mut []).unwrap();
assert_eq!(e.read_exact(&mut [0]).unwrap_err().kind(), ErrorKind::UnexpectedEof);
assert_eq!(e.read_exact(&mut [0; 1024]).unwrap_err().kind(), ErrorKind::UnexpectedEof);
assert!(!e.is_read_vectored());
assert_eq!(e.read_vectored(&mut []).unwrap(), 0);
let (mut buf1, mut buf1024) = ([0], [0; 1024]);
let bufs = &mut [
IoSliceMut::new(&mut []),
IoSliceMut::new(&mut buf1),
IoSliceMut::new(&mut buf1024),
IoSliceMut::new(&mut []),
];
assert_eq!(e.read_vectored(bufs).unwrap(), 0);
let buf: &mut [MaybeUninit<_>] = &mut [];
let mut buf: BorrowedBuf<'_> = buf.into();
e.read_buf(buf.unfilled()).unwrap();
assert_eq!(buf.len(), 0);
assert_eq!(buf.init_len(), 0);
let buf: &mut [_] = &mut [MaybeUninit::uninit()];
let mut buf: BorrowedBuf<'_> = buf.into();
e.read_buf(buf.unfilled()).unwrap();
assert_eq!(buf.len(), 0);
assert_eq!(buf.init_len(), 0);
let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024];
let mut buf: BorrowedBuf<'_> = buf.into();
e.read_buf(buf.unfilled()).unwrap();
assert_eq!(buf.len(), 0);
assert_eq!(buf.init_len(), 0);
let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024];
let mut buf: BorrowedBuf<'_> = buf.into();
Read::by_ref(&mut e).read_buf(buf.unfilled()).unwrap();
assert_eq!(buf.len(), 0);
assert_eq!(buf.init_len(), 0);
let buf: &mut [MaybeUninit<_>] = &mut [];
let mut buf: BorrowedBuf<'_> = buf.into();
e.read_buf_exact(buf.unfilled()).unwrap();
assert_eq!(buf.len(), 0);
assert_eq!(buf.init_len(), 0);
let buf: &mut [_] = &mut [MaybeUninit::uninit()];
let mut buf: BorrowedBuf<'_> = buf.into();
assert_eq!(e.read_buf_exact(buf.unfilled()).unwrap_err().kind(), ErrorKind::UnexpectedEof);
assert_eq!(buf.len(), 0);
assert_eq!(buf.init_len(), 0);
let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024];
let mut buf: BorrowedBuf<'_> = buf.into();
assert_eq!(e.read_buf_exact(buf.unfilled()).unwrap_err().kind(), ErrorKind::UnexpectedEof);
assert_eq!(buf.len(), 0);
assert_eq!(buf.init_len(), 0);
let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024];
let mut buf: BorrowedBuf<'_> = buf.into();
assert_eq!(
Read::by_ref(&mut e).read_buf_exact(buf.unfilled()).unwrap_err().kind(),
ErrorKind::UnexpectedEof,
);
assert_eq!(buf.len(), 0);
assert_eq!(buf.init_len(), 0);
let mut buf = Vec::new();
assert_eq!(e.read_to_end(&mut buf).unwrap(), 0);
assert_eq!(buf, vec![]);
let mut buf = vec![1, 2, 3];
assert_eq!(e.read_to_end(&mut buf).unwrap(), 0);
assert_eq!(buf, vec![1, 2, 3]);
let mut buf = String::new();
assert_eq!(e.read_to_string(&mut buf).unwrap(), 0);
assert_eq!(buf, "");
let mut buf = "hello".to_owned();
assert_eq!(e.read_to_string(&mut buf).unwrap(), 0);
assert_eq!(buf, "hello");
}
#[test]
fn empty_seeks() {
let mut e = empty();
assert!(matches!(e.seek(SeekFrom::Start(0)), Ok(0)));
assert!(matches!(e.seek(SeekFrom::Start(1)), Ok(0)));
assert!(matches!(e.seek(SeekFrom::Start(u64::MAX)), Ok(0)));
assert!(matches!(e.seek(SeekFrom::End(i64::MIN)), Ok(0)));
assert!(matches!(e.seek(SeekFrom::End(-1)), Ok(0)));
assert!(matches!(e.seek(SeekFrom::End(0)), Ok(0)));
assert!(matches!(e.seek(SeekFrom::End(1)), Ok(0)));
assert!(matches!(e.seek(SeekFrom::End(i64::MAX)), Ok(0)));
assert!(matches!(e.seek(SeekFrom::Current(i64::MIN)), Ok(0)));
assert!(matches!(e.seek(SeekFrom::Current(-1)), Ok(0)));
assert!(matches!(e.seek(SeekFrom::Current(0)), Ok(0)));
assert!(matches!(e.seek(SeekFrom::Current(1)), Ok(0)));
assert!(matches!(e.seek(SeekFrom::Current(i64::MAX)), Ok(0)));
}
#[test]
fn empty_sinks() {
test_sinking(empty());
}
#[test]
fn repeat_repeats() {
let mut r = repeat(4);
let mut b = [0; 1024];
assert_eq!(r.read(&mut b).unwrap(), 1024);
assert!(b.iter().all(|b| *b == 4));
}
#[test]
fn take_some_bytes() {
assert_eq!(repeat(4).take(100).bytes().count(), 100);
assert_eq!(repeat(4).take(100).bytes().next().unwrap().unwrap(), 4);
assert_eq!(repeat(1).take(10).chain(repeat(2).take(10)).bytes().count(), 20);
}
#[allow(dead_code)]
fn const_utils() {
const _: Empty = empty();
const _: Repeat = repeat(b'c');
const _: Sink = sink();
}

View File

@@ -1,14 +1,25 @@
pub mod once {
use crate::sys::sync as sys;
pub struct OnceState {
pub(crate) inner: sys::OnceState,
}
/// Used for the internal implementation of `sys::sync::once` on different platforms and the
/// [`LazyLock`](crate::sync::LazyLock) implementation.
pub(crate) enum OnceExclusiveState {
Incomplete,
Poisoned,
Complete,
}
}
pub mod barrier;
pub mod lazy_lock;
pub mod mpmc;
pub mod mpsc;
pub mod nonpoison;
pub mod once;
pub mod once_lock;
pub mod poison;
pub mod reentrant_lock;
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::sync::atomic;
pub use once::Once;
pub use once::OnceState;
pub use poison::LockResult;
pub use poison::Mutex;
pub use poison::PoisonError;
pub use poison::TryLockError;
pub use poison::TryLockResult;
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[stable(feature = "wait_timeout", since = "1.5.0")]
pub struct WaitTimeoutResult(bool);

View File

@@ -0,0 +1,167 @@
use crate::fmt;
use core::panic::RefUnwindSafe;
use crate::sync::nonpoison::{Condvar, Mutex};
/// A barrier enables multiple threads to synchronize the beginning
/// of some computation.
///
/// # Examples
///
/// ```
/// use std::sync::Barrier;
/// use std::thread;
///
/// let n = 10;
/// let barrier = Barrier::new(n);
/// thread::scope(|s| {
/// for _ in 0..n {
/// // The same messages will be printed together.
/// // You will NOT see any interleaving.
/// s.spawn(|| {
/// println!("before wait");
/// barrier.wait();
/// println!("after wait");
/// });
/// }
/// });
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Barrier {
lock: Mutex<BarrierState>,
cvar: Condvar,
num_threads: usize,
}
#[stable(feature = "unwind_safe_lock_refs", since = "1.12.0")]
impl RefUnwindSafe for Barrier {}
// The inner state of a double barrier
struct BarrierState {
count: usize,
generation_id: usize,
}
/// A `BarrierWaitResult` is returned by [`Barrier::wait()`] when all threads
/// in the [`Barrier`] have rendezvoused.
///
/// # Examples
///
/// ```
/// use std::sync::Barrier;
///
/// let barrier = Barrier::new(1);
/// let barrier_wait_result = barrier.wait();
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct BarrierWaitResult(bool);
#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Barrier {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Barrier").finish_non_exhaustive()
}
}
impl Barrier {
/// Creates a new barrier that can block a given number of threads.
///
/// A barrier will block all threads which call [`wait()`] until the `n`th thread calls [`wait()`],
/// and then wake up all threads at once.
///
/// [`wait()`]: Barrier::wait
///
/// # Examples
///
/// ```
/// use std::sync::Barrier;
///
/// let barrier = Barrier::new(10);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_barrier", since = "1.78.0")]
#[must_use]
#[inline]
pub const fn new(n: usize) -> Barrier {
Barrier {
lock: Mutex::new(BarrierState { count: 0, generation_id: 0 }),
cvar: Condvar::new(),
num_threads: n,
}
}
/// Blocks the current thread until all threads have rendezvoused here.
///
/// Barriers are re-usable after all threads have rendezvoused once, and can
/// be used continuously.
///
/// A single (arbitrary) thread will receive a [`BarrierWaitResult`] that
/// returns `true` from [`BarrierWaitResult::is_leader()`] when returning
/// from this function, and all other threads will receive a result that
/// will return `false` from [`BarrierWaitResult::is_leader()`].
///
/// # Examples
///
/// ```
/// use std::sync::Barrier;
/// use std::thread;
///
/// let n = 10;
/// let barrier = Barrier::new(n);
/// thread::scope(|s| {
/// for _ in 0..n {
/// // The same messages will be printed together.
/// // You will NOT see any interleaving.
/// s.spawn(|| {
/// println!("before wait");
/// barrier.wait();
/// println!("after wait");
/// });
/// }
/// });
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn wait(&self) -> BarrierWaitResult {
let mut lock = self.lock.lock();
let local_gen = lock.generation_id;
lock.count += 1;
if lock.count < self.num_threads {
self.cvar.wait_while(&mut lock, |state| local_gen == state.generation_id);
BarrierWaitResult(false)
} else {
lock.count = 0;
lock.generation_id = lock.generation_id.wrapping_add(1);
self.cvar.notify_all();
BarrierWaitResult(true)
}
}
}
#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for BarrierWaitResult {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BarrierWaitResult").field("is_leader", &self.is_leader()).finish()
}
}
impl BarrierWaitResult {
/// Returns `true` if this thread is the "leader thread" for the call to
/// [`Barrier::wait()`].
///
/// Only one thread will have `true` returned from their result, all other
/// threads will have `false` returned.
///
/// # Examples
///
/// ```
/// use std::sync::Barrier;
///
/// let barrier = Barrier::new(1);
/// let barrier_wait_result = barrier.wait();
/// println!("{:?}", barrier_wait_result.is_leader());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[must_use]
pub fn is_leader(&self) -> bool {
self.0
}
}

View File

@@ -0,0 +1,422 @@
use super::once::OnceExclusiveState;
use crate::cell::UnsafeCell;
use crate::mem::ManuallyDrop;
use crate::ops::{Deref, DerefMut};
use core::panic::{RefUnwindSafe, UnwindSafe};
use crate::sync::Once;
use crate::{fmt, ptr};
// We use the state of a Once as discriminant value. Upon creation, the state is
// "incomplete" and `f` contains the initialization closure. In the first call to
// `call_once`, `f` is taken and run. If it succeeds, `value` is set and the state
// is changed to "complete". If it panics, the Once is poisoned, so none of the
// two fields is initialized.
union Data<T, F> {
value: ManuallyDrop<T>,
f: ManuallyDrop<F>,
}
/// A value which is initialized on the first access.
///
/// This type is a thread-safe [`LazyCell`], and can be used in statics.
/// Since initialization may be called from multiple threads, any
/// dereferencing call will block the calling thread if another
/// initialization routine is currently running.
///
/// [`LazyCell`]: crate::cell::LazyCell
///
/// # Poisoning
///
/// If the initialization closure passed to [`LazyLock::new`] panics, the lock will be poisoned.
/// Once the lock is poisoned, any threads that attempt to access this lock (via a dereference
/// or via an explicit call to [`force()`]) will panic.
///
/// This concept is similar to that of poisoning in the [`std::sync::poison`] module. A key
/// difference, however, is that poisoning in `LazyLock` is _unrecoverable_. All future accesses of
/// the lock from other threads will panic, whereas a type in [`std::sync::poison`] like
/// [`std::sync::poison::Mutex`] allows recovery via [`PoisonError::into_inner()`].
///
/// [`force()`]: LazyLock::force
/// [`std::sync::poison`]: crate::sync::poison
/// [`std::sync::poison::Mutex`]: crate::sync::poison::Mutex
/// [`PoisonError::into_inner()`]: crate::sync::poison::PoisonError::into_inner
///
/// # Examples
///
/// Initialize static variables with `LazyLock`.
/// ```
/// use std::sync::LazyLock;
///
/// // Note: static items do not call [`Drop`] on program termination, so this won't be deallocated.
/// // this is fine, as the OS can deallocate the terminated program faster than we can free memory
/// // but tools like valgrind might report "memory leaks" as it isn't obvious this is intentional.
/// static DEEP_THOUGHT: LazyLock<String> = LazyLock::new(|| {
/// # mod another_crate {
/// # pub fn great_question() -> String { "42".to_string() }
/// # }
/// // M3 Ultra takes about 16 million years in --release config
/// another_crate::great_question()
/// });
///
/// // The `String` is built, stored in the `LazyLock`, and returned as `&String`.
/// let _ = &*DEEP_THOUGHT;
/// ```
///
/// Initialize fields with `LazyLock`.
/// ```
/// use std::sync::LazyLock;
///
/// #[derive(Debug)]
/// struct UseCellLock {
/// number: LazyLock<u32>,
/// }
/// fn main() {
/// let lock: LazyLock<u32> = LazyLock::new(|| 0u32);
///
/// let data = UseCellLock { number: lock };
/// println!("{}", *data.number);
/// }
/// ```
#[stable(feature = "lazy_cell", since = "1.80.0")]
pub struct LazyLock<T, F = fn() -> T> {
// FIXME(nonpoison_once): if possible, switch to nonpoison version once it is available
once: Once,
data: UnsafeCell<Data<T, F>>,
}
impl<T, F: FnOnce() -> T> LazyLock<T, F> {
/// Creates a new lazy value with the given initializing function.
///
/// # Examples
///
/// ```
/// use std::sync::LazyLock;
///
/// let hello = "Hello, World!".to_string();
///
/// let lazy = LazyLock::new(|| hello.to_uppercase());
///
/// assert_eq!(&*lazy, "HELLO, WORLD!");
/// ```
#[inline]
#[stable(feature = "lazy_cell", since = "1.80.0")]
#[rustc_const_stable(feature = "lazy_cell", since = "1.80.0")]
pub const fn new(f: F) -> LazyLock<T, F> {
LazyLock { once: Once::new(), data: UnsafeCell::new(Data { f: ManuallyDrop::new(f) }) }
}
/// Creates a new lazy value that is already initialized.
#[inline]
#[cfg(test)]
pub(crate) fn preinit(value: T) -> LazyLock<T, F> {
let once = Once::new();
once.call_once(|| {});
LazyLock { once, data: UnsafeCell::new(Data { value: ManuallyDrop::new(value) }) }
}
/// Consumes this `LazyLock` returning the stored value.
///
/// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise.
///
/// # Panics
///
/// Panics if the lock is poisoned.
///
/// # Examples
///
/// ```
/// #![feature(lazy_cell_into_inner)]
///
/// use std::sync::LazyLock;
///
/// let hello = "Hello, World!".to_string();
///
/// let lazy = LazyLock::new(|| hello.to_uppercase());
///
/// assert_eq!(&*lazy, "HELLO, WORLD!");
/// assert_eq!(LazyLock::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string()));
/// ```
#[unstable(feature = "lazy_cell_into_inner", issue = "125623")]
pub fn into_inner(mut this: Self) -> Result<T, F> {
let state = this.once.state();
match state {
OnceExclusiveState::Poisoned => panic_poisoned(),
state => {
let this = ManuallyDrop::new(this);
let data = unsafe { ptr::read(&this.data) }.into_inner();
match state {
OnceExclusiveState::Incomplete => {
Err(ManuallyDrop::into_inner(unsafe { data.f }))
}
OnceExclusiveState::Complete => {
Ok(ManuallyDrop::into_inner(unsafe { data.value }))
}
OnceExclusiveState::Poisoned => unreachable!(),
}
}
}
}
/// Forces the evaluation of this lazy value and returns a mutable reference to
/// the result.
///
/// # Panics
///
/// If the initialization closure panics (the one that is passed to the [`new()`] method), the
/// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future
/// accesses of the lock (via [`force()`] or a dereference) to panic.
///
/// [`new()`]: LazyLock::new
/// [`force()`]: LazyLock::force
///
/// # Examples
///
/// ```
/// use std::sync::LazyLock;
///
/// let mut lazy = LazyLock::new(|| 92);
///
/// let p = LazyLock::force_mut(&mut lazy);
/// assert_eq!(*p, 92);
/// *p = 44;
/// assert_eq!(*lazy, 44);
/// ```
#[inline]
#[stable(feature = "lazy_get", since = "1.94.0")]
pub fn force_mut(this: &mut LazyLock<T, F>) -> &mut T {
#[cold]
/// # Safety
/// May only be called when the state is `Incomplete`.
unsafe fn really_init_mut<T, F: FnOnce() -> T>(this: &mut LazyLock<T, F>) -> &mut T {
struct PoisonOnPanic<'a, T, F>(&'a mut LazyLock<T, F>);
impl<T, F> Drop for PoisonOnPanic<'_, T, F> {
#[inline]
fn drop(&mut self) {
self.0.once.set_state(OnceExclusiveState::Poisoned);
}
}
// SAFETY: We always poison if the initializer panics (then we never check the data),
// or set the data on success.
let f = unsafe { ManuallyDrop::take(&mut this.data.get_mut().f) };
// INVARIANT: Initiated from mutable reference, don't drop because we read it.
let guard = PoisonOnPanic(this);
let data = f();
guard.0.data.get_mut().value = ManuallyDrop::new(data);
guard.0.once.set_state(OnceExclusiveState::Complete);
core::mem::forget(guard);
// SAFETY: We put the value there above.
unsafe { &mut this.data.get_mut().value }
}
let state = this.once.state();
match state {
OnceExclusiveState::Poisoned => panic_poisoned(),
// SAFETY: The `Once` states we completed the initialization.
OnceExclusiveState::Complete => unsafe { &mut this.data.get_mut().value },
// SAFETY: The state is `Incomplete`.
OnceExclusiveState::Incomplete => unsafe { really_init_mut(this) },
}
}
/// Forces the evaluation of this lazy value and returns a reference to
/// result. This is equivalent to the `Deref` impl, but is explicit.
///
/// This method will block the calling thread if another initialization
/// routine is currently running.
///
/// # Panics
///
/// If the initialization closure panics (the one that is passed to the [`new()`] method), the
/// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future
/// accesses of the lock (via [`force()`] or a dereference) to panic.
///
/// [`new()`]: LazyLock::new
/// [`force()`]: LazyLock::force
///
/// # Examples
///
/// ```
/// use std::sync::LazyLock;
///
/// let lazy = LazyLock::new(|| 92);
///
/// assert_eq!(LazyLock::force(&lazy), &92);
/// assert_eq!(&*lazy, &92);
/// ```
#[inline]
#[stable(feature = "lazy_cell", since = "1.80.0")]
#[rustc_should_not_be_called_on_const_items]
pub fn force(this: &LazyLock<T, F>) -> &T {
this.once.call_once_force(|state| {
if state.is_poisoned() {
panic_poisoned();
}
// SAFETY: `call_once` only runs this closure once, ever.
let data = unsafe { &mut *this.data.get() };
let f = unsafe { ManuallyDrop::take(&mut data.f) };
let value = f();
data.value = ManuallyDrop::new(value);
});
// SAFETY:
// There are four possible scenarios:
// * the closure was called and initialized `value`.
// * the closure was called and panicked, so this point is never reached.
// * the closure was not called, but a previous call initialized `value`.
// * the closure was not called because the Once is poisoned, which we handled above.
// So `value` has definitely been initialized and will not be modified again.
unsafe { &*(*this.data.get()).value }
}
}
impl<T, F> LazyLock<T, F> {
/// Returns a mutable reference to the value if initialized. Otherwise (if uninitialized or
/// poisoned), returns `None`.
///
/// # Examples
///
/// ```
/// use std::sync::LazyLock;
///
/// let mut lazy = LazyLock::new(|| 92);
///
/// assert_eq!(LazyLock::get_mut(&mut lazy), None);
/// let _ = LazyLock::force(&lazy);
/// *LazyLock::get_mut(&mut lazy).unwrap() = 44;
/// assert_eq!(*lazy, 44);
/// ```
#[inline]
#[stable(feature = "lazy_get", since = "1.94.0")]
pub fn get_mut(this: &mut LazyLock<T, F>) -> Option<&mut T> {
// `state()` does not perform an atomic load, so prefer it over `is_complete()`.
let state = this.once.state();
match state {
// SAFETY:
// The closure has been run successfully, so `value` has been initialized.
OnceExclusiveState::Complete => Some(unsafe { &mut this.data.get_mut().value }),
_ => None,
}
}
/// Returns a reference to the value if initialized. Otherwise (if uninitialized or poisoned),
/// returns `None`.
///
/// # Examples
///
/// ```
/// use std::sync::LazyLock;
///
/// let lazy = LazyLock::new(|| 92);
///
/// assert_eq!(LazyLock::get(&lazy), None);
/// let _ = LazyLock::force(&lazy);
/// assert_eq!(LazyLock::get(&lazy), Some(&92));
/// ```
#[inline]
#[stable(feature = "lazy_get", since = "1.94.0")]
#[rustc_should_not_be_called_on_const_items]
pub fn get(this: &LazyLock<T, F>) -> Option<&T> {
if this.once.is_completed() {
// SAFETY:
// The closure has been run successfully, so `value` has been initialized
// and will not be modified again.
Some(unsafe { &(*this.data.get()).value })
} else {
None
}
}
}
#[stable(feature = "lazy_cell", since = "1.80.0")]
impl<T, F> Drop for LazyLock<T, F> {
fn drop(&mut self) {
match self.once.state() {
OnceExclusiveState::Incomplete => unsafe {
ManuallyDrop::drop(&mut self.data.get_mut().f)
},
OnceExclusiveState::Complete => unsafe {
ManuallyDrop::drop(&mut self.data.get_mut().value)
},
OnceExclusiveState::Poisoned => {}
}
}
}
#[stable(feature = "lazy_cell", since = "1.80.0")]
impl<T, F: FnOnce() -> T> Deref for LazyLock<T, F> {
type Target = T;
/// Dereferences the value.
///
/// This method will block the calling thread if another initialization
/// routine is currently running.
///
/// # Panics
///
/// If the initialization closure panics (the one that is passed to the [`new()`] method), the
/// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future
/// accesses of the lock (via [`force()`] or a dereference) to panic.
///
/// [`new()`]: LazyLock::new
/// [`force()`]: LazyLock::force
#[inline]
fn deref(&self) -> &T {
LazyLock::force(self)
}
}
#[stable(feature = "lazy_deref_mut", since = "1.89.0")]
impl<T, F: FnOnce() -> T> DerefMut for LazyLock<T, F> {
/// # Panics
///
/// If the initialization closure panics (the one that is passed to the [`new()`] method), the
/// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future
/// accesses of the lock (via [`force()`] or a dereference) to panic.
///
/// [`new()`]: LazyLock::new
/// [`force()`]: LazyLock::force
#[inline]
fn deref_mut(&mut self) -> &mut T {
LazyLock::force_mut(self)
}
}
#[stable(feature = "lazy_cell", since = "1.80.0")]
impl<T: Default> Default for LazyLock<T> {
/// Creates a new lazy value using `Default` as the initializing function.
#[inline]
fn default() -> LazyLock<T> {
LazyLock::new(T::default)
}
}
#[stable(feature = "lazy_cell", since = "1.80.0")]
impl<T: fmt::Debug, F> fmt::Debug for LazyLock<T, F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut d = f.debug_tuple("LazyLock");
match LazyLock::get(self) {
Some(v) => d.field(v),
None => d.field(&format_args!("<uninit>")),
};
d.finish()
}
}
#[cold]
#[inline(never)]
fn panic_poisoned() -> ! {
panic!("LazyLock instance has previously been poisoned")
}
// We never create a `&F` from a `&LazyLock<T, F>` so it is fine
// to not impl `Sync` for `F`.
#[stable(feature = "lazy_cell", since = "1.80.0")]
unsafe impl<T: Sync + Send, F: Send> Sync for LazyLock<T, F> {}
// auto-derived `Send` impl is OK.
#[stable(feature = "lazy_cell", since = "1.80.0")]
impl<T: RefUnwindSafe + UnwindSafe, F: UnwindSafe> RefUnwindSafe for LazyLock<T, F> {}
#[stable(feature = "lazy_cell", since = "1.80.0")]
impl<T: UnwindSafe, F: UnwindSafe> UnwindSafe for LazyLock<T, F> {}

View File

@@ -0,0 +1,569 @@
//! Bounded channel based on a preallocated array.
//!
//! This flavor has a fixed, positive capacity.
//!
//! The implementation is based on Dmitry Vyukov's bounded MPMC queue.
//!
//! Source:
//! - <http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue>
//! - <https://docs.google.com/document/d/1yIAYmbvL3JxOKOjuCyon7JhW4cSv1wy5hC0ApeGMV9s/pub>
use super::context::Context;
use super::error::*;
use super::select::{Operation, Selected, Token};
use super::utils::{Backoff, CachePadded};
use super::waker::SyncWaker;
use crate::cell::UnsafeCell;
use crate::mem::MaybeUninit;
use crate::ptr;
use crate::sync::atomic::{self, Atomic, AtomicUsize, Ordering};
use crate::time::Instant;
/// A slot in a channel.
struct Slot<T> {
/// The current stamp.
stamp: Atomic<usize>,
/// The message in this slot. Either read out in `read` or dropped through
/// `discard_all_messages`.
msg: UnsafeCell<MaybeUninit<T>>,
}
/// The token type for the array flavor.
#[derive(Debug)]
pub(crate) struct ArrayToken {
/// Slot to read from or write to.
slot: *const u8,
/// Stamp to store into the slot after reading or writing.
stamp: usize,
}
impl Default for ArrayToken {
#[inline]
fn default() -> Self {
ArrayToken { slot: ptr::null(), stamp: 0 }
}
}
/// Bounded channel based on a preallocated array.
pub(crate) struct Channel<T> {
/// The head of the channel.
///
/// This value is a "stamp" consisting of an index into the buffer, a mark bit, and a lap, but
/// packed into a single `usize`. The lower bits represent the index, while the upper bits
/// represent the lap. The mark bit in the head is always zero.
///
/// Messages are popped from the head of the channel.
head: CachePadded<Atomic<usize>>,
/// The tail of the channel.
///
/// This value is a "stamp" consisting of an index into the buffer, a mark bit, and a lap, but
/// packed into a single `usize`. The lower bits represent the index, while the upper bits
/// represent the lap. The mark bit indicates that the channel is disconnected.
///
/// Messages are pushed into the tail of the channel.
tail: CachePadded<Atomic<usize>>,
/// The buffer holding slots.
buffer: Box<[Slot<T>]>,
/// The channel capacity.
cap: usize,
/// A stamp with the value of `{ lap: 1, mark: 0, index: 0 }`.
one_lap: usize,
/// If this bit is set in the tail, that means the channel is disconnected.
mark_bit: usize,
/// Senders waiting while the channel is full.
senders: SyncWaker,
/// Receivers waiting while the channel is empty and not disconnected.
receivers: SyncWaker,
}
impl<T> Channel<T> {
/// Creates a bounded channel of capacity `cap`.
pub(crate) fn with_capacity(cap: usize) -> Self {
assert!(cap > 0, "capacity must be positive");
// Compute constants `mark_bit` and `one_lap`.
let mark_bit = (cap + 1).next_power_of_two();
let one_lap = mark_bit * 2;
// Head is initialized to `{ lap: 0, mark: 0, index: 0 }`.
let head = 0;
// Tail is initialized to `{ lap: 0, mark: 0, index: 0 }`.
let tail = 0;
// Allocate a buffer of `cap` slots initialized
// with stamps.
let buffer: Box<[Slot<T>]> = (0..cap)
.map(|i| {
// Set the stamp to `{ lap: 0, mark: 0, index: i }`.
Slot { stamp: AtomicUsize::new(i), msg: UnsafeCell::new(MaybeUninit::uninit()) }
})
.collect();
Channel {
buffer,
cap,
one_lap,
mark_bit,
head: CachePadded::new(AtomicUsize::new(head)),
tail: CachePadded::new(AtomicUsize::new(tail)),
senders: SyncWaker::new(),
receivers: SyncWaker::new(),
}
}
/// Attempts to reserve a slot for sending a message.
fn start_send(&self, token: &mut Token) -> bool {
let backoff = Backoff::new();
let mut tail = self.tail.load(Ordering::Relaxed);
loop {
// Check if the channel is disconnected.
if tail & self.mark_bit != 0 {
token.array.slot = ptr::null();
token.array.stamp = 0;
return true;
}
// Deconstruct the tail.
let index = tail & (self.mark_bit - 1);
let lap = tail & !(self.one_lap - 1);
// Inspect the corresponding slot.
debug_assert!(index < self.buffer.len());
let slot = unsafe { self.buffer.get_unchecked(index) };
let stamp = slot.stamp.load(Ordering::Acquire);
// If the tail and the stamp match, we may attempt to push.
if tail == stamp {
let new_tail = if index + 1 < self.cap {
// Same lap, incremented index.
// Set to `{ lap: lap, mark: 0, index: index + 1 }`.
tail + 1
} else {
// One lap forward, index wraps around to zero.
// Set to `{ lap: lap.wrapping_add(1), mark: 0, index: 0 }`.
lap.wrapping_add(self.one_lap)
};
// Try moving the tail.
match self.tail.compare_exchange_weak(
tail,
new_tail,
Ordering::SeqCst,
Ordering::Relaxed,
) {
Ok(_) => {
// Prepare the token for the follow-up call to `write`.
token.array.slot = slot as *const Slot<T> as *const u8;
token.array.stamp = tail + 1;
return true;
}
Err(_) => {
backoff.spin_light();
tail = self.tail.load(Ordering::Relaxed);
}
}
} else if stamp.wrapping_add(self.one_lap) == tail + 1 {
atomic::fence(Ordering::SeqCst);
let head = self.head.load(Ordering::Relaxed);
// If the head lags one lap behind the tail as well...
if head.wrapping_add(self.one_lap) == tail {
// ...then the channel is full.
return false;
}
backoff.spin_light();
tail = self.tail.load(Ordering::Relaxed);
} else {
// Snooze because we need to wait for the stamp to get updated.
backoff.spin_heavy();
tail = self.tail.load(Ordering::Relaxed);
}
}
}
/// Writes a message into the channel.
pub(crate) unsafe fn write(&self, token: &mut Token, msg: T) -> Result<(), T> {
// If there is no slot, the channel is disconnected.
if token.array.slot.is_null() {
return Err(msg);
}
// Write the message into the slot and update the stamp.
unsafe {
let slot: &Slot<T> = &*(token.array.slot as *const Slot<T>);
slot.msg.get().write(MaybeUninit::new(msg));
slot.stamp.store(token.array.stamp, Ordering::Release);
}
// Wake a sleeping receiver.
self.receivers.notify();
Ok(())
}
/// Attempts to reserve a slot for receiving a message.
fn start_recv(&self, token: &mut Token) -> bool {
let backoff = Backoff::new();
let mut head = self.head.load(Ordering::Relaxed);
loop {
// Deconstruct the head.
let index = head & (self.mark_bit - 1);
let lap = head & !(self.one_lap - 1);
// Inspect the corresponding slot.
debug_assert!(index < self.buffer.len());
let slot = unsafe { self.buffer.get_unchecked(index) };
let stamp = slot.stamp.load(Ordering::Acquire);
// If the stamp is ahead of the head by 1, we may attempt to pop.
if head + 1 == stamp {
let new = if index + 1 < self.cap {
// Same lap, incremented index.
// Set to `{ lap: lap, mark: 0, index: index + 1 }`.
head + 1
} else {
// One lap forward, index wraps around to zero.
// Set to `{ lap: lap.wrapping_add(1), mark: 0, index: 0 }`.
lap.wrapping_add(self.one_lap)
};
// Try moving the head.
match self.head.compare_exchange_weak(
head,
new,
Ordering::SeqCst,
Ordering::Relaxed,
) {
Ok(_) => {
// Prepare the token for the follow-up call to `read`.
token.array.slot = slot as *const Slot<T> as *const u8;
token.array.stamp = head.wrapping_add(self.one_lap);
return true;
}
Err(_) => {
backoff.spin_light();
head = self.head.load(Ordering::Relaxed);
}
}
} else if stamp == head {
atomic::fence(Ordering::SeqCst);
let tail = self.tail.load(Ordering::Relaxed);
// If the tail equals the head, that means the channel is empty.
if (tail & !self.mark_bit) == head {
// If the channel is disconnected...
if tail & self.mark_bit != 0 {
// ...then receive an error.
token.array.slot = ptr::null();
token.array.stamp = 0;
return true;
} else {
// Otherwise, the receive operation is not ready.
return false;
}
}
backoff.spin_light();
head = self.head.load(Ordering::Relaxed);
} else {
// Snooze because we need to wait for the stamp to get updated.
backoff.spin_heavy();
head = self.head.load(Ordering::Relaxed);
}
}
}
/// Reads a message from the channel.
pub(crate) unsafe fn read(&self, token: &mut Token) -> Result<T, ()> {
if token.array.slot.is_null() {
// The channel is disconnected.
return Err(());
}
// Read the message from the slot and update the stamp.
let msg = unsafe {
let slot: &Slot<T> = &*(token.array.slot as *const Slot<T>);
let msg = slot.msg.get().read().assume_init();
slot.stamp.store(token.array.stamp, Ordering::Release);
msg
};
// Wake a sleeping sender.
self.senders.notify();
Ok(msg)
}
/// Attempts to send a message into the channel.
pub(crate) fn try_send(&self, msg: T) -> Result<(), TrySendError<T>> {
let token = &mut Token::default();
if self.start_send(token) {
unsafe { self.write(token, msg).map_err(TrySendError::Disconnected) }
} else {
Err(TrySendError::Full(msg))
}
}
/// Sends a message into the channel.
pub(crate) fn send(
&self,
msg: T,
deadline: Option<Instant>,
) -> Result<(), SendTimeoutError<T>> {
let token = &mut Token::default();
loop {
// Try sending a message.
if self.start_send(token) {
let res = unsafe { self.write(token, msg) };
return res.map_err(SendTimeoutError::Disconnected);
}
if let Some(d) = deadline {
if Instant::now() >= d {
return Err(SendTimeoutError::Timeout(msg));
}
}
Context::with(|cx| {
// Prepare for blocking until a receiver wakes us up.
let oper = Operation::hook(token);
self.senders.register(oper, cx);
// Has the channel become ready just now?
if !self.is_full() || self.is_disconnected() {
let _ = cx.try_select(Selected::Aborted);
}
// Block the current thread.
// SAFETY: the context belongs to the current thread.
let sel = unsafe { cx.wait_until(deadline) };
match sel {
Selected::Waiting => unreachable!(),
Selected::Aborted | Selected::Disconnected => {
self.senders.unregister(oper).unwrap();
}
Selected::Operation(_) => {}
}
});
}
}
/// Attempts to receive a message without blocking.
pub(crate) fn try_recv(&self) -> Result<T, TryRecvError> {
let token = &mut Token::default();
if self.start_recv(token) {
unsafe { self.read(token).map_err(|_| TryRecvError::Disconnected) }
} else {
Err(TryRecvError::Empty)
}
}
/// Receives a message from the channel.
pub(crate) fn recv(&self, deadline: Option<Instant>) -> Result<T, RecvTimeoutError> {
let token = &mut Token::default();
loop {
// Try receiving a message.
if self.start_recv(token) {
let res = unsafe { self.read(token) };
return res.map_err(|_| RecvTimeoutError::Disconnected);
}
if let Some(d) = deadline {
if Instant::now() >= d {
return Err(RecvTimeoutError::Timeout);
}
}
Context::with(|cx| {
// Prepare for blocking until a sender wakes us up.
let oper = Operation::hook(token);
self.receivers.register(oper, cx);
// Has the channel become ready just now?
if !self.is_empty() || self.is_disconnected() {
let _ = cx.try_select(Selected::Aborted);
}
// Block the current thread.
// SAFETY: the context belongs to the current thread.
let sel = unsafe { cx.wait_until(deadline) };
match sel {
Selected::Waiting => unreachable!(),
Selected::Aborted | Selected::Disconnected => {
self.receivers.unregister(oper).unwrap();
// If the channel was disconnected, we still have to check for remaining
// messages.
}
Selected::Operation(_) => {}
}
});
}
}
/// Returns the current number of messages inside the channel.
pub(crate) fn len(&self) -> usize {
loop {
// Load the tail, then load the head.
let tail = self.tail.load(Ordering::SeqCst);
let head = self.head.load(Ordering::SeqCst);
// If the tail didn't change, we've got consistent values to work with.
if self.tail.load(Ordering::SeqCst) == tail {
let hix = head & (self.mark_bit - 1);
let tix = tail & (self.mark_bit - 1);
return if hix < tix {
tix - hix
} else if hix > tix {
self.cap - hix + tix
} else if (tail & !self.mark_bit) == head {
0
} else {
self.cap
};
}
}
}
/// Returns the capacity of the channel.
#[allow(clippy::unnecessary_wraps)] // This is intentional.
pub(crate) fn capacity(&self) -> Option<usize> {
Some(self.cap)
}
/// Disconnects senders and wakes up all blocked receivers.
///
/// Returns `true` if this call disconnected the channel.
pub(crate) fn disconnect_senders(&self) -> bool {
let tail = self.tail.fetch_or(self.mark_bit, Ordering::SeqCst);
if tail & self.mark_bit == 0 {
self.receivers.disconnect();
true
} else {
false
}
}
/// Disconnects receivers and wakes up all blocked senders.
///
/// Returns `true` if this call disconnected the channel.
///
/// # Safety
/// May only be called once upon dropping the last receiver. The
/// destruction of all other receivers must have been observed with acquire
/// ordering or stronger.
pub(crate) unsafe fn disconnect_receivers(&self) -> bool {
let tail = self.tail.fetch_or(self.mark_bit, Ordering::SeqCst);
let disconnected = if tail & self.mark_bit == 0 {
self.senders.disconnect();
true
} else {
false
};
unsafe { self.discard_all_messages(tail) };
disconnected
}
/// Discards all messages.
///
/// `tail` should be the current (and therefore last) value of `tail`.
///
/// # Panicking
/// If a destructor panics, the remaining messages are leaked, matching the
/// behavior of the unbounded channel.
///
/// # Safety
/// This method must only be called when dropping the last receiver. The
/// destruction of all other receivers must have been observed with acquire
/// ordering or stronger.
unsafe fn discard_all_messages(&self, tail: usize) {
debug_assert!(self.is_disconnected());
// Only receivers modify `head`, so since we are the last one,
// this value will not change and will not be observed (since
// no new messages can be sent after disconnection).
let mut head = self.head.load(Ordering::Relaxed);
let tail = tail & !self.mark_bit;
let backoff = Backoff::new();
loop {
// Deconstruct the head.
let index = head & (self.mark_bit - 1);
let lap = head & !(self.one_lap - 1);
// Inspect the corresponding slot.
debug_assert!(index < self.buffer.len());
let slot = unsafe { self.buffer.get_unchecked(index) };
let stamp = slot.stamp.load(Ordering::Acquire);
// If the stamp is ahead of the head by 1, we may drop the message.
if head + 1 == stamp {
head = if index + 1 < self.cap {
// Same lap, incremented index.
// Set to `{ lap: lap, mark: 0, index: index + 1 }`.
head + 1
} else {
// One lap forward, index wraps around to zero.
// Set to `{ lap: lap.wrapping_add(1), mark: 0, index: 0 }`.
lap.wrapping_add(self.one_lap)
};
unsafe {
(*slot.msg.get()).assume_init_drop();
}
// If the tail equals the head, that means the channel is empty.
} else if tail == head {
return;
// Otherwise, a sender is about to write into the slot, so we need
// to wait for it to update the stamp.
} else {
backoff.spin_heavy();
}
}
}
/// Returns `true` if the channel is disconnected.
pub(crate) fn is_disconnected(&self) -> bool {
self.tail.load(Ordering::SeqCst) & self.mark_bit != 0
}
/// Returns `true` if the channel is empty.
pub(crate) fn is_empty(&self) -> bool {
let head = self.head.load(Ordering::SeqCst);
let tail = self.tail.load(Ordering::SeqCst);
// Is the tail equal to the head?
//
// Note: If the head changes just before we load the tail, that means there was a moment
// when the channel was not empty, so it is safe to just return `false`.
(tail & !self.mark_bit) == head
}
/// Returns `true` if the channel is full.
pub(crate) fn is_full(&self) -> bool {
let tail = self.tail.load(Ordering::SeqCst);
let head = self.head.load(Ordering::SeqCst);
// Is the head lagging one lap behind tail?
//
// Note: If the tail changes just before we load the head, that means there was a moment
// when the channel was not full, so it is safe to just return `false`.
head.wrapping_add(self.one_lap) == tail & !self.mark_bit
}
}

View File

@@ -0,0 +1,159 @@
//! Thread-local channel context.
use super::select::Selected;
use super::waker::current_thread_id;
use crate::cell::Cell;
use crate::ptr;
use alloc_crate::sync::Arc;
use crate::sync::atomic::{Atomic, AtomicPtr, AtomicUsize, Ordering};
use crate::thread::{self, Thread};
use crate::time::Instant;
/// Thread-local context.
#[derive(Debug, Clone)]
pub struct Context {
inner: Arc<Inner>,
}
/// Inner representation of `Context`.
#[derive(Debug)]
struct Inner {
/// Selected operation.
select: Atomic<usize>,
/// A slot into which another thread may store a pointer to its `Packet`.
packet: Atomic<*mut ()>,
/// Thread handle.
thread: Thread,
/// Thread id.
thread_id: usize,
}
impl Context {
/// Creates a new context for the duration of the closure.
#[inline]
pub fn with<F, R>(f: F) -> R
where
F: FnOnce(&Context) -> R,
{
thread_local! {
/// Cached thread-local context.
static CONTEXT: Cell<Option<Context>> = Cell::new(Some(Context::new()));
}
let mut f = Some(f);
let mut f = |cx: &Context| -> R {
let f = f.take().unwrap();
f(cx)
};
CONTEXT
.try_with(|cell| match cell.take() {
None => f(&Context::new()),
Some(cx) => {
cx.reset();
let res = f(&cx);
cell.set(Some(cx));
res
}
})
.unwrap_or_else(|_| f(&Context::new()))
}
/// Creates a new `Context`.
#[cold]
fn new() -> Context {
Context {
inner: Arc::new(Inner {
select: AtomicUsize::new(Selected::Waiting.into()),
packet: AtomicPtr::new(ptr::null_mut()),
thread: thread::current_or_unnamed(),
thread_id: current_thread_id(),
}),
}
}
/// Resets `select` and `packet`.
#[inline]
fn reset(&self) {
self.inner.select.store(Selected::Waiting.into(), Ordering::Release);
self.inner.packet.store(ptr::null_mut(), Ordering::Release);
}
/// Attempts to select an operation.
///
/// On failure, the previously selected operation is returned.
#[inline]
pub fn try_select(&self, select: Selected) -> Result<(), Selected> {
self.inner
.select
.compare_exchange(
Selected::Waiting.into(),
select.into(),
Ordering::AcqRel,
Ordering::Acquire,
)
.map(|_| ())
.map_err(|e| e.into())
}
/// Stores a packet.
///
/// This method must be called after `try_select` succeeds and there is a packet to provide.
#[inline]
pub fn store_packet(&self, packet: *mut ()) {
if !packet.is_null() {
self.inner.packet.store(packet, Ordering::Release);
}
}
/// Waits until an operation is selected and returns it.
///
/// If the deadline is reached, `Selected::Aborted` will be selected.
///
/// # Safety
/// This may only be called from the thread this `Context` belongs to.
#[inline]
pub unsafe fn wait_until(&self, deadline: Option<Instant>) -> Selected {
loop {
// Check whether an operation has been selected.
let sel = Selected::from(self.inner.select.load(Ordering::Acquire));
if sel != Selected::Waiting {
return sel;
}
// If there's a deadline, park the current thread until the deadline is reached.
if let Some(end) = deadline {
let now = Instant::now();
if now < end {
// SAFETY: guaranteed by caller.
unsafe { self.inner.thread.park_timeout(end - now) };
} else {
// The deadline has been reached. Try aborting select.
return match self.try_select(Selected::Aborted) {
Ok(()) => Selected::Aborted,
Err(s) => s,
};
}
} else {
// SAFETY: guaranteed by caller.
unsafe { self.inner.thread.park() };
}
}
}
/// Unparks the thread this context belongs to.
#[inline]
pub fn unpark(&self) {
self.inner.thread.unpark();
}
/// Returns the id of the thread this context belongs to.
#[inline]
pub fn thread_id(&self) -> usize {
self.inner.thread_id
}
}

View File

@@ -0,0 +1,136 @@
use crate::sync::atomic::{Atomic, AtomicBool, AtomicUsize, Ordering};
use crate::{ops, process};
/// Reference counter internals.
struct Counter<C> {
/// The number of senders associated with the channel.
senders: Atomic<usize>,
/// The number of receivers associated with the channel.
receivers: Atomic<usize>,
/// Set to `true` if the last sender or the last receiver reference deallocates the channel.
destroy: Atomic<bool>,
/// The internal channel.
chan: C,
}
/// Wraps a channel into the reference counter.
pub(crate) fn new<C>(chan: C) -> (Sender<C>, Receiver<C>) {
let counter = Box::into_raw(Box::new(Counter {
senders: AtomicUsize::new(1),
receivers: AtomicUsize::new(1),
destroy: AtomicBool::new(false),
chan,
}));
let s = Sender { counter };
let r = Receiver { counter };
(s, r)
}
/// The sending side.
pub(crate) struct Sender<C> {
counter: *mut Counter<C>,
}
impl<C> Sender<C> {
/// Returns the internal `Counter`.
fn counter(&self) -> &Counter<C> {
unsafe { &*self.counter }
}
/// Acquires another sender reference.
pub(crate) fn acquire(&self) -> Sender<C> {
let count = self.counter().senders.fetch_add(1, Ordering::Relaxed);
// Cloning senders and calling `mem::forget` on the clones could potentially overflow the
// counter. It's very difficult to recover sensibly from such degenerate scenarios so we
// just abort when the count becomes very large.
if count > isize::MAX as usize {
process::abort();
}
Sender { counter: self.counter }
}
/// Releases the sender reference.
///
/// Function `disconnect` will be called if this is the last sender reference.
pub(crate) unsafe fn release<F: FnOnce(&C) -> bool>(&self, disconnect: F) {
if self.counter().senders.fetch_sub(1, Ordering::AcqRel) == 1 {
disconnect(&self.counter().chan);
if self.counter().destroy.swap(true, Ordering::AcqRel) {
drop(unsafe { Box::from_raw(self.counter) });
}
}
}
}
impl<C> ops::Deref for Sender<C> {
type Target = C;
fn deref(&self) -> &C {
&self.counter().chan
}
}
impl<C> PartialEq for Sender<C> {
fn eq(&self, other: &Sender<C>) -> bool {
self.counter == other.counter
}
}
/// The receiving side.
pub(crate) struct Receiver<C> {
counter: *mut Counter<C>,
}
impl<C> Receiver<C> {
/// Returns the internal `Counter`.
fn counter(&self) -> &Counter<C> {
unsafe { &*self.counter }
}
/// Acquires another receiver reference.
pub(crate) fn acquire(&self) -> Receiver<C> {
let count = self.counter().receivers.fetch_add(1, Ordering::Relaxed);
// Cloning receivers and calling `mem::forget` on the clones could potentially overflow the
// counter. It's very difficult to recover sensibly from such degenerate scenarios so we
// just abort when the count becomes very large.
if count > isize::MAX as usize {
process::abort();
}
Receiver { counter: self.counter }
}
/// Releases the receiver reference.
///
/// Function `disconnect` will be called if this is the last receiver reference.
pub(crate) unsafe fn release<F: FnOnce(&C) -> bool>(&self, disconnect: F) {
if self.counter().receivers.fetch_sub(1, Ordering::AcqRel) == 1 {
disconnect(&self.counter().chan);
if self.counter().destroy.swap(true, Ordering::AcqRel) {
drop(unsafe { Box::from_raw(self.counter) });
}
}
}
}
impl<C> ops::Deref for Receiver<C> {
type Target = C;
fn deref(&self) -> &C {
&self.counter().chan
}
}
impl<C> PartialEq for Receiver<C> {
fn eq(&self, other: &Receiver<C>) -> bool {
self.counter == other.counter
}
}

View File

@@ -0,0 +1,49 @@
pub use crate::sync::mpsc::{RecvError, RecvTimeoutError, SendError, TryRecvError, TrySendError};
use crate::{error, fmt};
/// An error returned from the [`send_timeout`] method.
///
/// The error contains the message being sent so it can be recovered.
///
/// [`send_timeout`]: super::Sender::send_timeout
#[derive(PartialEq, Eq, Clone, Copy)]
#[unstable(feature = "mpmc_channel", issue = "126840")]
pub enum SendTimeoutError<T> {
/// The message could not be sent because the channel is full and the operation timed out.
///
/// If this is a zero-capacity channel, then the error indicates that there was no receiver
/// available to receive the message and the operation timed out.
Timeout(T),
/// The message could not be sent because the channel is disconnected.
Disconnected(T),
}
#[unstable(feature = "mpmc_channel", issue = "126840")]
impl<T> fmt::Debug for SendTimeoutError<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
"SendTimeoutError(..)".fmt(f)
}
}
#[unstable(feature = "mpmc_channel", issue = "126840")]
impl<T> fmt::Display for SendTimeoutError<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
SendTimeoutError::Timeout(..) => "timed out waiting on send operation".fmt(f),
SendTimeoutError::Disconnected(..) => "sending on a disconnected channel".fmt(f),
}
}
}
#[unstable(feature = "mpmc_channel", issue = "126840")]
impl<T> error::Error for SendTimeoutError<T> {}
#[unstable(feature = "mpmc_channel", issue = "126840")]
impl<T> From<SendError<T>> for SendTimeoutError<T> {
fn from(err: SendError<T>) -> SendTimeoutError<T> {
match err {
SendError(e) => SendTimeoutError::Disconnected(e),
}
}
}

View File

@@ -0,0 +1,668 @@
//! Unbounded channel implemented as a linked list.
use super::context::Context;
use super::error::*;
use super::select::{Operation, Selected, Token};
use super::utils::{Backoff, CachePadded};
use super::waker::SyncWaker;
use crate::cell::UnsafeCell;
use crate::marker::PhantomData;
use crate::mem::MaybeUninit;
use crate::ptr;
use crate::sync::atomic::{self, Atomic, AtomicPtr, AtomicUsize, Ordering};
use crate::time::Instant;
// Bits indicating the state of a slot:
// * If a message has been written into the slot, `WRITE` is set.
// * If a message has been read from the slot, `READ` is set.
// * If the block is being destroyed, `DESTROY` is set.
const WRITE: usize = 1;
const READ: usize = 2;
const DESTROY: usize = 4;
// Each block covers one "lap" of indices.
const LAP: usize = 32;
// The maximum number of messages a block can hold.
const BLOCK_CAP: usize = LAP - 1;
// How many lower bits are reserved for metadata.
const SHIFT: usize = 1;
// Has two different purposes:
// * If set in head, indicates that the block is not the last one.
// * If set in tail, indicates that the channel is disconnected.
const MARK_BIT: usize = 1;
/// A slot in a block.
struct Slot<T> {
/// The message.
msg: UnsafeCell<MaybeUninit<T>>,
/// The state of the slot.
state: Atomic<usize>,
}
impl<T> Slot<T> {
/// Waits until a message is written into the slot.
fn wait_write(&self) {
let backoff = Backoff::new();
while self.state.load(Ordering::Acquire) & WRITE == 0 {
backoff.spin_heavy();
}
}
}
/// A block in a linked list.
///
/// Each block in the list can hold up to `BLOCK_CAP` messages.
struct Block<T> {
/// The next block in the linked list.
next: Atomic<*mut Block<T>>,
/// Slots for messages.
slots: [Slot<T>; BLOCK_CAP],
}
impl<T> Block<T> {
/// Creates an empty block.
fn new() -> Box<Block<T>> {
// SAFETY: This is safe because:
// [1] `Block::next` (Atomic<*mut _>) may be safely zero initialized.
// [2] `Block::slots` (Array) may be safely zero initialized because of [3, 4].
// [3] `Slot::msg` (UnsafeCell) may be safely zero initialized because it
// holds a MaybeUninit.
// [4] `Slot::state` (Atomic<usize>) may be safely zero initialized.
unsafe { Box::new_zeroed().assume_init() }
}
/// Waits until the next pointer is set.
fn wait_next(&self) -> *mut Block<T> {
let backoff = Backoff::new();
loop {
let next = self.next.load(Ordering::Acquire);
if !next.is_null() {
return next;
}
backoff.spin_heavy();
}
}
/// Sets the `DESTROY` bit in slots starting from `start` and destroys the block.
unsafe fn destroy(this: *mut Block<T>, start: usize) {
// It is not necessary to set the `DESTROY` bit in the last slot because that slot has
// begun destruction of the block.
for i in start..BLOCK_CAP - 1 {
let slot = unsafe { (*this).slots.get_unchecked(i) };
// Mark the `DESTROY` bit if a thread is still using the slot.
if slot.state.load(Ordering::Acquire) & READ == 0
&& slot.state.fetch_or(DESTROY, Ordering::AcqRel) & READ == 0
{
// If a thread is still using the slot, it will continue destruction of the block.
return;
}
}
// No thread is using the block, now it is safe to destroy it.
drop(unsafe { Box::from_raw(this) });
}
}
/// A position in a channel.
#[derive(Debug)]
struct Position<T> {
/// The index in the channel.
index: Atomic<usize>,
/// The block in the linked list.
block: Atomic<*mut Block<T>>,
}
/// The token type for the list flavor.
#[derive(Debug)]
pub(crate) struct ListToken {
/// The block of slots.
block: *const u8,
/// The offset into the block.
offset: usize,
}
impl Default for ListToken {
#[inline]
fn default() -> Self {
ListToken { block: ptr::null(), offset: 0 }
}
}
/// Unbounded channel implemented as a linked list.
///
/// Each message sent into the channel is assigned a sequence number, i.e. an index. Indices are
/// represented as numbers of type `usize` and wrap on overflow.
///
/// Consecutive messages are grouped into blocks in order to put less pressure on the allocator and
/// improve cache efficiency.
pub(crate) struct Channel<T> {
/// The head of the channel.
head: CachePadded<Position<T>>,
/// The tail of the channel.
tail: CachePadded<Position<T>>,
/// Receivers waiting while the channel is empty and not disconnected.
receivers: SyncWaker,
/// Indicates that dropping a `Channel<T>` may drop messages of type `T`.
_marker: PhantomData<T>,
}
impl<T> Channel<T> {
/// Creates a new unbounded channel.
pub(crate) fn new() -> Self {
Channel {
head: CachePadded::new(Position {
block: AtomicPtr::new(ptr::null_mut()),
index: AtomicUsize::new(0),
}),
tail: CachePadded::new(Position {
block: AtomicPtr::new(ptr::null_mut()),
index: AtomicUsize::new(0),
}),
receivers: SyncWaker::new(),
_marker: PhantomData,
}
}
/// Attempts to reserve a slot for sending a message.
fn start_send(&self, token: &mut Token) -> bool {
let backoff = Backoff::new();
let mut tail = self.tail.index.load(Ordering::Acquire);
let mut block = self.tail.block.load(Ordering::Acquire);
let mut next_block = None;
loop {
// Check if the channel is disconnected.
if tail & MARK_BIT != 0 {
token.list.block = ptr::null();
return true;
}
// Calculate the offset of the index into the block.
let offset = (tail >> SHIFT) % LAP;
// If we reached the end of the block, wait until the next one is installed.
if offset == BLOCK_CAP {
backoff.spin_heavy();
tail = self.tail.index.load(Ordering::Acquire);
block = self.tail.block.load(Ordering::Acquire);
continue;
}
// If we're going to have to install the next block, allocate it in advance in order to
// make the wait for other threads as short as possible.
if offset + 1 == BLOCK_CAP && next_block.is_none() {
next_block = Some(Block::<T>::new());
}
// If this is the first message to be sent into the channel, we need to allocate the
// first block and install it.
if block.is_null() {
let new = Box::into_raw(Block::<T>::new());
if self
.tail
.block
.compare_exchange(block, new, Ordering::Release, Ordering::Relaxed)
.is_ok()
{
// This yield point leaves the channel in a half-initialized state where the
// tail.block pointer is set but the head.block is not. This is used to
// facilitate the test in src/tools/miri/tests/pass/issues/issue-139553.rs
#[cfg(miri)]
crate::thread::yield_now();
self.head.block.store(new, Ordering::Release);
block = new;
} else {
next_block = unsafe { Some(Box::from_raw(new)) };
tail = self.tail.index.load(Ordering::Acquire);
block = self.tail.block.load(Ordering::Acquire);
continue;
}
}
let new_tail = tail + (1 << SHIFT);
// Try advancing the tail forward.
match self.tail.index.compare_exchange_weak(
tail,
new_tail,
Ordering::SeqCst,
Ordering::Acquire,
) {
Ok(_) => unsafe {
// If we've reached the end of the block, install the next one.
if offset + 1 == BLOCK_CAP {
let next_block = Box::into_raw(next_block.unwrap());
self.tail.block.store(next_block, Ordering::Release);
self.tail.index.fetch_add(1 << SHIFT, Ordering::Release);
(*block).next.store(next_block, Ordering::Release);
}
token.list.block = block as *const u8;
token.list.offset = offset;
return true;
},
Err(_) => {
backoff.spin_light();
tail = self.tail.index.load(Ordering::Acquire);
block = self.tail.block.load(Ordering::Acquire);
}
}
}
}
/// Writes a message into the channel.
pub(crate) unsafe fn write(&self, token: &mut Token, msg: T) -> Result<(), T> {
// If there is no slot, the channel is disconnected.
if token.list.block.is_null() {
return Err(msg);
}
// Write the message into the slot.
let block = token.list.block as *mut Block<T>;
let offset = token.list.offset;
unsafe {
let slot = (*block).slots.get_unchecked(offset);
slot.msg.get().write(MaybeUninit::new(msg));
slot.state.fetch_or(WRITE, Ordering::Release);
}
// Wake a sleeping receiver.
self.receivers.notify();
Ok(())
}
/// Attempts to reserve a slot for receiving a message.
fn start_recv(&self, token: &mut Token) -> bool {
let backoff = Backoff::new();
let mut head = self.head.index.load(Ordering::Acquire);
let mut block = self.head.block.load(Ordering::Acquire);
loop {
// Calculate the offset of the index into the block.
let offset = (head >> SHIFT) % LAP;
// If we reached the end of the block, wait until the next one is installed.
if offset == BLOCK_CAP {
backoff.spin_heavy();
head = self.head.index.load(Ordering::Acquire);
block = self.head.block.load(Ordering::Acquire);
continue;
}
let mut new_head = head + (1 << SHIFT);
if new_head & MARK_BIT == 0 {
atomic::fence(Ordering::SeqCst);
let tail = self.tail.index.load(Ordering::Relaxed);
// If the tail equals the head, that means the channel is empty.
if head >> SHIFT == tail >> SHIFT {
// If the channel is disconnected...
if tail & MARK_BIT != 0 {
// ...then receive an error.
token.list.block = ptr::null();
return true;
} else {
// Otherwise, the receive operation is not ready.
return false;
}
}
// If head and tail are not in the same block, set `MARK_BIT` in head.
if (head >> SHIFT) / LAP != (tail >> SHIFT) / LAP {
new_head |= MARK_BIT;
}
}
// The block can be null here only if the first message is being sent into the channel.
// In that case, just wait until it gets initialized.
if block.is_null() {
backoff.spin_heavy();
head = self.head.index.load(Ordering::Acquire);
block = self.head.block.load(Ordering::Acquire);
continue;
}
// Try moving the head index forward.
match self.head.index.compare_exchange_weak(
head,
new_head,
Ordering::SeqCst,
Ordering::Acquire,
) {
Ok(_) => unsafe {
// If we've reached the end of the block, move to the next one.
if offset + 1 == BLOCK_CAP {
let next = (*block).wait_next();
let mut next_index = (new_head & !MARK_BIT).wrapping_add(1 << SHIFT);
if !(*next).next.load(Ordering::Relaxed).is_null() {
next_index |= MARK_BIT;
}
self.head.block.store(next, Ordering::Release);
self.head.index.store(next_index, Ordering::Release);
}
token.list.block = block as *const u8;
token.list.offset = offset;
return true;
},
Err(_) => {
backoff.spin_light();
head = self.head.index.load(Ordering::Acquire);
block = self.head.block.load(Ordering::Acquire);
}
}
}
}
/// Reads a message from the channel.
pub(crate) unsafe fn read(&self, token: &mut Token) -> Result<T, ()> {
if token.list.block.is_null() {
// The channel is disconnected.
return Err(());
}
// Read the message.
let block = token.list.block as *mut Block<T>;
let offset = token.list.offset;
unsafe {
let slot = (*block).slots.get_unchecked(offset);
slot.wait_write();
let msg = slot.msg.get().read().assume_init();
// Destroy the block if we've reached the end, or if another thread wanted to destroy but
// couldn't because we were busy reading from the slot.
if offset + 1 == BLOCK_CAP {
Block::destroy(block, 0);
} else if slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0 {
Block::destroy(block, offset + 1);
}
Ok(msg)
}
}
/// Attempts to send a message into the channel.
pub(crate) fn try_send(&self, msg: T) -> Result<(), TrySendError<T>> {
self.send(msg, None).map_err(|err| match err {
SendTimeoutError::Disconnected(msg) => TrySendError::Disconnected(msg),
SendTimeoutError::Timeout(_) => unreachable!(),
})
}
/// Sends a message into the channel.
pub(crate) fn send(
&self,
msg: T,
_deadline: Option<Instant>,
) -> Result<(), SendTimeoutError<T>> {
let token = &mut Token::default();
assert!(self.start_send(token));
unsafe { self.write(token, msg).map_err(SendTimeoutError::Disconnected) }
}
/// Attempts to receive a message without blocking.
pub(crate) fn try_recv(&self) -> Result<T, TryRecvError> {
let token = &mut Token::default();
if self.start_recv(token) {
unsafe { self.read(token).map_err(|_| TryRecvError::Disconnected) }
} else {
Err(TryRecvError::Empty)
}
}
/// Receives a message from the channel.
pub(crate) fn recv(&self, deadline: Option<Instant>) -> Result<T, RecvTimeoutError> {
let token = &mut Token::default();
loop {
if self.start_recv(token) {
unsafe {
return self.read(token).map_err(|_| RecvTimeoutError::Disconnected);
}
}
if let Some(d) = deadline {
if Instant::now() >= d {
return Err(RecvTimeoutError::Timeout);
}
}
// Prepare for blocking until a sender wakes us up.
Context::with(|cx| {
let oper = Operation::hook(token);
self.receivers.register(oper, cx);
// Has the channel become ready just now?
if !self.is_empty() || self.is_disconnected() {
let _ = cx.try_select(Selected::Aborted);
}
// Block the current thread.
// SAFETY: the context belongs to the current thread.
let sel = unsafe { cx.wait_until(deadline) };
match sel {
Selected::Waiting => unreachable!(),
Selected::Aborted | Selected::Disconnected => {
self.receivers.unregister(oper).unwrap();
// If the channel was disconnected, we still have to check for remaining
// messages.
}
Selected::Operation(_) => {}
}
});
}
}
/// Returns the current number of messages inside the channel.
pub(crate) fn len(&self) -> usize {
loop {
// Load the tail index, then load the head index.
let mut tail = self.tail.index.load(Ordering::SeqCst);
let mut head = self.head.index.load(Ordering::SeqCst);
// If the tail index didn't change, we've got consistent indices to work with.
if self.tail.index.load(Ordering::SeqCst) == tail {
// Erase the lower bits.
tail &= !((1 << SHIFT) - 1);
head &= !((1 << SHIFT) - 1);
// Fix up indices if they fall onto block ends.
if (tail >> SHIFT) & (LAP - 1) == LAP - 1 {
tail = tail.wrapping_add(1 << SHIFT);
}
if (head >> SHIFT) & (LAP - 1) == LAP - 1 {
head = head.wrapping_add(1 << SHIFT);
}
// Rotate indices so that head falls into the first block.
let lap = (head >> SHIFT) / LAP;
tail = tail.wrapping_sub((lap * LAP) << SHIFT);
head = head.wrapping_sub((lap * LAP) << SHIFT);
// Remove the lower bits.
tail >>= SHIFT;
head >>= SHIFT;
// Return the difference minus the number of blocks between tail and head.
return tail - head - tail / LAP;
}
}
}
/// Returns the capacity of the channel.
pub(crate) fn capacity(&self) -> Option<usize> {
None
}
/// Disconnects senders and wakes up all blocked receivers.
///
/// Returns `true` if this call disconnected the channel.
pub(crate) fn disconnect_senders(&self) -> bool {
let tail = self.tail.index.fetch_or(MARK_BIT, Ordering::SeqCst);
if tail & MARK_BIT == 0 {
self.receivers.disconnect();
true
} else {
false
}
}
/// Disconnects receivers.
///
/// Returns `true` if this call disconnected the channel.
pub(crate) fn disconnect_receivers(&self) -> bool {
let tail = self.tail.index.fetch_or(MARK_BIT, Ordering::SeqCst);
if tail & MARK_BIT == 0 {
// If receivers are dropped first, discard all messages to free
// memory eagerly.
self.discard_all_messages();
true
} else {
false
}
}
/// Discards all messages.
///
/// This method should only be called when all receivers are dropped.
fn discard_all_messages(&self) {
let backoff = Backoff::new();
let mut tail = self.tail.index.load(Ordering::Acquire);
loop {
let offset = (tail >> SHIFT) % LAP;
if offset != BLOCK_CAP {
break;
}
// New updates to tail will be rejected by MARK_BIT and aborted unless it's
// at boundary. We need to wait for the updates take affect otherwise there
// can be memory leaks.
backoff.spin_heavy();
tail = self.tail.index.load(Ordering::Acquire);
}
let mut head = self.head.index.load(Ordering::Acquire);
// The channel may be uninitialized, so we have to swap to avoid overwriting any sender's attempts
// to initialize the first block before noticing that the receivers disconnected. Late allocations
// will be deallocated by the sender in Drop.
let mut block = self.head.block.swap(ptr::null_mut(), Ordering::AcqRel);
// If we're going to be dropping messages we need to synchronize with initialization
if head >> SHIFT != tail >> SHIFT {
// The block can be null here only if a sender is in the process of initializing the
// channel while another sender managed to send a message by inserting it into the
// semi-initialized channel and advanced the tail.
// In that case, just wait until it gets initialized.
while block.is_null() {
backoff.spin_heavy();
block = self.head.block.swap(ptr::null_mut(), Ordering::AcqRel);
}
}
// After this point `head.block` is not modified again and it will be deallocated if it's
// non-null. The `Drop` code of the channel, which runs after this function, also attempts
// to deallocate `head.block` if it's non-null. Therefore this function must maintain the
// invariant that if a deallocation of head.block is attempted then it must also be set to
// NULL. Failing to do so will lead to the Drop code attempting a double free. For this
// reason both reads above do an atomic swap instead of a simple atomic load.
unsafe {
// Drop all messages between head and tail and deallocate the heap-allocated blocks.
while head >> SHIFT != tail >> SHIFT {
let offset = (head >> SHIFT) % LAP;
if offset < BLOCK_CAP {
// Drop the message in the slot.
let slot = (*block).slots.get_unchecked(offset);
slot.wait_write();
let p = &mut *slot.msg.get();
p.as_mut_ptr().drop_in_place();
} else {
(*block).wait_next();
// Deallocate the block and move to the next one.
let next = (*block).next.load(Ordering::Acquire);
drop(Box::from_raw(block));
block = next;
}
head = head.wrapping_add(1 << SHIFT);
}
// Deallocate the last remaining block.
if !block.is_null() {
drop(Box::from_raw(block));
}
}
head &= !MARK_BIT;
self.head.index.store(head, Ordering::Release);
}
/// Returns `true` if the channel is disconnected.
pub(crate) fn is_disconnected(&self) -> bool {
self.tail.index.load(Ordering::SeqCst) & MARK_BIT != 0
}
/// Returns `true` if the channel is empty.
pub(crate) fn is_empty(&self) -> bool {
let head = self.head.index.load(Ordering::SeqCst);
let tail = self.tail.index.load(Ordering::SeqCst);
head >> SHIFT == tail >> SHIFT
}
/// Returns `true` if the channel is full.
pub(crate) fn is_full(&self) -> bool {
false
}
}
impl<T> Drop for Channel<T> {
fn drop(&mut self) {
let mut head = self.head.index.load(Ordering::Relaxed);
let mut tail = self.tail.index.load(Ordering::Relaxed);
let mut block = self.head.block.load(Ordering::Relaxed);
// Erase the lower bits.
head &= !((1 << SHIFT) - 1);
tail &= !((1 << SHIFT) - 1);
unsafe {
// Drop all messages between head and tail and deallocate the heap-allocated blocks.
while head != tail {
let offset = (head >> SHIFT) % LAP;
if offset < BLOCK_CAP {
// Drop the message in the slot.
let slot = (*block).slots.get_unchecked(offset);
let p = &mut *slot.msg.get();
p.as_mut_ptr().drop_in_place();
} else {
// Deallocate the block and move to the next one.
let next = (*block).next.load(Ordering::Relaxed);
drop(Box::from_raw(block));
block = next;
}
head = head.wrapping_add(1 << SHIFT);
}
// Deallocate the last remaining block.
if !block.is_null() {
drop(Box::from_raw(block));
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,71 @@
/// Temporary data that gets initialized during a blocking operation, and is consumed by
/// `read` or `write`.
///
/// Each field contains data associated with a specific channel flavor.
#[derive(Debug, Default)]
pub struct Token {
pub(crate) array: super::array::ArrayToken,
pub(crate) list: super::list::ListToken,
#[allow(dead_code)]
pub(crate) zero: super::zero::ZeroToken,
}
/// Identifier associated with an operation by a specific thread on a specific channel.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Operation(usize);
impl Operation {
/// Creates an operation identifier from a mutable reference.
///
/// This function essentially just turns the address of the reference into a number. The
/// reference should point to a variable that is specific to the thread and the operation,
/// and is alive for the entire duration of a blocking operation.
#[inline]
pub fn hook<T>(r: &mut T) -> Operation {
let val = r as *mut T as usize;
// Make sure that the pointer address doesn't equal the numerical representation of
// `Selected::{Waiting, Aborted, Disconnected}`.
assert!(val > 2);
Operation(val)
}
}
/// Current state of a blocking operation.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Selected {
/// Still waiting for an operation.
Waiting,
/// The attempt to block the current thread has been aborted.
Aborted,
/// An operation became ready because a channel is disconnected.
Disconnected,
/// An operation became ready because a message can be sent or received.
Operation(Operation),
}
impl From<usize> for Selected {
#[inline]
fn from(val: usize) -> Selected {
match val {
0 => Selected::Waiting,
1 => Selected::Aborted,
2 => Selected::Disconnected,
oper => Selected::Operation(Operation(oper)),
}
}
}
impl Into<usize> for Selected {
#[inline]
fn into(self) -> usize {
match self {
Selected::Waiting => 0,
Selected::Aborted => 1,
Selected::Disconnected => 2,
Selected::Operation(Operation(val)) => val,
}
}
}

View File

@@ -0,0 +1,14 @@
// Ensure that thread_local init with `const { 0 }` still has unique address at run-time
#[test]
fn waker_current_thread_id() {
let first = super::waker::current_thread_id();
let t = crate::thread::spawn(move || {
let second = super::waker::current_thread_id();
assert_ne!(first, second);
assert_eq!(second, super::waker::current_thread_id());
});
assert_eq!(first, super::waker::current_thread_id());
t.join().unwrap();
assert_eq!(first, super::waker::current_thread_id());
}

View File

@@ -0,0 +1,137 @@
use crate::cell::Cell;
use crate::ops::{Deref, DerefMut};
/// Pads and aligns a value to the length of a cache line.
#[derive(Clone, Copy, Default, Hash, PartialEq, Eq)]
// Starting from Intel's Sandy Bridge, spatial prefetcher is now pulling pairs of 64-byte cache
// lines at a time, so we have to align to 128 bytes rather than 64.
//
// Sources:
// - https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf
// - https://github.com/facebook/folly/blob/1b5288e6eea6df074758f877c849b6e73bbb9fbb/folly/lang/Align.h#L107
//
// ARM's big.LITTLE architecture has asymmetric cores and "big" cores have 128-byte cache line size.
//
// Sources:
// - https://www.mono-project.com/news/2016/09/12/arm64-icache/
//
// powerpc64 has 128-byte cache line size.
//
// Sources:
// - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_ppc64x.go#L9
#[cfg_attr(
any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "powerpc64",),
repr(align(128))
)]
// arm, mips and mips64 have 32-byte cache line size.
//
// Sources:
// - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_arm.go#L7
// - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_mips.go#L7
// - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_mipsle.go#L7
// - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_mips64x.go#L9
#[cfg_attr(
any(
target_arch = "arm",
target_arch = "mips",
target_arch = "mips32r6",
target_arch = "mips64",
target_arch = "mips64r6",
),
repr(align(32))
)]
// s390x has 256-byte cache line size.
//
// Sources:
// - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_s390x.go#L7
#[cfg_attr(target_arch = "s390x", repr(align(256)))]
// x86, wasm and riscv have 64-byte cache line size.
//
// Sources:
// - https://github.com/golang/go/blob/dda2991c2ea0c5914714469c4defc2562a907230/src/internal/cpu/cpu_x86.go#L9
// - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_wasm.go#L7
// - https://github.com/golang/go/blob/5e31f78c8a4ed1b872ddc194f0cd1ae931b37d7e/src/internal/cpu/cpu_riscv64.go#L7
//
// All others are assumed to have 64-byte cache line size.
#[cfg_attr(
not(any(
target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "powerpc64",
target_arch = "arm",
target_arch = "mips",
target_arch = "mips32r6",
target_arch = "mips64",
target_arch = "mips64r6",
target_arch = "s390x",
)),
repr(align(64))
)]
pub struct CachePadded<T> {
value: T,
}
impl<T> CachePadded<T> {
/// Pads and aligns a value to the length of a cache line.
pub fn new(value: T) -> CachePadded<T> {
CachePadded::<T> { value }
}
}
impl<T> Deref for CachePadded<T> {
type Target = T;
fn deref(&self) -> &T {
&self.value
}
}
impl<T> DerefMut for CachePadded<T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.value
}
}
const SPIN_LIMIT: u32 = 6;
/// Performs quadratic backoff in spin loops.
pub struct Backoff {
step: Cell<u32>,
}
impl Backoff {
/// Creates a new `Backoff`.
pub fn new() -> Self {
Backoff { step: Cell::new(0) }
}
/// Backs off using lightweight spinning.
///
/// This method should be used for retrying an operation because another thread made
/// progress. i.e. on CAS failure.
#[inline]
pub fn spin_light(&self) {
let step = self.step.get().min(SPIN_LIMIT);
for _ in 0..step.pow(2) {
crate::hint::spin_loop();
}
self.step.set(self.step.get() + 1);
}
/// Backs off using heavyweight spinning.
///
/// This method should be used in blocking loops where parking the thread is not an option.
#[inline]
pub fn spin_heavy(&self) {
if self.step.get() <= SPIN_LIMIT {
for _ in 0..self.step.get().pow(2) {
crate::hint::spin_loop()
}
} else {
crate::thread::yield_now();
}
self.step.set(self.step.get() + 1);
}
}

View File

@@ -0,0 +1,209 @@
//! Waking mechanism for threads blocked on channel operations.
use super::context::Context;
use super::select::{Operation, Selected};
use crate::ptr;
use crate::sync::Mutex;
use crate::sync::atomic::{Atomic, AtomicBool, Ordering};
/// Represents a thread blocked on a specific channel operation.
pub(crate) struct Entry {
/// The operation.
pub(crate) oper: Operation,
/// Optional packet.
pub(crate) packet: *mut (),
/// Context associated with the thread owning this operation.
pub(crate) cx: Context,
}
/// A queue of threads blocked on channel operations.
///
/// This data structure is used by threads to register blocking operations and get woken up once
/// an operation becomes ready.
pub(crate) struct Waker {
/// A list of select operations.
selectors: Vec<Entry>,
/// A list of operations waiting to be ready.
observers: Vec<Entry>,
}
impl Waker {
/// Creates a new `Waker`.
#[inline]
pub(crate) fn new() -> Self {
Waker { selectors: Vec::new(), observers: Vec::new() }
}
/// Registers a select operation.
#[inline]
pub(crate) fn register(&mut self, oper: Operation, cx: &Context) {
self.register_with_packet(oper, ptr::null_mut(), cx);
}
/// Registers a select operation and a packet.
#[inline]
pub(crate) fn register_with_packet(&mut self, oper: Operation, packet: *mut (), cx: &Context) {
self.selectors.push(Entry { oper, packet, cx: cx.clone() });
}
/// Unregisters a select operation.
#[inline]
pub(crate) fn unregister(&mut self, oper: Operation) -> Option<Entry> {
if let Some((i, _)) =
self.selectors.iter().enumerate().find(|&(_, entry)| entry.oper == oper)
{
let entry = self.selectors.remove(i);
Some(entry)
} else {
None
}
}
/// Attempts to find another thread's entry, select the operation, and wake it up.
#[inline]
pub(crate) fn try_select(&mut self) -> Option<Entry> {
if self.selectors.is_empty() {
None
} else {
let thread_id = current_thread_id();
self.selectors
.iter()
.position(|selector| {
// Does the entry belong to a different thread?
selector.cx.thread_id() != thread_id
&& selector // Try selecting this operation.
.cx
.try_select(Selected::Operation(selector.oper))
.is_ok()
&& {
// Provide the packet.
selector.cx.store_packet(selector.packet);
// Wake the thread up.
selector.cx.unpark();
true
}
})
// Remove the entry from the queue to keep it clean and improve
// performance.
.map(|pos| self.selectors.remove(pos))
}
}
/// Notifies all operations waiting to be ready.
#[inline]
pub(crate) fn notify(&mut self) {
for entry in self.observers.drain(..) {
if entry.cx.try_select(Selected::Operation(entry.oper)).is_ok() {
entry.cx.unpark();
}
}
}
/// Notifies all registered operations that the channel is disconnected.
#[inline]
pub(crate) fn disconnect(&mut self) {
for entry in self.selectors.iter() {
if entry.cx.try_select(Selected::Disconnected).is_ok() {
// Wake the thread up.
//
// Here we don't remove the entry from the queue. Registered threads must
// unregister from the waker by themselves. They might also want to recover the
// packet value and destroy it, if necessary.
entry.cx.unpark();
}
}
self.notify();
}
}
impl Drop for Waker {
#[inline]
fn drop(&mut self) {
debug_assert_eq!(self.selectors.len(), 0);
debug_assert_eq!(self.observers.len(), 0);
}
}
/// A waker that can be shared among threads without locking.
///
/// This is a simple wrapper around `Waker` that internally uses a mutex for synchronization.
pub(crate) struct SyncWaker {
/// The inner `Waker`.
inner: Mutex<Waker>,
/// `true` if the waker is empty.
is_empty: Atomic<bool>,
}
impl SyncWaker {
/// Creates a new `SyncWaker`.
#[inline]
pub(crate) fn new() -> Self {
SyncWaker { inner: Mutex::new(Waker::new()), is_empty: AtomicBool::new(true) }
}
/// Registers the current thread with an operation.
#[inline]
pub(crate) fn register(&self, oper: Operation, cx: &Context) {
let mut inner = self.inner.lock().unwrap();
inner.register(oper, cx);
self.is_empty
.store(inner.selectors.is_empty() && inner.observers.is_empty(), Ordering::SeqCst);
}
/// Unregisters an operation previously registered by the current thread.
#[inline]
pub(crate) fn unregister(&self, oper: Operation) -> Option<Entry> {
let mut inner = self.inner.lock().unwrap();
let entry = inner.unregister(oper);
self.is_empty
.store(inner.selectors.is_empty() && inner.observers.is_empty(), Ordering::SeqCst);
entry
}
/// Attempts to find one thread (not the current one), select its operation, and wake it up.
#[inline]
pub(crate) fn notify(&self) {
if !self.is_empty.load(Ordering::SeqCst) {
let mut inner = self.inner.lock().unwrap();
if !self.is_empty.load(Ordering::SeqCst) {
inner.try_select();
inner.notify();
self.is_empty.store(
inner.selectors.is_empty() && inner.observers.is_empty(),
Ordering::SeqCst,
);
}
}
}
/// Notifies all threads that the channel is disconnected.
#[inline]
pub(crate) fn disconnect(&self) {
let mut inner = self.inner.lock().unwrap();
inner.disconnect();
self.is_empty
.store(inner.selectors.is_empty() && inner.observers.is_empty(), Ordering::SeqCst);
}
}
impl Drop for SyncWaker {
#[inline]
fn drop(&mut self) {
debug_assert!(self.is_empty.load(Ordering::SeqCst));
}
}
/// Returns a unique id for the current thread.
#[inline]
pub fn current_thread_id() -> usize {
// `u8` is not drop so this variable will be available during thread destruction,
// whereas `thread::current()` would not be
thread_local! { static DUMMY: u8 = const { 0 } }
DUMMY.with(|x| (x as *const u8).addr())
}

View File

@@ -0,0 +1,319 @@
//! Zero-capacity channel.
//!
//! This kind of channel is also known as *rendezvous* channel.
use super::context::Context;
use super::error::*;
use super::select::{Operation, Selected, Token};
use super::utils::Backoff;
use super::waker::Waker;
use crate::cell::UnsafeCell;
use crate::marker::PhantomData;
use crate::sync::Mutex;
use crate::sync::atomic::{Atomic, AtomicBool, Ordering};
use crate::time::Instant;
use crate::{fmt, ptr};
/// A pointer to a packet.
pub(crate) struct ZeroToken(*mut ());
impl Default for ZeroToken {
fn default() -> Self {
Self(ptr::null_mut())
}
}
impl fmt::Debug for ZeroToken {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&(self.0 as usize), f)
}
}
/// A slot for passing one message from a sender to a receiver.
struct Packet<T> {
/// Equals `true` if the packet is allocated on the stack.
on_stack: bool,
/// Equals `true` once the packet is ready for reading or writing.
ready: Atomic<bool>,
/// The message.
msg: UnsafeCell<Option<T>>,
}
impl<T> Packet<T> {
/// Creates an empty packet on the stack.
fn empty_on_stack() -> Packet<T> {
Packet { on_stack: true, ready: AtomicBool::new(false), msg: UnsafeCell::new(None) }
}
/// Creates a packet on the stack, containing a message.
fn message_on_stack(msg: T) -> Packet<T> {
Packet { on_stack: true, ready: AtomicBool::new(false), msg: UnsafeCell::new(Some(msg)) }
}
/// Waits until the packet becomes ready for reading or writing.
fn wait_ready(&self) {
let backoff = Backoff::new();
while !self.ready.load(Ordering::Acquire) {
backoff.spin_heavy();
}
}
}
/// Inner representation of a zero-capacity channel.
struct Inner {
/// Senders waiting to pair up with a receive operation.
senders: Waker,
/// Receivers waiting to pair up with a send operation.
receivers: Waker,
/// Equals `true` when the channel is disconnected.
is_disconnected: bool,
}
/// Zero-capacity channel.
pub(crate) struct Channel<T> {
/// Inner representation of the channel.
inner: Mutex<Inner>,
/// Indicates that dropping a `Channel<T>` may drop values of type `T`.
_marker: PhantomData<T>,
}
impl<T> Channel<T> {
/// Constructs a new zero-capacity channel.
pub(crate) fn new() -> Self {
Channel {
inner: Mutex::new(Inner {
senders: Waker::new(),
receivers: Waker::new(),
is_disconnected: false,
}),
_marker: PhantomData,
}
}
/// Writes a message into the packet.
pub(crate) unsafe fn write(&self, token: &mut Token, msg: T) -> Result<(), T> {
// If there is no packet, the channel is disconnected.
if token.zero.0.is_null() {
return Err(msg);
}
unsafe {
let packet = &*(token.zero.0 as *const Packet<T>);
packet.msg.get().write(Some(msg));
packet.ready.store(true, Ordering::Release);
}
Ok(())
}
/// Reads a message from the packet.
pub(crate) unsafe fn read(&self, token: &mut Token) -> Result<T, ()> {
// If there is no packet, the channel is disconnected.
if token.zero.0.is_null() {
return Err(());
}
let packet = unsafe { &*(token.zero.0 as *const Packet<T>) };
if packet.on_stack {
// The message has been in the packet from the beginning, so there is no need to wait
// for it. However, after reading the message, we need to set `ready` to `true` in
// order to signal that the packet can be destroyed.
let msg = unsafe { packet.msg.get().replace(None) }.unwrap();
packet.ready.store(true, Ordering::Release);
Ok(msg)
} else {
// Wait until the message becomes available, then read it and destroy the
// heap-allocated packet.
packet.wait_ready();
unsafe {
let msg = packet.msg.get().replace(None).unwrap();
drop(Box::from_raw(token.zero.0 as *mut Packet<T>));
Ok(msg)
}
}
}
/// Attempts to send a message into the channel.
pub(crate) fn try_send(&self, msg: T) -> Result<(), TrySendError<T>> {
let token = &mut Token::default();
let mut inner = self.inner.lock().unwrap();
// If there's a waiting receiver, pair up with it.
if let Some(operation) = inner.receivers.try_select() {
token.zero.0 = operation.packet;
drop(inner);
unsafe {
self.write(token, msg).ok().unwrap();
}
Ok(())
} else if inner.is_disconnected {
Err(TrySendError::Disconnected(msg))
} else {
Err(TrySendError::Full(msg))
}
}
/// Sends a message into the channel.
pub(crate) fn send(
&self,
msg: T,
deadline: Option<Instant>,
) -> Result<(), SendTimeoutError<T>> {
let token = &mut Token::default();
let mut inner = self.inner.lock().unwrap();
// If there's a waiting receiver, pair up with it.
if let Some(operation) = inner.receivers.try_select() {
token.zero.0 = operation.packet;
drop(inner);
unsafe {
self.write(token, msg).ok().unwrap();
}
return Ok(());
}
if inner.is_disconnected {
return Err(SendTimeoutError::Disconnected(msg));
}
Context::with(|cx| {
// Prepare for blocking until a receiver wakes us up.
let oper = Operation::hook(token);
let mut packet = Packet::<T>::message_on_stack(msg);
inner.senders.register_with_packet(oper, (&raw mut packet) as *mut (), cx);
inner.receivers.notify();
drop(inner);
// Block the current thread.
// SAFETY: the context belongs to the current thread.
let sel = unsafe { cx.wait_until(deadline) };
match sel {
Selected::Waiting => unreachable!(),
Selected::Aborted => {
self.inner.lock().unwrap().senders.unregister(oper).unwrap();
let msg = unsafe { packet.msg.get().replace(None).unwrap() };
Err(SendTimeoutError::Timeout(msg))
}
Selected::Disconnected => {
self.inner.lock().unwrap().senders.unregister(oper).unwrap();
let msg = unsafe { packet.msg.get().replace(None).unwrap() };
Err(SendTimeoutError::Disconnected(msg))
}
Selected::Operation(_) => {
// Wait until the message is read, then drop the packet.
packet.wait_ready();
Ok(())
}
}
})
}
/// Attempts to receive a message without blocking.
pub(crate) fn try_recv(&self) -> Result<T, TryRecvError> {
let token = &mut Token::default();
let mut inner = self.inner.lock().unwrap();
// If there's a waiting sender, pair up with it.
if let Some(operation) = inner.senders.try_select() {
token.zero.0 = operation.packet;
drop(inner);
unsafe { self.read(token).map_err(|_| TryRecvError::Disconnected) }
} else if inner.is_disconnected {
Err(TryRecvError::Disconnected)
} else {
Err(TryRecvError::Empty)
}
}
/// Receives a message from the channel.
pub(crate) fn recv(&self, deadline: Option<Instant>) -> Result<T, RecvTimeoutError> {
let token = &mut Token::default();
let mut inner = self.inner.lock().unwrap();
// If there's a waiting sender, pair up with it.
if let Some(operation) = inner.senders.try_select() {
token.zero.0 = operation.packet;
drop(inner);
unsafe {
return self.read(token).map_err(|_| RecvTimeoutError::Disconnected);
}
}
if inner.is_disconnected {
return Err(RecvTimeoutError::Disconnected);
}
Context::with(|cx| {
// Prepare for blocking until a sender wakes us up.
let oper = Operation::hook(token);
let mut packet = Packet::<T>::empty_on_stack();
inner.receivers.register_with_packet(oper, (&raw mut packet) as *mut (), cx);
inner.senders.notify();
drop(inner);
// Block the current thread.
// SAFETY: the context belongs to the current thread.
let sel = unsafe { cx.wait_until(deadline) };
match sel {
Selected::Waiting => unreachable!(),
Selected::Aborted => {
self.inner.lock().unwrap().receivers.unregister(oper).unwrap();
Err(RecvTimeoutError::Timeout)
}
Selected::Disconnected => {
self.inner.lock().unwrap().receivers.unregister(oper).unwrap();
Err(RecvTimeoutError::Disconnected)
}
Selected::Operation(_) => {
// Wait until the message is provided, then read it.
packet.wait_ready();
unsafe { Ok(packet.msg.get().replace(None).unwrap()) }
}
}
})
}
/// Disconnects the channel and wakes up all blocked senders and receivers.
///
/// Returns `true` if this call disconnected the channel.
pub(crate) fn disconnect(&self) -> bool {
let mut inner = self.inner.lock().unwrap();
if !inner.is_disconnected {
inner.is_disconnected = true;
inner.senders.disconnect();
inner.receivers.disconnect();
true
} else {
false
}
}
/// Returns the current number of messages inside the channel.
pub(crate) fn len(&self) -> usize {
0
}
/// Returns the capacity of the channel.
#[allow(clippy::unnecessary_wraps)] // This is intentional.
pub(crate) fn capacity(&self) -> Option<usize> {
Some(0)
}
/// Returns `true` if the channel is empty.
pub(crate) fn is_empty(&self) -> bool {
true
}
/// Returns `true` if the channel is full.
pub(crate) fn is_full(&self) -> bool {
true
}
}

1214
crates/std/src/sync/mpsc.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,45 @@
//! Non-poisoning synchronous locks.
//!
//! The difference from the locks in the [`poison`] module is that the locks in this module will not
//! become poisoned when a thread panics while holding a guard.
//!
//! [`poison`]: super::poison
use crate::fmt;
/// A type alias for the result of a nonblocking locking method.
#[unstable(feature = "sync_nonpoison", issue = "134645")]
pub type TryLockResult<Guard> = Result<Guard, WouldBlock>;
/// A lock could not be acquired at this time because the operation would otherwise block.
#[unstable(feature = "sync_nonpoison", issue = "134645")]
pub struct WouldBlock;
#[unstable(feature = "sync_nonpoison", issue = "134645")]
impl fmt::Debug for WouldBlock {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
"WouldBlock".fmt(f)
}
}
#[unstable(feature = "sync_nonpoison", issue = "134645")]
impl fmt::Display for WouldBlock {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
"try_lock failed because the operation would block".fmt(f)
}
}
#[unstable(feature = "nonpoison_condvar", issue = "134645")]
pub use self::condvar::Condvar;
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
pub use self::mutex::MappedMutexGuard;
#[unstable(feature = "nonpoison_mutex", issue = "134645")]
pub use self::mutex::{Mutex, MutexGuard};
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
pub use self::rwlock::{MappedRwLockReadGuard, MappedRwLockWriteGuard};
#[unstable(feature = "nonpoison_rwlock", issue = "134645")]
pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard};
mod condvar;
mod mutex;
mod rwlock;

View File

@@ -0,0 +1,444 @@
use crate::fmt;
use crate::ops::DerefMut;
use crate::sync::WaitTimeoutResult;
use crate::sync::nonpoison::{MutexGuard, mutex};
use crate::sys::sync as sys;
use crate::time::{Duration, Instant};
/// A Condition Variable
///
/// For more information about condition variables, check out the documentation for the poisoning
/// variant of this type at [`poison::Condvar`].
///
/// # Examples
///
/// Note that this `Condvar` does **not** propagate information about threads that panic while
/// holding a lock. If you need this functionality, see [`poison::Mutex`] and [`poison::Condvar`].
///
/// ```
/// #![feature(nonpoison_mutex)]
/// #![feature(nonpoison_condvar)]
///
/// use std::sync::nonpoison::{Mutex, Condvar};
/// use std::sync::Arc;
/// use std::thread;
///
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
/// let pair2 = Arc::clone(&pair);
///
/// // Inside of our lock, spawn a new thread, and then wait for it to start.
/// thread::spawn(move || {
/// let (lock, cvar) = &*pair2;
/// let mut started = lock.lock();
/// *started = true;
/// // We notify the condvar that the value has changed.
/// cvar.notify_one();
/// });
///
/// // Wait for the thread to start up.
/// let (lock, cvar) = &*pair;
/// let mut started = lock.lock();
/// while !*started {
/// cvar.wait(&mut started);
/// }
/// ```
///
/// [`poison::Mutex`]: crate::sync::poison::Mutex
/// [`poison::Condvar`]: crate::sync::poison::Condvar
#[unstable(feature = "nonpoison_condvar", issue = "134645")]
pub struct Condvar {
inner: sys::Condvar,
}
impl Condvar {
/// Creates a new condition variable which is ready to be waited on and
/// notified.
///
/// # Examples
///
/// ```
/// use std::sync::Condvar;
///
/// let condvar = Condvar::new();
/// ```
#[unstable(feature = "nonpoison_condvar", issue = "134645")]
#[must_use]
#[inline]
pub const fn new() -> Condvar {
Condvar { inner: sys::Condvar::new() }
}
/// Blocks the current thread until this condition variable receives a
/// notification.
///
/// This function will atomically unlock the mutex specified (represented by
/// `guard`) and block the current thread. This means that any calls
/// to [`notify_one`] or [`notify_all`] which happen logically after the
/// mutex is unlocked are candidates to wake this thread up. When this
/// function call returns, the lock specified will have been re-acquired.
///
/// Note that this function is susceptible to spurious wakeups. Condition
/// variables normally have a boolean predicate associated with them, and
/// the predicate must always be checked each time this function returns to
/// protect against spurious wakeups.
///
/// # Panics
///
/// This function may [`panic!`] if it is used with more than one mutex
/// over time.
///
/// [`notify_one`]: Self::notify_one
/// [`notify_all`]: Self::notify_all
///
/// # Examples
///
/// ```
/// #![feature(nonpoison_mutex)]
/// #![feature(nonpoison_condvar)]
///
/// use std::sync::nonpoison::{Mutex, Condvar};
/// use std::sync::Arc;
/// use std::thread;
///
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
/// let pair2 = Arc::clone(&pair);
///
/// thread::spawn(move || {
/// let (lock, cvar) = &*pair2;
/// let mut started = lock.lock();
/// *started = true;
/// // We notify the condvar that the value has changed.
/// cvar.notify_one();
/// });
///
/// // Wait for the thread to start up.
/// let (lock, cvar) = &*pair;
/// let mut started = lock.lock();
/// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
/// while !*started {
/// cvar.wait(&mut started);
/// }
/// ```
#[unstable(feature = "nonpoison_condvar", issue = "134645")]
pub fn wait<T>(&self, guard: &mut MutexGuard<'_, T>) {
unsafe {
let lock = mutex::guard_lock(guard);
self.inner.wait(lock);
}
}
/// Blocks the current thread until the provided condition becomes false.
///
/// `condition` is checked immediately; if not met (returns `true`), this
/// will [`wait`] for the next notification then check again. This repeats
/// until `condition` returns `false`, in which case this function returns.
///
/// This function will atomically unlock the mutex specified (represented by
/// `guard`) and block the current thread. This means that any calls
/// to [`notify_one`] or [`notify_all`] which happen logically after the
/// mutex is unlocked are candidates to wake this thread up. When this
/// function call returns, the lock specified will have been re-acquired.
///
/// [`wait`]: Self::wait
/// [`notify_one`]: Self::notify_one
/// [`notify_all`]: Self::notify_all
///
/// # Examples
///
/// ```
/// #![feature(nonpoison_mutex)]
/// #![feature(nonpoison_condvar)]
///
/// use std::sync::nonpoison::{Mutex, Condvar};
/// use std::sync::Arc;
/// use std::thread;
///
/// let pair = Arc::new((Mutex::new(true), Condvar::new()));
/// let pair2 = Arc::clone(&pair);
///
/// thread::spawn(move || {
/// let (lock, cvar) = &*pair2;
/// let mut pending = lock.lock();
/// *pending = false;
/// // We notify the condvar that the value has changed.
/// cvar.notify_one();
/// });
///
/// // Wait for the thread to start up.
/// let (lock, cvar) = &*pair;
/// // As long as the value inside the `Mutex<bool>` is `true`, we wait.
/// let mut guard = lock.lock();
/// cvar.wait_while(&mut guard, |pending| { *pending });
/// ```
#[unstable(feature = "nonpoison_condvar", issue = "134645")]
pub fn wait_while<T, F>(&self, guard: &mut MutexGuard<'_, T>, mut condition: F)
where
F: FnMut(&mut T) -> bool,
{
while condition(guard.deref_mut()) {
self.wait(guard);
}
}
/// Waits on this condition variable for a notification, timing out after a
/// specified duration.
///
/// The semantics of this function are equivalent to [`wait`] except that
/// the thread will be blocked for roughly no longer than `dur`. This
/// method should not be used for precise timing due to anomalies such as
/// preemption or platform differences that might not cause the maximum
/// amount of time waited to be precisely `dur`.
///
/// Note that the best effort is made to ensure that the time waited is
/// measured with a monotonic clock, and not affected by the changes made to
/// the system time. This function is susceptible to spurious wakeups.
/// Condition variables normally have a boolean predicate associated with
/// them, and the predicate must always be checked each time this function
/// returns to protect against spurious wakeups. Furthermore, since the timeout
/// is given relative to the moment this function is called, it needs to be adjusted
/// when this function is called in a loop. The [`wait_timeout_while`] method
/// lets you wait with a timeout while a predicate is true, taking care of all these concerns.
///
/// The returned [`WaitTimeoutResult`] value indicates if the timeout is
/// known to have elapsed.
///
/// Like [`wait`], the lock specified will have been re-acquired when this function
/// returns, regardless of whether the timeout elapsed or not.
///
/// [`wait`]: Self::wait
/// [`wait_timeout_while`]: Self::wait_timeout_while
///
/// # Examples
///
/// ```
/// #![feature(nonpoison_mutex)]
/// #![feature(nonpoison_condvar)]
///
/// use std::sync::nonpoison::{Mutex, Condvar};
/// use std::sync::Arc;
/// use std::thread;
/// use std::time::Duration;
///
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
/// let pair2 = Arc::clone(&pair);
///
/// thread::spawn(move || {
/// let (lock, cvar) = &*pair2;
/// let mut started = lock.lock();
/// *started = true;
/// // We notify the condvar that the value has changed.
/// cvar.notify_one();
/// });
///
/// // wait for the thread to start up
/// let (lock, cvar) = &*pair;
/// let mut started = lock.lock();
/// // as long as the value inside the `Mutex<bool>` is `false`, we wait
/// loop {
/// let result = cvar.wait_timeout(&mut started, Duration::from_millis(10));
/// // 10 milliseconds have passed, or maybe the value changed!
/// if *started == true {
/// // We received the notification and the value has been updated, we can leave.
/// break
/// }
/// }
/// ```
#[unstable(feature = "nonpoison_condvar", issue = "134645")]
pub fn wait_timeout<T>(
&self,
guard: &mut MutexGuard<'_, T>,
dur: Duration,
) -> WaitTimeoutResult {
let success = unsafe {
let lock = mutex::guard_lock(guard);
self.inner.wait_timeout(lock, dur)
};
WaitTimeoutResult(!success)
}
/// Waits on this condition variable for a notification, timing out after a
/// specified duration.
///
/// The semantics of this function are equivalent to [`wait_while`] except
/// that the thread will be blocked for roughly no longer than `dur`. This
/// method should not be used for precise timing due to anomalies such as
/// preemption or platform differences that might not cause the maximum
/// amount of time waited to be precisely `dur`.
///
/// Note that the best effort is made to ensure that the time waited is
/// measured with a monotonic clock, and not affected by the changes made to
/// the system time.
///
/// The returned [`WaitTimeoutResult`] value indicates if the timeout is
/// known to have elapsed without the condition being met.
///
/// Like [`wait_while`], the lock specified will have been re-acquired when this
/// function returns, regardless of whether the timeout elapsed or not.
///
/// [`wait_while`]: Self::wait_while
/// [`wait_timeout`]: Self::wait_timeout
///
/// # Examples
///
/// ```
/// #![feature(nonpoison_mutex)]
/// #![feature(nonpoison_condvar)]
///
/// use std::sync::nonpoison::{Mutex, Condvar};
/// use std::sync::Arc;
/// use std::thread;
/// use std::time::Duration;
///
/// let pair = Arc::new((Mutex::new(true), Condvar::new()));
/// let pair2 = Arc::clone(&pair);
///
/// thread::spawn(move || {
/// let (lock, cvar) = &*pair2;
/// let mut pending = lock.lock();
/// *pending = false;
/// // We notify the condvar that the value has changed.
/// cvar.notify_one();
/// });
///
/// // wait for the thread to start up
/// let (lock, cvar) = &*pair;
/// let mut guard = lock.lock();
/// let result = cvar.wait_timeout_while(
/// &mut guard,
/// Duration::from_millis(100),
/// |&mut pending| pending,
/// );
/// if result.timed_out() {
/// // timed-out without the condition ever evaluating to false.
/// }
/// // access the locked mutex via guard
/// ```
#[unstable(feature = "nonpoison_condvar", issue = "134645")]
pub fn wait_timeout_while<T, F>(
&self,
guard: &mut MutexGuard<'_, T>,
dur: Duration,
mut condition: F,
) -> WaitTimeoutResult
where
F: FnMut(&mut T) -> bool,
{
let start = Instant::now();
while condition(guard.deref_mut()) {
let timeout = match dur.checked_sub(start.elapsed()) {
Some(timeout) => timeout,
None => return WaitTimeoutResult(true),
};
self.wait_timeout(guard, timeout);
}
WaitTimeoutResult(false)
}
/// Wakes up one blocked thread on this condvar.
///
/// If there is a blocked thread on this condition variable, then it will
/// be woken up from its call to [`wait`] or [`wait_timeout`]. Calls to
/// `notify_one` are not buffered in any way.
///
/// To wake up all threads, see [`notify_all`].
///
/// [`wait`]: Self::wait
/// [`wait_timeout`]: Self::wait_timeout
/// [`notify_all`]: Self::notify_all
///
/// # Examples
///
/// ```
/// #![feature(nonpoison_mutex)]
/// #![feature(nonpoison_condvar)]
///
/// use std::sync::nonpoison::{Mutex, Condvar};
/// use std::sync::Arc;
/// use std::thread;
///
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
/// let pair2 = Arc::clone(&pair);
///
/// thread::spawn(move || {
/// let (lock, cvar) = &*pair2;
/// let mut started = lock.lock();
/// *started = true;
/// // We notify the condvar that the value has changed.
/// cvar.notify_one();
/// });
///
/// // Wait for the thread to start up.
/// let (lock, cvar) = &*pair;
/// let mut started = lock.lock();
/// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
/// while !*started {
/// cvar.wait(&mut started);
/// }
/// ```
#[unstable(feature = "nonpoison_condvar", issue = "134645")]
pub fn notify_one(&self) {
self.inner.notify_one()
}
/// Wakes up all blocked threads on this condvar.
///
/// This method will ensure that any current waiters on the condition
/// variable are awoken. Calls to `notify_all()` are not buffered in any
/// way.
///
/// To wake up only one thread, see [`notify_one`].
///
/// [`notify_one`]: Self::notify_one
///
/// # Examples
///
/// ```
/// #![feature(nonpoison_mutex)]
/// #![feature(nonpoison_condvar)]
///
/// use std::sync::nonpoison::{Mutex, Condvar};
/// use std::sync::Arc;
/// use std::thread;
///
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
/// let pair2 = Arc::clone(&pair);
///
/// thread::spawn(move || {
/// let (lock, cvar) = &*pair2;
/// let mut started = lock.lock();
/// *started = true;
/// // We notify the condvar that the value has changed.
/// cvar.notify_all();
/// });
///
/// // Wait for the thread to start up.
/// let (lock, cvar) = &*pair;
/// let mut started = lock.lock();
/// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
/// while !*started {
/// cvar.wait(&mut started);
/// }
/// ```
#[unstable(feature = "nonpoison_condvar", issue = "134645")]
pub fn notify_all(&self) {
self.inner.notify_all()
}
}
#[unstable(feature = "nonpoison_condvar", issue = "134645")]
impl fmt::Debug for Condvar {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Condvar").finish_non_exhaustive()
}
}
#[unstable(feature = "nonpoison_condvar", issue = "134645")]
impl Default for Condvar {
/// Creates a `Condvar` which is ready to be waited on and notified.
fn default() -> Condvar {
Condvar::new()
}
}

View File

@@ -0,0 +1,649 @@
use crate::cell::UnsafeCell;
use crate::fmt;
use crate::marker::PhantomData;
use crate::mem::{self, ManuallyDrop};
use crate::ops::{Deref, DerefMut};
use crate::ptr::NonNull;
use crate::sync::nonpoison::{TryLockResult, WouldBlock};
use crate::sys::sync as sys;
/// A mutual exclusion primitive useful for protecting shared data that does not keep track of
/// lock poisoning.
///
/// For more information about mutexes, check out the documentation for the poisoning variant of
/// this lock at [`poison::Mutex`].
///
/// [`poison::Mutex`]: crate::sync::poison::Mutex
///
/// # Examples
///
/// Note that this `Mutex` does **not** propagate threads that panic while holding the lock via
/// poisoning. If you need this functionality, see [`poison::Mutex`].
///
/// ```
/// #![feature(nonpoison_mutex)]
///
/// use std::thread;
/// use std::sync::{Arc, nonpoison::Mutex};
///
/// let mutex = Arc::new(Mutex::new(0u32));
/// let mut handles = Vec::new();
///
/// for n in 0..10 {
/// let m = Arc::clone(&mutex);
/// let handle = thread::spawn(move || {
/// let mut guard = m.lock();
/// *guard += 1;
/// panic!("panic from thread {n} {guard}")
/// });
/// handles.push(handle);
/// }
///
/// for h in handles {
/// let _ = h.join();
/// }
///
/// println!("Finished, locked {} times", mutex.lock());
/// ```
#[unstable(feature = "nonpoison_mutex", issue = "134645")]
#[cfg_attr(not(test), rustc_diagnostic_item = "NonPoisonMutex")]
pub struct Mutex<T: ?Sized> {
inner: sys::Mutex,
data: UnsafeCell<T>,
}
/// `T` must be `Send` for a [`Mutex`] to be `Send` because it is possible to acquire
/// the owned `T` from the `Mutex` via [`into_inner`].
///
/// [`into_inner`]: Mutex::into_inner
#[unstable(feature = "nonpoison_mutex", issue = "134645")]
unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}
/// `T` must be `Send` for [`Mutex`] to be `Sync`.
/// This ensures that the protected data can be accessed safely from multiple threads
/// without causing data races or other unsafe behavior.
///
/// [`Mutex<T>`] provides mutable access to `T` to one thread at a time. However, it's essential
/// for `T` to be `Send` because it's not safe for non-`Send` structures to be accessed in
/// this manner. For instance, consider [`Rc`], a non-atomic reference counted smart pointer,
/// which is not `Send`. With `Rc`, we can have multiple copies pointing to the same heap
/// allocation with a non-atomic reference count. If we were to use `Mutex<Rc<_>>`, it would
/// only protect one instance of `Rc` from shared access, leaving other copies vulnerable
/// to potential data races.
///
/// Also note that it is not necessary for `T` to be `Sync` as `&T` is only made available
/// to one thread at a time if `T` is not `Sync`.
///
/// [`Rc`]: crate::rc::Rc
#[unstable(feature = "nonpoison_mutex", issue = "134645")]
unsafe impl<T: ?Sized + Send> Sync for Mutex<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.
///
/// The data protected by the mutex can be accessed through this guard via its
/// [`Deref`] and [`DerefMut`] implementations.
///
/// This structure is created by the [`lock`] and [`try_lock`] methods on
/// [`Mutex`].
///
/// [`lock`]: Mutex::lock
/// [`try_lock`]: Mutex::try_lock
#[must_use = "if unused the Mutex will immediately unlock"]
#[must_not_suspend = "holding a MutexGuard across suspend \
points can cause deadlocks, delays, \
and cause Futures to not implement `Send`"]
#[unstable(feature = "nonpoison_mutex", issue = "134645")]
#[clippy::has_significant_drop]
#[cfg_attr(not(test), rustc_diagnostic_item = "NonPoisonMutexGuard")]
pub struct MutexGuard<'a, T: ?Sized + 'a> {
lock: &'a Mutex<T>,
}
/// A [`MutexGuard`] is not `Send` to maximize platform portability.
///
/// On platforms that use POSIX threads (commonly referred to as pthreads) there is a requirement to
/// release mutex locks on the same thread they were acquired.
/// For this reason, [`MutexGuard`] must not implement `Send` to prevent it being dropped from
/// another thread.
#[unstable(feature = "nonpoison_mutex", issue = "134645")]
impl<T: ?Sized> !Send for MutexGuard<'_, T> {}
/// `T` must be `Sync` for a [`MutexGuard<T>`] to be `Sync`
/// because it is possible to get a `&T` from `&MutexGuard` (via `Deref`).
#[unstable(feature = "nonpoison_mutex", issue = "134645")]
unsafe impl<T: ?Sized + Sync> Sync for MutexGuard<'_, T> {}
/// An RAII mutex guard returned by `MutexGuard::map`, which can point to a
/// subfield of the protected data. When this structure is dropped (falls out
/// of scope), the lock will be unlocked.
///
/// The main difference between `MappedMutexGuard` and [`MutexGuard`] is that the
/// former cannot be used with [`Condvar`], since that could introduce soundness issues if the
/// locked object is modified by another thread while the `Mutex` is unlocked.
///
/// The data protected by the mutex can be accessed through this guard via its
/// [`Deref`] and [`DerefMut`] implementations.
///
/// This structure is created by the [`map`] and [`filter_map`] methods on
/// [`MutexGuard`].
///
/// [`map`]: MutexGuard::map
/// [`filter_map`]: MutexGuard::filter_map
/// [`Condvar`]: crate::sync::nonpoison::Condvar
#[must_use = "if unused the Mutex will immediately unlock"]
#[must_not_suspend = "holding a MappedMutexGuard across suspend \
points can cause deadlocks, delays, \
and cause Futures to not implement `Send`"]
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
// #[unstable(feature = "nonpoison_mutex", issue = "134645")]
#[clippy::has_significant_drop]
pub struct MappedMutexGuard<'a, T: ?Sized + 'a> {
// NB: we use a pointer instead of `&'a mut T` to avoid `noalias` violations, because a
// `MappedMutexGuard` argument doesn't hold uniqueness for its whole scope, only until it drops.
// `NonNull` is covariant over `T`, so we add a `PhantomData<&'a mut T>` field
// below for the correct variance over `T` (invariance).
data: NonNull<T>,
inner: &'a sys::Mutex,
_variance: PhantomData<&'a mut T>,
}
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
// #[unstable(feature = "nonpoison_mutex", issue = "134645")]
impl<T: ?Sized> !Send for MappedMutexGuard<'_, T> {}
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
// #[unstable(feature = "nonpoison_mutex", issue = "134645")]
unsafe impl<T: ?Sized + Sync> Sync for MappedMutexGuard<'_, T> {}
impl<T> Mutex<T> {
/// Creates a new mutex in an unlocked state ready for use.
///
/// # Examples
///
/// ```
/// #![feature(nonpoison_mutex)]
///
/// use std::sync::nonpoison::Mutex;
///
/// let mutex = Mutex::new(0);
/// ```
#[unstable(feature = "nonpoison_mutex", issue = "134645")]
#[inline]
pub const fn new(t: T) -> Mutex<T> {
Mutex { inner: sys::Mutex::new(), data: UnsafeCell::new(t) }
}
/// Returns the contained value by cloning it.
///
/// # Examples
///
/// ```
/// #![feature(nonpoison_mutex)]
/// #![feature(lock_value_accessors)]
///
/// use std::sync::nonpoison::Mutex;
///
/// let mut mutex = Mutex::new(7);
///
/// assert_eq!(mutex.get_cloned(), 7);
/// ```
#[unstable(feature = "lock_value_accessors", issue = "133407")]
// #[unstable(feature = "nonpoison_mutex", issue = "134645")]
pub fn get_cloned(&self) -> T
where
T: Clone,
{
self.lock().clone()
}
/// Sets the contained value.
///
/// # Examples
///
/// ```
/// #![feature(nonpoison_mutex)]
/// #![feature(lock_value_accessors)]
///
/// use std::sync::nonpoison::Mutex;
///
/// let mut mutex = Mutex::new(7);
///
/// assert_eq!(mutex.get_cloned(), 7);
/// mutex.set(11);
/// assert_eq!(mutex.get_cloned(), 11);
/// ```
#[unstable(feature = "lock_value_accessors", issue = "133407")]
// #[unstable(feature = "nonpoison_mutex", issue = "134645")]
pub fn set(&self, value: T) {
if mem::needs_drop::<T>() {
// If the contained value has a non-trivial destructor, we
// call that destructor after the lock has been released.
drop(self.replace(value))
} else {
*self.lock() = value;
}
}
/// Replaces the contained value with `value`, and returns the old contained value.
///
/// # Examples
///
/// ```
/// #![feature(nonpoison_mutex)]
/// #![feature(lock_value_accessors)]
///
/// use std::sync::nonpoison::Mutex;
///
/// let mut mutex = Mutex::new(7);
///
/// assert_eq!(mutex.replace(11), 7);
/// assert_eq!(mutex.get_cloned(), 11);
/// ```
#[unstable(feature = "lock_value_accessors", issue = "133407")]
// #[unstable(feature = "nonpoison_mutex", issue = "134645")]
pub fn replace(&self, value: T) -> T {
let mut guard = self.lock();
mem::replace(&mut *guard, value)
}
}
impl<T: ?Sized> Mutex<T> {
/// Acquires a mutex, blocking the current thread until it is able to do so.
///
/// This function will block the local thread until it is available to acquire
/// the mutex. Upon returning, the thread is the only thread with the lock
/// held. An RAII guard is returned to allow scoped unlock of the lock. When
/// the guard goes out of scope, the mutex will be unlocked.
///
/// The exact behavior on locking a mutex in the thread which already holds
/// the lock is left unspecified. However, this function will not return on
/// the second call (it might panic or deadlock, for example).
///
/// # Panics
///
/// This function might panic when called if the lock is already held by
/// the current thread.
///
/// # Examples
///
/// ```
/// #![feature(nonpoison_mutex)]
///
/// use std::sync::{Arc, nonpoison::Mutex};
/// use std::thread;
///
/// let mutex = Arc::new(Mutex::new(0));
/// let c_mutex = Arc::clone(&mutex);
///
/// thread::spawn(move || {
/// *c_mutex.lock() = 10;
/// }).join().expect("thread::spawn failed");
/// assert_eq!(*mutex.lock(), 10);
/// ```
#[unstable(feature = "nonpoison_mutex", issue = "134645")]
pub fn lock(&self) -> MutexGuard<'_, T> {
unsafe {
self.inner.lock();
MutexGuard::new(self)
}
}
/// Attempts to acquire this lock.
///
/// This function does not block. If the lock could not be acquired at this time, then
/// [`WouldBlock`] is returned. Otherwise, an RAII guard is returned.
///
/// The lock will be unlocked when the guard is dropped.
///
/// # Errors
///
/// If the mutex could not be acquired because it is already locked, then this call will return
/// the [`WouldBlock`] error.
///
/// # Examples
///
/// ```
/// use std::sync::{Arc, Mutex};
/// use std::thread;
///
/// let mutex = Arc::new(Mutex::new(0));
/// let c_mutex = Arc::clone(&mutex);
///
/// thread::spawn(move || {
/// let mut lock = c_mutex.try_lock();
/// if let Ok(ref mut mutex) = lock {
/// **mutex = 10;
/// } else {
/// println!("try_lock failed");
/// }
/// }).join().expect("thread::spawn failed");
/// assert_eq!(*mutex.lock().unwrap(), 10);
/// ```
#[unstable(feature = "nonpoison_mutex", issue = "134645")]
pub fn try_lock(&self) -> TryLockResult<MutexGuard<'_, T>> {
unsafe { if self.inner.try_lock() { Ok(MutexGuard::new(self)) } else { Err(WouldBlock) } }
}
/// Consumes this mutex, returning the underlying data.
///
/// # Examples
///
/// ```
/// #![feature(nonpoison_mutex)]
///
/// use std::sync::nonpoison::Mutex;
///
/// let mutex = Mutex::new(0);
/// assert_eq!(mutex.into_inner(), 0);
/// ```
#[unstable(feature = "nonpoison_mutex", issue = "134645")]
pub fn into_inner(self) -> T
where
T: Sized,
{
self.data.into_inner()
}
/// Returns a mutable reference to the underlying data.
///
/// Since this call borrows the `Mutex` mutably, no actual locking needs to
/// take place -- the mutable borrow statically guarantees no locks exist.
///
/// # Examples
///
/// ```
/// #![feature(nonpoison_mutex)]
///
/// use std::sync::nonpoison::Mutex;
///
/// let mut mutex = Mutex::new(0);
/// *mutex.get_mut() = 10;
/// assert_eq!(*mutex.lock(), 10);
/// ```
#[unstable(feature = "nonpoison_mutex", issue = "134645")]
pub fn get_mut(&mut self) -> &mut T {
self.data.get_mut()
}
/// Returns a raw pointer to the underlying data.
///
/// The returned pointer is always non-null and properly aligned, but it is
/// the user's responsibility to ensure that any reads and writes through it
/// are properly synchronized to avoid data races, and that it is not read
/// or written through after the mutex is dropped.
#[unstable(feature = "mutex_data_ptr", issue = "140368")]
// #[unstable(feature = "nonpoison_mutex", issue = "134645")]
pub const fn data_ptr(&self) -> *mut T {
self.data.get()
}
/// Acquires the mutex and provides mutable access to the underlying data by passing
/// a mutable reference to the given closure.
///
/// This method acquires the lock, calls the provided closure with a mutable reference
/// to the data, and returns the result of the closure. The lock is released after
/// the closure completes, even if it panics.
///
/// # Examples
///
/// ```
/// #![feature(lock_value_accessors, nonpoison_mutex)]
///
/// use std::sync::nonpoison::Mutex;
///
/// let mutex = Mutex::new(2);
///
/// let result = mutex.with_mut(|data| {
/// *data += 3;
///
/// *data + 5
/// });
///
/// assert_eq!(*mutex.lock(), 5);
/// assert_eq!(result, 10);
/// ```
#[unstable(feature = "lock_value_accessors", issue = "133407")]
// #[unstable(feature = "nonpoison_mutex", issue = "134645")]
pub fn with_mut<F, R>(&self, f: F) -> R
where
F: FnOnce(&mut T) -> R,
{
f(&mut self.lock())
}
}
#[unstable(feature = "nonpoison_mutex", issue = "134645")]
impl<T> From<T> for Mutex<T> {
/// Creates a new mutex in an unlocked state ready for use.
/// This is equivalent to [`Mutex::new`].
fn from(t: T) -> Self {
Mutex::new(t)
}
}
#[unstable(feature = "nonpoison_mutex", issue = "134645")]
impl<T: Default> Default for Mutex<T> {
/// Creates a `Mutex<T>`, with the `Default` value for T.
fn default() -> Mutex<T> {
Mutex::new(Default::default())
}
}
#[unstable(feature = "nonpoison_mutex", issue = "134645")]
impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut d = f.debug_struct("Mutex");
match self.try_lock() {
Ok(guard) => {
d.field("data", &&*guard);
}
Err(WouldBlock) => {
d.field("data", &"<locked>");
}
}
d.finish_non_exhaustive()
}
}
impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> {
unsafe fn new(lock: &'mutex Mutex<T>) -> MutexGuard<'mutex, T> {
return MutexGuard { lock };
}
}
#[unstable(feature = "nonpoison_mutex", issue = "134645")]
impl<T: ?Sized> Deref for MutexGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.lock.data.get() }
}
}
#[unstable(feature = "nonpoison_mutex", issue = "134645")]
impl<T: ?Sized> DerefMut for MutexGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.lock.data.get() }
}
}
#[unstable(feature = "nonpoison_mutex", issue = "134645")]
impl<T: ?Sized> Drop for MutexGuard<'_, T> {
#[inline]
fn drop(&mut self) {
unsafe {
self.lock.inner.unlock();
}
}
}
#[unstable(feature = "nonpoison_mutex", issue = "134645")]
impl<T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
#[unstable(feature = "nonpoison_mutex", issue = "134645")]
impl<T: ?Sized + fmt::Display> fmt::Display for MutexGuard<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}
/// For use in [`nonpoison::condvar`](super::condvar).
pub(super) fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex {
&guard.lock.inner
}
impl<'a, T: ?Sized> MutexGuard<'a, T> {
/// Makes a [`MappedMutexGuard`] for a component of the borrowed data, e.g.
/// an enum variant.
///
/// The `Mutex` is already locked, so this cannot fail.
///
/// This is an associated function that needs to be used as
/// `MutexGuard::map(...)`. A method would interfere with methods of the
/// same name on the contents of the `MutexGuard` used through `Deref`.
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
// #[unstable(feature = "nonpoison_mutex", issue = "134645")]
pub fn map<U, F>(orig: Self, f: F) -> MappedMutexGuard<'a, U>
where
F: FnOnce(&mut T) -> &mut U,
U: ?Sized,
{
// SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard
// was created, and have been upheld throughout `map` and/or `filter_map`.
// The signature of the closure guarantees that it will not "leak" the lifetime of the reference
// passed to it. If the closure panics, the guard will be dropped.
let data = NonNull::from(f(unsafe { &mut *orig.lock.data.get() }));
let orig = ManuallyDrop::new(orig);
MappedMutexGuard { data, inner: &orig.lock.inner, _variance: PhantomData }
}
/// Makes a [`MappedMutexGuard`] for a component of the borrowed data. The
/// original guard is returned as an `Err(...)` if the closure returns
/// `None`.
///
/// The `Mutex` is already locked, so this cannot fail.
///
/// This is an associated function that needs to be used as
/// `MutexGuard::filter_map(...)`. A method would interfere with methods of the
/// same name on the contents of the `MutexGuard` used through `Deref`.
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
// #[unstable(feature = "nonpoison_mutex", issue = "134645")]
pub fn filter_map<U, F>(orig: Self, f: F) -> Result<MappedMutexGuard<'a, U>, Self>
where
F: FnOnce(&mut T) -> Option<&mut U>,
U: ?Sized,
{
// SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard
// was created, and have been upheld throughout `map` and/or `filter_map`.
// The signature of the closure guarantees that it will not "leak" the lifetime of the reference
// passed to it. If the closure panics, the guard will be dropped.
match f(unsafe { &mut *orig.lock.data.get() }) {
Some(data) => {
let data = NonNull::from(data);
let orig = ManuallyDrop::new(orig);
Ok(MappedMutexGuard { data, inner: &orig.lock.inner, _variance: PhantomData })
}
None => Err(orig),
}
}
}
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
impl<T: ?Sized> Deref for MappedMutexGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { self.data.as_ref() }
}
}
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
impl<T: ?Sized> DerefMut for MappedMutexGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { self.data.as_mut() }
}
}
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
impl<T: ?Sized> Drop for MappedMutexGuard<'_, T> {
#[inline]
fn drop(&mut self) {
unsafe {
self.inner.unlock();
}
}
}
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
impl<T: ?Sized + fmt::Debug> fmt::Debug for MappedMutexGuard<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
impl<T: ?Sized + fmt::Display> fmt::Display for MappedMutexGuard<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}
impl<'a, T: ?Sized> MappedMutexGuard<'a, T> {
/// Makes a [`MappedMutexGuard`] for a component of the borrowed data, e.g.
/// an enum variant.
///
/// The `Mutex` is already locked, so this cannot fail.
///
/// This is an associated function that needs to be used as
/// `MappedMutexGuard::map(...)`. A method would interfere with methods of the
/// same name on the contents of the `MutexGuard` used through `Deref`.
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
// #[unstable(feature = "nonpoison_mutex", issue = "134645")]
pub fn map<U, F>(mut orig: Self, f: F) -> MappedMutexGuard<'a, U>
where
F: FnOnce(&mut T) -> &mut U,
U: ?Sized,
{
// SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard
// was created, and have been upheld throughout `map` and/or `filter_map`.
// The signature of the closure guarantees that it will not "leak" the lifetime of the reference
// passed to it. If the closure panics, the guard will be dropped.
let data = NonNull::from(f(unsafe { orig.data.as_mut() }));
let orig = ManuallyDrop::new(orig);
MappedMutexGuard { data, inner: orig.inner, _variance: PhantomData }
}
/// Makes a [`MappedMutexGuard`] for a component of the borrowed data. The
/// original guard is returned as an `Err(...)` if the closure returns
/// `None`.
///
/// The `Mutex` is already locked, so this cannot fail.
///
/// This is an associated function that needs to be used as
/// `MappedMutexGuard::filter_map(...)`. A method would interfere with methods of the
/// same name on the contents of the `MutexGuard` used through `Deref`.
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
// #[unstable(feature = "nonpoison_mutex", issue = "134645")]
pub fn filter_map<U, F>(mut orig: Self, f: F) -> Result<MappedMutexGuard<'a, U>, Self>
where
F: FnOnce(&mut T) -> Option<&mut U>,
U: ?Sized,
{
// SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard
// was created, and have been upheld throughout `map` and/or `filter_map`.
// The signature of the closure guarantees that it will not "leak" the lifetime of the reference
// passed to it. If the closure panics, the guard will be dropped.
match f(unsafe { orig.data.as_mut() }) {
Some(data) => {
let data = NonNull::from(data);
let orig = ManuallyDrop::new(orig);
Ok(MappedMutexGuard { data, inner: orig.inner, _variance: PhantomData })
}
None => Err(orig),
}
}
}

File diff suppressed because it is too large Load Diff

395
crates/std/src/sync/once.rs Normal file
View File

@@ -0,0 +1,395 @@
//! A "once initialization" primitive
//!
//! This primitive is meant to be used to run one-time initialization. An
//! example use case would be for initializing an FFI library.
use crate::fmt;
use core::panic::{RefUnwindSafe, UnwindSafe};
use crate::sys::sync as sys;
/// A low-level synchronization primitive for one-time global execution.
///
/// Previously this was the only "execute once" synchronization in `std`.
/// Other libraries implemented novel synchronizing types with `Once`, like
/// [`OnceLock<T>`] or [`LazyLock<T, F>`], before those were added to `std`.
/// `OnceLock<T>` in particular supersedes `Once` in functionality and should
/// be preferred for the common case where the `Once` is associated with data.
///
/// This type can only be constructed with [`Once::new()`].
///
/// # Examples
///
/// ```
/// use std::sync::Once;
///
/// static START: Once = Once::new();
///
/// START.call_once(|| {
/// // run initialization here
/// });
/// ```
///
/// [`OnceLock<T>`]: crate::sync::OnceLock
/// [`LazyLock<T, F>`]: crate::sync::LazyLock
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Once {
inner: sys::Once,
}
#[stable(feature = "sync_once_unwind_safe", since = "1.59.0")]
impl UnwindSafe for Once {}
#[stable(feature = "sync_once_unwind_safe", since = "1.59.0")]
impl RefUnwindSafe for Once {}
/// State yielded to [`Once::call_once_force()`]s closure parameter. The state
/// can be used to query the poison status of the [`Once`].
#[stable(feature = "once_poison", since = "1.51.0")]
pub struct OnceState {
pub(crate) inner: sys::OnceState,
}
/// Used for the internal implementation of `sys::sync::once` on different platforms and the
/// [`LazyLock`](crate::sync::LazyLock) implementation.
pub(crate) enum OnceExclusiveState {
Incomplete,
Poisoned,
Complete,
}
/// Initialization value for static [`Once`] values.
///
/// # Examples
///
/// ```
/// use std::sync::{Once, ONCE_INIT};
///
/// static START: Once = ONCE_INIT;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[deprecated(
since = "1.38.0",
note = "the `Once::new()` function is now preferred",
suggestion = "Once::new()"
)]
pub const ONCE_INIT: Once = Once::new();
impl Once {
/// Creates a new `Once` value.
#[inline]
#[stable(feature = "once_new", since = "1.2.0")]
#[rustc_const_stable(feature = "const_once_new", since = "1.32.0")]
#[must_use]
pub const fn new() -> Once {
Once { inner: sys::Once::new() }
}
/// Performs an initialization routine once and only once. The given closure
/// will be executed if this is the first time `call_once` has been called,
/// and otherwise the routine will *not* be invoked.
///
/// This method will block the calling thread if another initialization
/// routine is currently running.
///
/// When this function returns, it is guaranteed that some initialization
/// has run and completed (it might not be the closure specified). It is also
/// guaranteed that any memory writes performed by the executed closure can
/// be reliably observed by other threads at this point (there is a
/// happens-before relation between the closure and code executing after the
/// return).
///
/// If the given closure recursively invokes `call_once` on the same [`Once`]
/// instance, the exact behavior is not specified: allowed outcomes are
/// a panic or a deadlock.
///
/// # Examples
///
/// ```
/// use std::sync::Once;
///
/// static mut VAL: usize = 0;
/// static INIT: Once = Once::new();
///
/// // Accessing a `static mut` is unsafe much of the time, but if we do so
/// // in a synchronized fashion (e.g., write once or read all) then we're
/// // good to go!
/// //
/// // This function will only call `expensive_computation` once, and will
/// // otherwise always return the value returned from the first invocation.
/// fn get_cached_val() -> usize {
/// unsafe {
/// INIT.call_once(|| {
/// VAL = expensive_computation();
/// });
/// VAL
/// }
/// }
///
/// fn expensive_computation() -> usize {
/// // ...
/// # 2
/// }
/// ```
///
/// # Panics
///
/// The closure `f` will only be executed once even if this is called
/// concurrently amongst many threads. If that closure panics, however, then
/// it will *poison* this [`Once`] instance, causing all future invocations of
/// `call_once` to also panic.
///
/// This is similar to [poisoning with mutexes][poison], but this mechanism
/// is guaranteed to never skip panics within `f`.
///
/// [poison]: struct.Mutex.html#poisoning
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[track_caller]
#[rustc_should_not_be_called_on_const_items]
pub fn call_once<F>(&self, f: F)
where
F: FnOnce(),
{
// Fast path check
if self.inner.is_completed() {
return;
}
let mut f = Some(f);
self.inner.call(false, &mut |_| f.take().unwrap()());
}
/// Performs the same function as [`call_once()`] except ignores poisoning.
///
/// Unlike [`call_once()`], if this [`Once`] has been poisoned (i.e., a previous
/// call to [`call_once()`] or [`call_once_force()`] caused a panic), calling
/// [`call_once_force()`] will still invoke the closure `f` and will _not_
/// result in an immediate panic. If `f` panics, the [`Once`] will remain
/// in a poison state. If `f` does _not_ panic, the [`Once`] will no
/// longer be in a poison state and all future calls to [`call_once()`] or
/// [`call_once_force()`] will be no-ops.
///
/// The closure `f` is yielded a [`OnceState`] structure which can be used
/// to query the poison status of the [`Once`].
///
/// [`call_once()`]: Once::call_once
/// [`call_once_force()`]: Once::call_once_force
///
/// # Examples
///
/// ```
/// use std::sync::Once;
/// use std::thread;
///
/// static INIT: Once = Once::new();
///
/// // poison the once
/// let handle = thread::spawn(|| {
/// INIT.call_once(|| panic!());
/// });
/// assert!(handle.join().is_err());
///
/// // poisoning propagates
/// let handle = thread::spawn(|| {
/// INIT.call_once(|| {});
/// });
/// assert!(handle.join().is_err());
///
/// // call_once_force will still run and reset the poisoned state
/// INIT.call_once_force(|state| {
/// assert!(state.is_poisoned());
/// });
///
/// // once any success happens, we stop propagating the poison
/// INIT.call_once(|| {});
/// ```
#[inline]
#[stable(feature = "once_poison", since = "1.51.0")]
#[rustc_should_not_be_called_on_const_items]
pub fn call_once_force<F>(&self, f: F)
where
F: FnOnce(&OnceState),
{
// Fast path check
if self.inner.is_completed() {
return;
}
let mut f = Some(f);
self.inner.call(true, &mut |p| f.take().unwrap()(p));
}
/// Returns `true` if some [`call_once()`] call has completed
/// successfully. Specifically, `is_completed` will return false in
/// the following situations:
/// * [`call_once()`] was not called at all,
/// * [`call_once()`] was called, but has not yet completed,
/// * the [`Once`] instance is poisoned
///
/// This function returning `false` does not mean that [`Once`] has not been
/// executed. For example, it may have been executed in the time between
/// when `is_completed` starts executing and when it returns, in which case
/// the `false` return value would be stale (but still permissible).
///
/// [`call_once()`]: Once::call_once
///
/// # Examples
///
/// ```
/// use std::sync::Once;
///
/// static INIT: Once = Once::new();
///
/// assert_eq!(INIT.is_completed(), false);
/// INIT.call_once(|| {
/// assert_eq!(INIT.is_completed(), false);
/// });
/// assert_eq!(INIT.is_completed(), true);
/// ```
///
/// ```
/// use std::sync::Once;
/// use std::thread;
///
/// static INIT: Once = Once::new();
///
/// assert_eq!(INIT.is_completed(), false);
/// let handle = thread::spawn(|| {
/// INIT.call_once(|| panic!());
/// });
/// assert!(handle.join().is_err());
/// assert_eq!(INIT.is_completed(), false);
/// ```
#[stable(feature = "once_is_completed", since = "1.43.0")]
#[inline]
pub fn is_completed(&self) -> bool {
self.inner.is_completed()
}
/// Blocks the current thread until initialization has completed.
///
/// # Example
///
/// ```rust
/// use std::sync::Once;
/// use std::thread;
///
/// static READY: Once = Once::new();
///
/// let thread = thread::spawn(|| {
/// READY.wait();
/// println!("everything is ready");
/// });
///
/// READY.call_once(|| println!("performing setup"));
/// ```
///
/// # Panics
///
/// If this [`Once`] has been poisoned because an initialization closure has
/// panicked, this method will also panic. Use [`wait_force`](Self::wait_force)
/// if this behavior is not desired.
#[stable(feature = "once_wait", since = "1.86.0")]
#[rustc_should_not_be_called_on_const_items]
pub fn wait(&self) {
if !self.inner.is_completed() {
self.inner.wait(false);
}
}
/// Blocks the current thread until initialization has completed, ignoring
/// poisoning.
///
/// If this [`Once`] has been poisoned, this function blocks until it
/// becomes completed, unlike [`Once::wait()`], which panics in this case.
#[stable(feature = "once_wait", since = "1.86.0")]
#[rustc_should_not_be_called_on_const_items]
pub fn wait_force(&self) {
if !self.inner.is_completed() {
self.inner.wait(true);
}
}
/// Returns the current state of the `Once` instance.
///
/// Since this takes a mutable reference, no initialization can currently
/// be running, so the state must be either "incomplete", "poisoned" or
/// "complete".
#[inline]
pub(crate) fn state(&mut self) -> OnceExclusiveState {
self.inner.state()
}
/// Sets current state of the `Once` instance.
///
/// Since this takes a mutable reference, no initialization can currently
/// be running, so the state must be either "incomplete", "poisoned" or
/// "complete".
#[inline]
pub(crate) fn set_state(&mut self, new_state: OnceExclusiveState) {
self.inner.set_state(new_state);
}
}
#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Once {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Once").finish_non_exhaustive()
}
}
impl OnceState {
/// Returns `true` if the associated [`Once`] was poisoned prior to the
/// invocation of the closure passed to [`Once::call_once_force()`].
///
/// # Examples
///
/// A poisoned [`Once`]:
///
/// ```
/// use std::sync::Once;
/// use std::thread;
///
/// static INIT: Once = Once::new();
///
/// // poison the once
/// let handle = thread::spawn(|| {
/// INIT.call_once(|| panic!());
/// });
/// assert!(handle.join().is_err());
///
/// INIT.call_once_force(|state| {
/// assert!(state.is_poisoned());
/// });
/// ```
///
/// An unpoisoned [`Once`]:
///
/// ```
/// use std::sync::Once;
///
/// static INIT: Once = Once::new();
///
/// INIT.call_once_force(|state| {
/// assert!(!state.is_poisoned());
/// });
#[stable(feature = "once_poison", since = "1.51.0")]
#[inline]
pub fn is_poisoned(&self) -> bool {
self.inner.is_poisoned()
}
/// Poison the associated [`Once`] without explicitly panicking.
// NOTE: This is currently only exposed for `OnceLock`.
#[inline]
pub(crate) fn poison(&self) {
self.inner.poison();
}
}
#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for OnceState {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OnceState").field("poisoned", &self.is_poisoned()).finish()
}
}

View File

@@ -0,0 +1,709 @@
use super::once::OnceExclusiveState;
use crate::cell::UnsafeCell;
use crate::fmt;
use crate::marker::PhantomData;
use crate::mem::MaybeUninit;
use core::panic::{RefUnwindSafe, UnwindSafe};
use crate::sync::Once;
/// A synchronization primitive which can nominally be written to only once.
///
/// This type is a thread-safe [`OnceCell`], and can be used in statics.
/// In many simple cases, you can use [`LazyLock<T, F>`] instead to get the benefits of this type
/// with less effort: `LazyLock<T, F>` "looks like" `&T` because it initializes with `F` on deref!
/// Where OnceLock shines is when LazyLock is too simple to support a given case, as LazyLock
/// doesn't allow additional inputs to its function after you call [`LazyLock::new(|| ...)`].
///
/// A `OnceLock` can be thought of as a safe abstraction over uninitialized data that becomes
/// initialized once written.
///
/// Unlike [`Mutex`](crate::sync::Mutex), `OnceLock` is never poisoned on panic.
///
/// [`OnceCell`]: crate::cell::OnceCell
/// [`LazyLock<T, F>`]: crate::sync::LazyLock
/// [`LazyLock::new(|| ...)`]: crate::sync::LazyLock::new
///
/// # Examples
///
/// Writing to a `OnceLock` from a separate thread:
///
/// ```
/// use std::sync::OnceLock;
///
/// static CELL: OnceLock<usize> = OnceLock::new();
///
/// // `OnceLock` has not been written to yet.
/// assert!(CELL.get().is_none());
///
/// // Spawn a thread and write to `OnceLock`.
/// std::thread::spawn(|| {
/// let value = CELL.get_or_init(|| 12345);
/// assert_eq!(value, &12345);
/// })
/// .join()
/// .unwrap();
///
/// // `OnceLock` now contains the value.
/// assert_eq!(
/// CELL.get(),
/// Some(&12345),
/// );
/// ```
///
/// You can use `OnceLock` to implement a type that requires "append-only" logic:
///
/// ```
/// use std::sync::{OnceLock, atomic::{AtomicU32, Ordering}};
/// use std::thread;
///
/// struct OnceList<T> {
/// data: OnceLock<T>,
/// next: OnceLock<Box<OnceList<T>>>,
/// }
/// impl<T> OnceList<T> {
/// const fn new() -> OnceList<T> {
/// OnceList { data: OnceLock::new(), next: OnceLock::new() }
/// }
/// fn push(&self, value: T) {
/// // FIXME: this impl is concise, but is also slow for long lists or many threads.
/// // as an exercise, consider how you might improve on it while preserving the behavior
/// if let Err(value) = self.data.set(value) {
/// let next = self.next.get_or_init(|| Box::new(OnceList::new()));
/// next.push(value)
/// };
/// }
/// fn contains(&self, example: &T) -> bool
/// where
/// T: PartialEq,
/// {
/// self.data.get().map(|item| item == example).filter(|v| *v).unwrap_or_else(|| {
/// self.next.get().map(|next| next.contains(example)).unwrap_or(false)
/// })
/// }
/// }
///
/// // Let's exercise this new Sync append-only list by doing a little counting
/// static LIST: OnceList<u32> = OnceList::new();
/// static COUNTER: AtomicU32 = AtomicU32::new(0);
///
/// # const LEN: u32 = if cfg!(miri) { 50 } else { 1000 };
/// # /*
/// const LEN: u32 = 1000;
/// # */
/// thread::scope(|s| {
/// for _ in 0..thread::available_parallelism().unwrap().get() {
/// s.spawn(|| {
/// while let i @ 0..LEN = COUNTER.fetch_add(1, Ordering::Relaxed) {
/// LIST.push(i);
/// }
/// });
/// }
/// });
///
/// for i in 0..LEN {
/// assert!(LIST.contains(&i));
/// }
///
/// ```
#[stable(feature = "once_cell", since = "1.70.0")]
pub struct OnceLock<T> {
// FIXME(nonpoison_once): switch to nonpoison version once it is available
once: Once,
// Whether or not the value is initialized is tracked by `once.is_completed()`.
value: UnsafeCell<MaybeUninit<T>>,
/// `PhantomData` to make sure dropck understands we're dropping T in our Drop impl.
///
/// ```compile_fail,E0597
/// use std::sync::OnceLock;
///
/// struct A<'a>(&'a str);
///
/// impl<'a> Drop for A<'a> {
/// fn drop(&mut self) {}
/// }
///
/// let cell = OnceLock::new();
/// {
/// let s = String::new();
/// let _ = cell.set(A(&s));
/// }
/// ```
_marker: PhantomData<T>,
}
impl<T> OnceLock<T> {
/// Creates a new uninitialized cell.
#[inline]
#[must_use]
#[stable(feature = "once_cell", since = "1.70.0")]
#[rustc_const_stable(feature = "once_cell", since = "1.70.0")]
pub const fn new() -> OnceLock<T> {
OnceLock {
once: Once::new(),
value: UnsafeCell::new(MaybeUninit::uninit()),
_marker: PhantomData,
}
}
/// Gets the reference to the underlying value.
///
/// Returns `None` if the cell is uninitialized, or being initialized.
/// This method never blocks.
#[inline]
#[stable(feature = "once_cell", since = "1.70.0")]
#[rustc_should_not_be_called_on_const_items]
pub fn get(&self) -> Option<&T> {
if self.initialized() {
// Safe b/c checked initialized
Some(unsafe { self.get_unchecked() })
} else {
None
}
}
/// Gets the mutable reference to the underlying value.
///
/// Returns `None` if the cell is uninitialized.
///
/// This method never blocks. Since it borrows the `OnceLock` mutably,
/// it is statically guaranteed that no active borrows to the `OnceLock`
/// exist, including from other threads.
#[inline]
#[stable(feature = "once_cell", since = "1.70.0")]
pub fn get_mut(&mut self) -> Option<&mut T> {
if self.initialized_mut() {
// Safe b/c checked initialized and we have a unique access
Some(unsafe { self.get_unchecked_mut() })
} else {
None
}
}
/// Blocks the current thread until the cell is initialized.
///
/// # Example
///
/// Waiting for a computation on another thread to finish:
/// ```rust
/// use std::thread;
/// use std::sync::OnceLock;
///
/// let value = OnceLock::new();
///
/// thread::scope(|s| {
/// s.spawn(|| value.set(1 + 1));
///
/// let result = value.wait();
/// assert_eq!(result, &2);
/// })
/// ```
#[inline]
#[stable(feature = "once_wait", since = "1.86.0")]
#[rustc_should_not_be_called_on_const_items]
pub fn wait(&self) -> &T {
self.once.wait_force();
unsafe { self.get_unchecked() }
}
/// Initializes the contents of the cell to `value`.
///
/// May block if another thread is currently attempting to initialize the cell. The cell is
/// guaranteed to contain a value when `set` returns, though not necessarily the one provided.
///
/// Returns `Ok(())` if the cell was uninitialized and
/// `Err(value)` if the cell was already initialized.
///
/// # Examples
///
/// ```
/// use std::sync::OnceLock;
///
/// static CELL: OnceLock<i32> = OnceLock::new();
///
/// fn main() {
/// assert!(CELL.get().is_none());
///
/// std::thread::spawn(|| {
/// assert_eq!(CELL.set(92), Ok(()));
/// }).join().unwrap();
///
/// assert_eq!(CELL.set(62), Err(62));
/// assert_eq!(CELL.get(), Some(&92));
/// }
/// ```
#[inline]
#[stable(feature = "once_cell", since = "1.70.0")]
#[rustc_should_not_be_called_on_const_items]
pub fn set(&self, value: T) -> Result<(), T> {
match self.try_insert(value) {
Ok(_) => Ok(()),
Err((_, value)) => Err(value),
}
}
/// Initializes the contents of the cell to `value` if the cell was uninitialized,
/// then returns a reference to it.
///
/// May block if another thread is currently attempting to initialize the cell. The cell is
/// guaranteed to contain a value when `try_insert` returns, though not necessarily the
/// one provided.
///
/// Returns `Ok(&value)` if the cell was uninitialized and
/// `Err((&current_value, value))` if it was already initialized.
///
/// # Examples
///
/// ```
/// #![feature(once_cell_try_insert)]
///
/// use std::sync::OnceLock;
///
/// static CELL: OnceLock<i32> = OnceLock::new();
///
/// fn main() {
/// assert!(CELL.get().is_none());
///
/// std::thread::spawn(|| {
/// assert_eq!(CELL.try_insert(92), Ok(&92));
/// }).join().unwrap();
///
/// assert_eq!(CELL.try_insert(62), Err((&92, 62)));
/// assert_eq!(CELL.get(), Some(&92));
/// }
/// ```
#[inline]
#[unstable(feature = "once_cell_try_insert", issue = "116693")]
#[rustc_should_not_be_called_on_const_items]
pub fn try_insert(&self, value: T) -> Result<&T, (&T, T)> {
let mut value = Some(value);
let res = self.get_or_init(|| value.take().unwrap());
match value {
None => Ok(res),
Some(value) => Err((res, value)),
}
}
/// Gets the contents of the cell, initializing it to `f()` if the cell
/// was uninitialized.
///
/// Many threads may call `get_or_init` concurrently with different
/// initializing functions, but it is guaranteed that only one function
/// will be executed if the function doesn't panic.
///
/// # Panics
///
/// If `f()` panics, the panic is propagated to the caller, and the cell
/// remains uninitialized.
///
/// It is an error to reentrantly initialize the cell from `f`. The
/// exact outcome is unspecified. Current implementation deadlocks, but
/// this may be changed to a panic in the future.
///
/// # Examples
///
/// ```
/// use std::sync::OnceLock;
///
/// let cell = OnceLock::new();
/// let value = cell.get_or_init(|| 92);
/// assert_eq!(value, &92);
/// let value = cell.get_or_init(|| unreachable!());
/// assert_eq!(value, &92);
/// ```
#[inline]
#[stable(feature = "once_cell", since = "1.70.0")]
#[rustc_should_not_be_called_on_const_items]
pub fn get_or_init<F>(&self, f: F) -> &T
where
F: FnOnce() -> T,
{
match self.get_or_try_init(|| Ok::<T, !>(f())) {
Ok(val) => val,
}
}
/// Gets the mutable reference of the contents of the cell, initializing
/// it to `f()` if the cell was uninitialized.
///
/// This method never blocks. Since it borrows the `OnceLock` mutably,
/// it is statically guaranteed that no active borrows to the `OnceLock`
/// exist, including from other threads.
///
/// # Panics
///
/// If `f()` panics, the panic is propagated to the caller, and the cell
/// remains uninitialized.
///
/// # Examples
///
/// ```
/// #![feature(once_cell_get_mut)]
///
/// use std::sync::OnceLock;
///
/// let mut cell = OnceLock::new();
/// let value = cell.get_mut_or_init(|| 92);
/// assert_eq!(*value, 92);
///
/// *value += 2;
/// assert_eq!(*value, 94);
///
/// let value = cell.get_mut_or_init(|| unreachable!());
/// assert_eq!(*value, 94);
/// ```
#[inline]
#[unstable(feature = "once_cell_get_mut", issue = "121641")]
pub fn get_mut_or_init<F>(&mut self, f: F) -> &mut T
where
F: FnOnce() -> T,
{
match self.get_mut_or_try_init(|| Ok::<T, !>(f())) {
Ok(val) => val,
}
}
/// Gets the contents of the cell, initializing it to `f()` if
/// the cell was uninitialized. If the cell was uninitialized
/// and `f()` failed, an error is returned.
///
/// # Panics
///
/// If `f()` panics, the panic is propagated to the caller, and
/// the cell remains uninitialized.
///
/// It is an error to reentrantly initialize the cell from `f`.
/// The exact outcome is unspecified. Current implementation
/// deadlocks, but this may be changed to a panic in the future.
///
/// # Examples
///
/// ```
/// #![feature(once_cell_try)]
///
/// use std::sync::OnceLock;
///
/// let cell = OnceLock::new();
/// assert_eq!(cell.get_or_try_init(|| Err(())), Err(()));
/// assert!(cell.get().is_none());
/// let value = cell.get_or_try_init(|| -> Result<i32, ()> {
/// Ok(92)
/// });
/// assert_eq!(value, Ok(&92));
/// assert_eq!(cell.get(), Some(&92))
/// ```
#[inline]
#[unstable(feature = "once_cell_try", issue = "109737")]
#[rustc_should_not_be_called_on_const_items]
pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
where
F: FnOnce() -> Result<T, E>,
{
// Fast path check
// NOTE: We need to perform an acquire on the state in this method
// in order to correctly synchronize `LazyLock::force`. This is
// currently done by calling `self.get()`, which in turn calls
// `self.initialized()`, which in turn performs the acquire.
if let Some(value) = self.get() {
return Ok(value);
}
self.initialize(f)?;
// SAFETY: The inner value has been initialized
Ok(unsafe { self.get_unchecked() })
}
/// Gets the mutable reference of the contents of the cell, initializing
/// it to `f()` if the cell was uninitialized. If the cell was uninitialized
/// and `f()` failed, an error is returned.
///
/// This method never blocks. Since it borrows the `OnceLock` mutably,
/// it is statically guaranteed that no active borrows to the `OnceLock`
/// exist, including from other threads.
///
/// # Panics
///
/// If `f()` panics, the panic is propagated to the caller, and
/// the cell remains uninitialized.
///
/// # Examples
///
/// ```
/// #![feature(once_cell_get_mut)]
///
/// use std::sync::OnceLock;
///
/// let mut cell: OnceLock<u32> = OnceLock::new();
///
/// // Failed attempts to initialize the cell do not change its contents
/// assert!(cell.get_mut_or_try_init(|| "not a number!".parse()).is_err());
/// assert!(cell.get().is_none());
///
/// let value = cell.get_mut_or_try_init(|| "1234".parse());
/// assert_eq!(value, Ok(&mut 1234));
/// *value.unwrap() += 2;
/// assert_eq!(cell.get(), Some(&1236))
/// ```
#[inline]
#[unstable(feature = "once_cell_get_mut", issue = "121641")]
pub fn get_mut_or_try_init<F, E>(&mut self, f: F) -> Result<&mut T, E>
where
F: FnOnce() -> Result<T, E>,
{
if self.get_mut().is_none() {
self.initialize(f)?;
}
// SAFETY: The inner value has been initialized
Ok(unsafe { self.get_unchecked_mut() })
}
/// Consumes the `OnceLock`, returning the wrapped value. Returns
/// `None` if the cell was uninitialized.
///
/// # Examples
///
/// ```
/// use std::sync::OnceLock;
///
/// let cell: OnceLock<String> = OnceLock::new();
/// assert_eq!(cell.into_inner(), None);
///
/// let cell = OnceLock::new();
/// cell.set("hello".to_string()).unwrap();
/// assert_eq!(cell.into_inner(), Some("hello".to_string()));
/// ```
#[inline]
#[stable(feature = "once_cell", since = "1.70.0")]
pub fn into_inner(mut self) -> Option<T> {
self.take()
}
/// Takes the value out of this `OnceLock`, moving it back to an uninitialized state.
///
/// Has no effect and returns `None` if the `OnceLock` was uninitialized.
///
/// Since this method borrows the `OnceLock` mutably, it is statically guaranteed that
/// no active borrows to the `OnceLock` exist, including from other threads.
///
/// # Examples
///
/// ```
/// use std::sync::OnceLock;
///
/// let mut cell: OnceLock<String> = OnceLock::new();
/// assert_eq!(cell.take(), None);
///
/// let mut cell = OnceLock::new();
/// cell.set("hello".to_string()).unwrap();
/// assert_eq!(cell.take(), Some("hello".to_string()));
/// assert_eq!(cell.get(), None);
/// ```
#[inline]
#[stable(feature = "once_cell", since = "1.70.0")]
pub fn take(&mut self) -> Option<T> {
if self.initialized_mut() {
self.once = Once::new();
// SAFETY: `self.value` is initialized and contains a valid `T`.
// `self.once` is reset, so `initialized()` will be false again
// which prevents the value from being read twice.
unsafe { Some(self.value.get_mut().assume_init_read()) }
} else {
None
}
}
#[inline]
fn initialized(&self) -> bool {
self.once.is_completed()
}
#[inline]
fn initialized_mut(&mut self) -> bool {
// `state()` does not perform an atomic load, so prefer it over `is_complete()`.
let state = self.once.state();
match state {
OnceExclusiveState::Complete => true,
_ => false,
}
}
#[cold]
#[optimize(size)]
fn initialize<F, E>(&self, f: F) -> Result<(), E>
where
F: FnOnce() -> Result<T, E>,
{
let mut res: Result<(), E> = Ok(());
let slot = &self.value;
// Ignore poisoning from other threads
// If another thread panics, then we'll be able to run our closure
self.once.call_once_force(|p| {
match f() {
Ok(value) => {
unsafe { (&mut *slot.get()).write(value) };
}
Err(e) => {
res = Err(e);
// Treat the underlying `Once` as poisoned since we
// failed to initialize our value.
p.poison();
}
}
});
res
}
/// # Safety
///
/// The cell must be initialized
#[inline]
unsafe fn get_unchecked(&self) -> &T {
debug_assert!(self.initialized());
unsafe { (&*self.value.get()).assume_init_ref() }
}
/// # Safety
///
/// The cell must be initialized
#[inline]
unsafe fn get_unchecked_mut(&mut self) -> &mut T {
debug_assert!(self.initialized_mut());
unsafe { self.value.get_mut().assume_init_mut() }
}
}
// Why do we need `T: Send`?
// Thread A creates a `OnceLock` and shares it with
// scoped thread B, which fills the cell, which is
// then destroyed by A. That is, destructor observes
// a sent value.
#[stable(feature = "once_cell", since = "1.70.0")]
unsafe impl<T: Sync + Send> Sync for OnceLock<T> {}
#[stable(feature = "once_cell", since = "1.70.0")]
unsafe impl<T: Send> Send for OnceLock<T> {}
#[stable(feature = "once_cell", since = "1.70.0")]
impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for OnceLock<T> {}
#[stable(feature = "once_cell", since = "1.70.0")]
impl<T: UnwindSafe> UnwindSafe for OnceLock<T> {}
#[stable(feature = "once_cell", since = "1.70.0")]
#[rustc_const_unstable(feature = "const_default", issue = "143894")]
impl<T> const Default for OnceLock<T> {
/// Creates a new uninitialized cell.
///
/// # Example
///
/// ```
/// use std::sync::OnceLock;
///
/// fn main() {
/// assert_eq!(OnceLock::<()>::new(), OnceLock::default());
/// }
/// ```
#[inline]
fn default() -> OnceLock<T> {
OnceLock::new()
}
}
#[stable(feature = "once_cell", since = "1.70.0")]
impl<T: fmt::Debug> fmt::Debug for OnceLock<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut d = f.debug_tuple("OnceLock");
match self.get() {
Some(v) => d.field(v),
None => d.field(&format_args!("<uninit>")),
};
d.finish()
}
}
#[stable(feature = "once_cell", since = "1.70.0")]
impl<T: Clone> Clone for OnceLock<T> {
#[inline]
fn clone(&self) -> OnceLock<T> {
let cell = Self::new();
if let Some(value) = self.get() {
match cell.set(value.clone()) {
Ok(()) => (),
Err(_) => unreachable!(),
}
}
cell
}
}
#[stable(feature = "once_cell", since = "1.70.0")]
impl<T> From<T> for OnceLock<T> {
/// Creates a new cell with its contents set to `value`.
///
/// # Example
///
/// ```
/// use std::sync::OnceLock;
///
/// # fn main() -> Result<(), i32> {
/// let a = OnceLock::from(3);
/// let b = OnceLock::new();
/// b.set(3)?;
/// assert_eq!(a, b);
/// Ok(())
/// # }
/// ```
#[inline]
fn from(value: T) -> Self {
let cell = Self::new();
match cell.set(value) {
Ok(()) => cell,
Err(_) => unreachable!(),
}
}
}
#[stable(feature = "once_cell", since = "1.70.0")]
impl<T: PartialEq> PartialEq for OnceLock<T> {
/// Equality for two `OnceLock`s.
///
/// Two `OnceLock`s are equal if they either both contain values and their
/// values are equal, or if neither contains a value.
///
/// # Examples
///
/// ```
/// use std::sync::OnceLock;
///
/// let five = OnceLock::new();
/// five.set(5).unwrap();
///
/// let also_five = OnceLock::new();
/// also_five.set(5).unwrap();
///
/// assert!(five == also_five);
///
/// assert!(OnceLock::<u32>::new() == OnceLock::<u32>::new());
/// ```
#[inline]
fn eq(&self, other: &OnceLock<T>) -> bool {
self.get() == other.get()
}
}
#[stable(feature = "once_cell", since = "1.70.0")]
impl<T: Eq> Eq for OnceLock<T> {}
#[stable(feature = "once_cell", since = "1.70.0")]
unsafe impl<#[may_dangle] T> Drop for OnceLock<T> {
#[inline]
fn drop(&mut self) {
if self.initialized_mut() {
// SAFETY: The cell is initialized and being dropped, so it can't
// be accessed again. We also don't touch the `T` other than
// dropping it, which validates our usage of #[may_dangle].
unsafe { self.value.get_mut().assume_init_drop() };
}
}
}

View File

@@ -0,0 +1,389 @@
//! Synchronization objects that employ poisoning.
//!
//! # Poisoning
//!
//! All synchronization objects in this module implement a strategy called
//! "poisoning" where a primitive becomes poisoned if it recognizes that some
//! thread has panicked while holding the exclusive access granted by the
//! primitive. This information is then propagated to all other threads
//! to signify that the data protected by this primitive is likely tainted
//! (some invariant is not being upheld).
//!
//! The specifics of how this "poisoned" state affects other threads and whether
//! the panics are recognized reliably or on a best-effort basis depend on the
//! primitive. See [Overview](#overview) below.
//!
//! The synchronization objects in this module have alternative implementations that do not employ
//! poisoning in the [`std::sync::nonpoison`] module.
//!
//! [`std::sync::nonpoison`]: crate::sync::nonpoison
//!
//! # Overview
//!
//! Below is a list of synchronization objects provided by this module
//! with a high-level overview for each object and a description
//! of how it employs "poisoning".
//!
//! - [`Condvar`]: Condition Variable, providing the ability to block
//! a thread while waiting for an event to occur.
//!
//! Condition variables are typically associated with
//! a boolean predicate (a condition) and a mutex.
//! This implementation is associated with [`poison::Mutex`](Mutex),
//! which employs poisoning.
//! For this reason, [`Condvar::wait()`] will return a [`LockResult`],
//! just like [`poison::Mutex::lock()`](Mutex::lock) does.
//!
//! - [`Mutex`]: Mutual Exclusion mechanism, which ensures that at
//! most one thread at a time is able to access some data.
//!
//! Panicking while holding the lock typically poisons the mutex, but it is
//! not guaranteed to detect this condition in all circumstances.
//! [`Mutex::lock()`] returns a [`LockResult`], providing a way to deal with
//! the poisoned state. See [`Mutex`'s documentation](Mutex#poisoning) for more.
//!
//! - [`RwLock`]: Provides a mutual exclusion mechanism which allows
//! multiple readers at the same time, while allowing only one
//! writer at a time. In some cases, this can be more efficient than
//! a mutex.
//!
//! This implementation, like [`Mutex`], usually becomes poisoned on a panic.
//! Note, however, that an `RwLock` may only be poisoned if a panic occurs
//! while it is locked exclusively (write mode). If a panic occurs in any reader,
//! then the lock will not be poisoned.
//!
//! Note that the [`Once`] type also employs poisoning, but since it has non-poisoning `force`
//! methods available on it, there is no separate `nonpoison` and `poison` version.
//!
//! [`Once`]: crate::sync::Once
// If we are not unwinding, `PoisonError` is uninhabited.
#![cfg_attr(not(panic = "unwind"), expect(unreachable_code))]
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::condvar::Condvar;
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
pub use self::mutex::MappedMutexGuard;
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::mutex::{Mutex, MutexGuard};
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
pub use self::rwlock::{MappedRwLockReadGuard, MappedRwLockWriteGuard};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use crate::error::Error;
use crate::fmt;
#[cfg(panic = "unwind")]
use crate::sync::atomic::{Atomic, AtomicBool, Ordering};
#[cfg(panic = "unwind")]
use crate::thread;
mod condvar;
#[stable(feature = "rust1", since = "1.0.0")]
mod mutex;
mod rwlock;
pub(crate) struct Flag {
#[cfg(panic = "unwind")]
failed: Atomic<bool>,
}
// Note that the Ordering uses to access the `failed` field of `Flag` below is
// always `Relaxed`, and that's because this isn't actually protecting any data,
// it's just a flag whether we've panicked or not.
//
// The actual location that this matters is when a mutex is **locked** which is
// where we have external synchronization ensuring that we see memory
// reads/writes to this flag.
//
// As a result, if it matters, we should see the correct value for `failed` in
// all cases.
impl Flag {
#[inline]
pub const fn new() -> Flag {
Flag {
#[cfg(panic = "unwind")]
failed: AtomicBool::new(false),
}
}
/// Checks the flag for an unguarded borrow, where we only care about existing poison.
#[inline]
pub fn borrow(&self) -> LockResult<()> {
if self.get() { Err(PoisonError::new(())) } else { Ok(()) }
}
/// Checks the flag for a guarded borrow, where we may also set poison when `done`.
#[inline]
pub fn guard(&self) -> LockResult<Guard> {
let ret = Guard {
#[cfg(panic = "unwind")]
panicking: thread::panicking(),
};
if self.get() { Err(PoisonError::new(ret)) } else { Ok(ret) }
}
#[inline]
#[cfg(panic = "unwind")]
pub fn done(&self, guard: &Guard) {
if !guard.panicking && thread::panicking() {
self.failed.store(true, Ordering::Relaxed);
}
}
#[inline]
#[cfg(not(panic = "unwind"))]
pub fn done(&self, _guard: &Guard) {}
#[inline]
#[cfg(panic = "unwind")]
pub fn get(&self) -> bool {
self.failed.load(Ordering::Relaxed)
}
#[inline(always)]
#[cfg(not(panic = "unwind"))]
pub fn get(&self) -> bool {
false
}
#[inline]
pub fn clear(&self) {
#[cfg(panic = "unwind")]
self.failed.store(false, Ordering::Relaxed)
}
}
#[derive(Clone)]
pub(crate) struct Guard {
#[cfg(panic = "unwind")]
panicking: bool,
}
/// A type of error which can be returned whenever a lock is acquired.
///
/// Both [`Mutex`]es and [`RwLock`]s are poisoned whenever a thread fails while the lock
/// is held. The precise semantics for when a lock is poisoned is documented on
/// each lock. For a lock in the poisoned state, unless the state is cleared manually,
/// all future acquisitions will return this error.
///
/// # Examples
///
/// ```
/// use std::sync::{Arc, Mutex};
/// use std::thread;
///
/// let mutex = Arc::new(Mutex::new(1));
///
/// // poison the mutex
/// let c_mutex = Arc::clone(&mutex);
/// let _ = thread::spawn(move || {
/// let mut data = c_mutex.lock().unwrap();
/// *data = 2;
/// panic!();
/// }).join();
///
/// match mutex.lock() {
/// Ok(_) => unreachable!(),
/// Err(p_err) => {
/// let data = p_err.get_ref();
/// println!("recovered: {data}");
/// }
/// };
/// ```
/// [`Mutex`]: crate::sync::Mutex
/// [`RwLock`]: crate::sync::RwLock
#[stable(feature = "rust1", since = "1.0.0")]
pub struct PoisonError<T> {
data: T,
#[cfg(not(panic = "unwind"))]
_never: !,
}
/// An enumeration of possible errors associated with a [`TryLockResult`] which
/// can occur while trying to acquire a lock, from the [`try_lock`] method on a
/// [`Mutex`] or the [`try_read`] and [`try_write`] methods on an [`RwLock`].
///
/// [`try_lock`]: crate::sync::Mutex::try_lock
/// [`try_read`]: crate::sync::RwLock::try_read
/// [`try_write`]: crate::sync::RwLock::try_write
/// [`Mutex`]: crate::sync::Mutex
/// [`RwLock`]: crate::sync::RwLock
#[stable(feature = "rust1", since = "1.0.0")]
pub enum TryLockError<T> {
/// The lock could not be acquired because another thread failed while holding
/// the lock.
#[stable(feature = "rust1", since = "1.0.0")]
Poisoned(#[stable(feature = "rust1", since = "1.0.0")] PoisonError<T>),
/// The lock could not be acquired at this time because the operation would
/// otherwise block.
#[stable(feature = "rust1", since = "1.0.0")]
WouldBlock,
}
/// A type alias for the result of a lock method which can be poisoned.
///
/// The [`Ok`] variant of this result indicates that the primitive was not
/// poisoned, and the operation result is contained within. The [`Err`] variant indicates
/// that the primitive was poisoned. Note that the [`Err`] variant *also* carries
/// an associated value assigned by the lock method, and it can be acquired through the
/// [`into_inner`] method. The semantics of the associated value depends on the corresponding
/// lock method.
///
/// [`into_inner`]: PoisonError::into_inner
#[stable(feature = "rust1", since = "1.0.0")]
pub type LockResult<T> = Result<T, PoisonError<T>>;
/// A type alias for the result of a nonblocking locking method.
///
/// For more information, see [`LockResult`]. A `TryLockResult` doesn't
/// necessarily hold the associated guard in the [`Err`] type as the lock might not
/// have been acquired for other reasons.
#[stable(feature = "rust1", since = "1.0.0")]
pub type TryLockResult<Guard> = Result<Guard, TryLockError<Guard>>;
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> fmt::Debug for PoisonError<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PoisonError").finish_non_exhaustive()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> fmt::Display for PoisonError<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
"poisoned lock: another task failed inside".fmt(f)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Error for PoisonError<T> {}
impl<T> PoisonError<T> {
/// Creates a `PoisonError`.
///
/// This is generally created by methods like [`Mutex::lock`](crate::sync::Mutex::lock)
/// or [`RwLock::read`](crate::sync::RwLock::read).
///
/// This method may panic if std was built with `panic="abort"`.
#[cfg(panic = "unwind")]
#[stable(feature = "sync_poison", since = "1.2.0")]
pub fn new(data: T) -> PoisonError<T> {
PoisonError { data }
}
/// Creates a `PoisonError`.
///
/// This is generally created by methods like [`Mutex::lock`](crate::sync::Mutex::lock)
/// or [`RwLock::read`](crate::sync::RwLock::read).
///
/// This method may panic if std was built with `panic="abort"`.
#[cfg(not(panic = "unwind"))]
#[stable(feature = "sync_poison", since = "1.2.0")]
#[track_caller]
pub fn new(_data: T) -> PoisonError<T> {
panic!("PoisonError created in a libstd built with panic=\"abort\"")
}
/// Consumes this error indicating that a lock is poisoned, returning the
/// associated data.
///
/// # Examples
///
/// ```
/// use std::collections::HashSet;
/// use std::sync::{Arc, Mutex};
/// use std::thread;
///
/// let mutex = Arc::new(Mutex::new(HashSet::new()));
///
/// // poison the mutex
/// let c_mutex = Arc::clone(&mutex);
/// let _ = thread::spawn(move || {
/// let mut data = c_mutex.lock().unwrap();
/// data.insert(10);
/// panic!();
/// }).join();
///
/// let p_err = mutex.lock().unwrap_err();
/// let data = p_err.into_inner();
/// println!("recovered {} items", data.len());
/// ```
#[stable(feature = "sync_poison", since = "1.2.0")]
pub fn into_inner(self) -> T {
self.data
}
/// Reaches into this error indicating that a lock is poisoned, returning a
/// reference to the associated data.
#[stable(feature = "sync_poison", since = "1.2.0")]
pub fn get_ref(&self) -> &T {
&self.data
}
/// Reaches into this error indicating that a lock is poisoned, returning a
/// mutable reference to the associated data.
#[stable(feature = "sync_poison", since = "1.2.0")]
pub fn get_mut(&mut self) -> &mut T {
&mut self.data
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> From<PoisonError<T>> for TryLockError<T> {
fn from(err: PoisonError<T>) -> TryLockError<T> {
TryLockError::Poisoned(err)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> fmt::Debug for TryLockError<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
#[cfg(panic = "unwind")]
TryLockError::Poisoned(..) => "Poisoned(..)".fmt(f),
#[cfg(not(panic = "unwind"))]
TryLockError::Poisoned(ref p) => match p._never {},
TryLockError::WouldBlock => "WouldBlock".fmt(f),
}
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> fmt::Display for TryLockError<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
#[cfg(panic = "unwind")]
TryLockError::Poisoned(..) => "poisoned lock: another task failed inside",
#[cfg(not(panic = "unwind"))]
TryLockError::Poisoned(ref p) => match p._never {},
TryLockError::WouldBlock => "try_lock failed because the operation would block",
}
.fmt(f)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Error for TryLockError<T> {
#[allow(deprecated)]
fn cause(&self) -> Option<&dyn Error> {
match *self {
#[cfg(panic = "unwind")]
TryLockError::Poisoned(ref p) => Some(p),
#[cfg(not(panic = "unwind"))]
TryLockError::Poisoned(ref p) => match p._never {},
_ => None,
}
}
}
pub(crate) fn map_result<T, U, F>(result: LockResult<T>, f: F) -> LockResult<U>
where
F: FnOnce(T) -> U,
{
match result {
Ok(t) => Ok(f(t)),
#[cfg(panic = "unwind")]
Err(PoisonError { data }) => Err(PoisonError::new(f(data))),
}
}

View File

@@ -0,0 +1,510 @@
use crate::fmt;
use crate::sync::WaitTimeoutResult;
use crate::sync::poison::{self, LockResult, MutexGuard, PoisonError, mutex};
use crate::sys::sync as sys;
use crate::time::{Duration, Instant};
/// A Condition Variable
///
/// Condition variables represent the ability to block a thread such that it
/// consumes no CPU time while waiting for an event to occur. Condition
/// variables are typically associated with a boolean predicate (a condition)
/// and a mutex. The predicate is always verified inside of the mutex before
/// determining that a thread must block.
///
/// Functions in this module will block the current **thread** of execution.
/// Note that any attempt to use multiple mutexes on the same condition
/// variable may result in a runtime panic.
///
/// # Examples
///
/// ```
/// use std::sync::{Arc, Mutex, Condvar};
/// use std::thread;
///
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
/// let pair2 = Arc::clone(&pair);
///
/// // Inside of our lock, spawn a new thread, and then wait for it to start.
/// thread::spawn(move || {
/// let (lock, cvar) = &*pair2;
/// let mut started = lock.lock().unwrap();
/// *started = true;
/// // We notify the condvar that the value has changed.
/// cvar.notify_one();
/// });
///
/// // Wait for the thread to start up.
/// let (lock, cvar) = &*pair;
/// let mut started = lock.lock().unwrap();
/// while !*started {
/// started = cvar.wait(started).unwrap();
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Condvar {
inner: sys::Condvar,
}
impl Condvar {
/// Creates a new condition variable which is ready to be waited on and
/// notified.
///
/// # Examples
///
/// ```
/// use std::sync::Condvar;
///
/// let condvar = Condvar::new();
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
#[must_use]
#[inline]
pub const fn new() -> Condvar {
Condvar { inner: sys::Condvar::new() }
}
/// Blocks the current thread until this condition variable receives a
/// notification.
///
/// This function will atomically unlock the mutex specified (represented by
/// `guard`) and block the current thread. This means that any calls
/// to [`notify_one`] or [`notify_all`] which happen logically after the
/// mutex is unlocked are candidates to wake this thread up. When this
/// function call returns, the lock specified will have been re-acquired.
///
/// Note that this function is susceptible to spurious wakeups. Condition
/// variables normally have a boolean predicate associated with them, and
/// the predicate must always be checked each time this function returns to
/// protect against spurious wakeups.
///
/// # Errors
///
/// This function will return an error if the mutex being waited on is
/// poisoned when this thread re-acquires the lock. For more information,
/// see information about [poisoning] on the [`Mutex`] type.
///
/// # Panics
///
/// This function may [`panic!`] if it is used with more than one mutex
/// over time.
///
/// [`notify_one`]: Self::notify_one
/// [`notify_all`]: Self::notify_all
/// [poisoning]: super::Mutex#poisoning
/// [`Mutex`]: super::Mutex
///
/// # Examples
///
/// ```
/// use std::sync::{Arc, Mutex, Condvar};
/// use std::thread;
///
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
/// let pair2 = Arc::clone(&pair);
///
/// thread::spawn(move || {
/// let (lock, cvar) = &*pair2;
/// let mut started = lock.lock().unwrap();
/// *started = true;
/// // We notify the condvar that the value has changed.
/// cvar.notify_one();
/// });
///
/// // Wait for the thread to start up.
/// let (lock, cvar) = &*pair;
/// let mut started = lock.lock().unwrap();
/// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
/// while !*started {
/// started = cvar.wait(started).unwrap();
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_should_not_be_called_on_const_items]
pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) -> LockResult<MutexGuard<'a, T>> {
let poisoned = unsafe {
let lock = mutex::guard_lock(&guard);
self.inner.wait(lock);
mutex::guard_poison(&guard).get()
};
if poisoned { Err(PoisonError::new(guard)) } else { Ok(guard) }
}
/// Blocks the current thread until the provided condition becomes false.
///
/// `condition` is checked immediately; if not met (returns `true`), this
/// will [`wait`] for the next notification then check again. This repeats
/// until `condition` returns `false`, in which case this function returns.
///
/// This function will atomically unlock the mutex specified (represented by
/// `guard`) and block the current thread. This means that any calls
/// to [`notify_one`] or [`notify_all`] which happen logically after the
/// mutex is unlocked are candidates to wake this thread up. When this
/// function call returns, the lock specified will have been re-acquired.
///
/// # Errors
///
/// This function will return an error if the mutex being waited on is
/// poisoned when this thread re-acquires the lock. For more information,
/// see information about [poisoning] on the [`Mutex`] type.
///
/// [`wait`]: Self::wait
/// [`notify_one`]: Self::notify_one
/// [`notify_all`]: Self::notify_all
/// [poisoning]: super::Mutex#poisoning
/// [`Mutex`]: super::Mutex
///
/// # Examples
///
/// ```
/// use std::sync::{Arc, Mutex, Condvar};
/// use std::thread;
///
/// let pair = Arc::new((Mutex::new(true), Condvar::new()));
/// let pair2 = Arc::clone(&pair);
///
/// thread::spawn(move || {
/// let (lock, cvar) = &*pair2;
/// let mut pending = lock.lock().unwrap();
/// *pending = false;
/// // We notify the condvar that the value has changed.
/// cvar.notify_one();
/// });
///
/// // Wait for the thread to start up.
/// let (lock, cvar) = &*pair;
/// // As long as the value inside the `Mutex<bool>` is `true`, we wait.
/// let _guard = cvar.wait_while(lock.lock().unwrap(), |pending| { *pending }).unwrap();
/// ```
#[stable(feature = "wait_until", since = "1.42.0")]
#[rustc_should_not_be_called_on_const_items]
pub fn wait_while<'a, T, F>(
&self,
mut guard: MutexGuard<'a, T>,
mut condition: F,
) -> LockResult<MutexGuard<'a, T>>
where
F: FnMut(&mut T) -> bool,
{
while condition(&mut *guard) {
guard = self.wait(guard)?;
}
Ok(guard)
}
/// Waits on this condition variable for a notification, timing out after a
/// specified duration.
///
/// The semantics of this function are equivalent to [`wait`]
/// except that the thread will be blocked for roughly no longer
/// than `ms` milliseconds. This method should not be used for
/// precise timing due to anomalies such as preemption or platform
/// differences that might not cause the maximum amount of time
/// waited to be precisely `ms`.
///
/// Note that the best effort is made to ensure that the time waited is
/// measured with a monotonic clock, and not affected by the changes made to
/// the system time.
///
/// The returned boolean is `false` only if the timeout is known
/// to have elapsed.
///
/// Like [`wait`], the lock specified will be re-acquired when this function
/// returns, regardless of whether the timeout elapsed or not.
///
/// [`wait`]: Self::wait
///
/// # Examples
///
/// ```
/// use std::sync::{Arc, Mutex, Condvar};
/// use std::thread;
///
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
/// let pair2 = Arc::clone(&pair);
///
/// thread::spawn(move || {
/// let (lock, cvar) = &*pair2;
/// let mut started = lock.lock().unwrap();
/// *started = true;
/// // We notify the condvar that the value has changed.
/// cvar.notify_one();
/// });
///
/// // Wait for the thread to start up.
/// let (lock, cvar) = &*pair;
/// let mut started = lock.lock().unwrap();
/// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
/// loop {
/// let result = cvar.wait_timeout_ms(started, 10).unwrap();
/// // 10 milliseconds have passed, or maybe the value changed!
/// started = result.0;
/// if *started == true {
/// // We received the notification and the value has been updated, we can leave.
/// break
/// }
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_should_not_be_called_on_const_items]
#[deprecated(since = "1.6.0", note = "replaced by `std::sync::Condvar::wait_timeout`")]
pub fn wait_timeout_ms<'a, T>(
&self,
guard: MutexGuard<'a, T>,
ms: u32,
) -> LockResult<(MutexGuard<'a, T>, bool)> {
let res = self.wait_timeout(guard, Duration::from_millis(ms as u64));
poison::map_result(res, |(a, b)| (a, !b.timed_out()))
}
/// Waits on this condition variable for a notification, timing out after a
/// specified duration.
///
/// The semantics of this function are equivalent to [`wait`] except that
/// the thread will be blocked for roughly no longer than `dur`. This
/// method should not be used for precise timing due to anomalies such as
/// preemption or platform differences that might not cause the maximum
/// amount of time waited to be precisely `dur`.
///
/// Note that the best effort is made to ensure that the time waited is
/// measured with a monotonic clock, and not affected by the changes made to
/// the system time. This function is susceptible to spurious wakeups.
/// Condition variables normally have a boolean predicate associated with
/// them, and the predicate must always be checked each time this function
/// returns to protect against spurious wakeups. Furthermore, since the timeout
/// is given relative to the moment this function is called, it needs to be adjusted
/// when this function is called in a loop. The [`wait_timeout_while`] method
/// lets you wait with a timeout while a predicate is true, taking care of all these concerns.
///
/// The returned [`WaitTimeoutResult`] value indicates if the timeout is
/// known to have elapsed.
///
/// Like [`wait`], the lock specified will be re-acquired when this function
/// returns, regardless of whether the timeout elapsed or not.
///
/// [`wait`]: Self::wait
/// [`wait_timeout_while`]: Self::wait_timeout_while
///
/// # Examples
///
/// ```
/// use std::sync::{Arc, Mutex, Condvar};
/// use std::thread;
/// use std::time::Duration;
///
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
/// let pair2 = Arc::clone(&pair);
///
/// thread::spawn(move || {
/// let (lock, cvar) = &*pair2;
/// let mut started = lock.lock().unwrap();
/// *started = true;
/// // We notify the condvar that the value has changed.
/// cvar.notify_one();
/// });
///
/// // wait for the thread to start up
/// let (lock, cvar) = &*pair;
/// let mut started = lock.lock().unwrap();
/// // as long as the value inside the `Mutex<bool>` is `false`, we wait
/// loop {
/// let result = cvar.wait_timeout(started, Duration::from_millis(10)).unwrap();
/// // 10 milliseconds have passed, or maybe the value changed!
/// started = result.0;
/// if *started == true {
/// // We received the notification and the value has been updated, we can leave.
/// break
/// }
/// }
/// ```
#[stable(feature = "wait_timeout", since = "1.5.0")]
#[rustc_should_not_be_called_on_const_items]
pub fn wait_timeout<'a, T>(
&self,
guard: MutexGuard<'a, T>,
dur: Duration,
) -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> {
let (poisoned, result) = unsafe {
let lock = mutex::guard_lock(&guard);
let success = self.inner.wait_timeout(lock, dur);
(mutex::guard_poison(&guard).get(), WaitTimeoutResult(!success))
};
if poisoned { Err(PoisonError::new((guard, result))) } else { Ok((guard, result)) }
}
/// Waits on this condition variable for a notification, timing out after a
/// specified duration.
///
/// The semantics of this function are equivalent to [`wait_while`] except
/// that the thread will be blocked for roughly no longer than `dur`. This
/// method should not be used for precise timing due to anomalies such as
/// preemption or platform differences that might not cause the maximum
/// amount of time waited to be precisely `dur`.
///
/// Note that the best effort is made to ensure that the time waited is
/// measured with a monotonic clock, and not affected by the changes made to
/// the system time.
///
/// The returned [`WaitTimeoutResult`] value indicates if the timeout is
/// known to have elapsed without the condition being met.
///
/// Like [`wait_while`], the lock specified will be re-acquired when this
/// function returns, regardless of whether the timeout elapsed or not.
///
/// [`wait_while`]: Self::wait_while
/// [`wait_timeout`]: Self::wait_timeout
///
/// # Examples
///
/// ```
/// use std::sync::{Arc, Mutex, Condvar};
/// use std::thread;
/// use std::time::Duration;
///
/// let pair = Arc::new((Mutex::new(true), Condvar::new()));
/// let pair2 = Arc::clone(&pair);
///
/// thread::spawn(move || {
/// let (lock, cvar) = &*pair2;
/// let mut pending = lock.lock().unwrap();
/// *pending = false;
/// // We notify the condvar that the value has changed.
/// cvar.notify_one();
/// });
///
/// // wait for the thread to start up
/// let (lock, cvar) = &*pair;
/// let result = cvar.wait_timeout_while(
/// lock.lock().unwrap(),
/// Duration::from_millis(100),
/// |&mut pending| pending,
/// ).unwrap();
/// if result.1.timed_out() {
/// // timed-out without the condition ever evaluating to false.
/// }
/// // access the locked mutex via result.0
/// ```
#[stable(feature = "wait_timeout_until", since = "1.42.0")]
#[rustc_should_not_be_called_on_const_items]
pub fn wait_timeout_while<'a, T, F>(
&self,
mut guard: MutexGuard<'a, T>,
dur: Duration,
mut condition: F,
) -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)>
where
F: FnMut(&mut T) -> bool,
{
let start = Instant::now();
loop {
if !condition(&mut *guard) {
return Ok((guard, WaitTimeoutResult(false)));
}
let timeout = match dur.checked_sub(start.elapsed()) {
Some(timeout) => timeout,
None => return Ok((guard, WaitTimeoutResult(true))),
};
guard = self.wait_timeout(guard, timeout)?.0;
}
}
/// Wakes up one blocked thread on this condvar.
///
/// If there is a blocked thread on this condition variable, then it will
/// be woken up from its call to [`wait`] or [`wait_timeout`]. Calls to
/// `notify_one` are not buffered in any way.
///
/// To wake up all threads, see [`notify_all`].
///
/// [`wait`]: Self::wait
/// [`wait_timeout`]: Self::wait_timeout
/// [`notify_all`]: Self::notify_all
///
/// # Examples
///
/// ```
/// use std::sync::{Arc, Mutex, Condvar};
/// use std::thread;
///
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
/// let pair2 = Arc::clone(&pair);
///
/// thread::spawn(move || {
/// let (lock, cvar) = &*pair2;
/// let mut started = lock.lock().unwrap();
/// *started = true;
/// // We notify the condvar that the value has changed.
/// cvar.notify_one();
/// });
///
/// // Wait for the thread to start up.
/// let (lock, cvar) = &*pair;
/// let mut started = lock.lock().unwrap();
/// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
/// while !*started {
/// started = cvar.wait(started).unwrap();
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_should_not_be_called_on_const_items]
pub fn notify_one(&self) {
self.inner.notify_one()
}
/// Wakes up all blocked threads on this condvar.
///
/// This method will ensure that any current waiters on the condition
/// variable are awoken. Calls to `notify_all()` are not buffered in any
/// way.
///
/// To wake up only one thread, see [`notify_one`].
///
/// [`notify_one`]: Self::notify_one
///
/// # Examples
///
/// ```
/// use std::sync::{Arc, Mutex, Condvar};
/// use std::thread;
///
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
/// let pair2 = Arc::clone(&pair);
///
/// thread::spawn(move || {
/// let (lock, cvar) = &*pair2;
/// let mut started = lock.lock().unwrap();
/// *started = true;
/// // We notify the condvar that the value has changed.
/// cvar.notify_all();
/// });
///
/// // Wait for the thread to start up.
/// let (lock, cvar) = &*pair;
/// let mut started = lock.lock().unwrap();
/// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
/// while !*started {
/// started = cvar.wait(started).unwrap();
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_should_not_be_called_on_const_items]
pub fn notify_all(&self) {
self.inner.notify_all()
}
}
#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Condvar {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Condvar").finish_non_exhaustive()
}
}
#[stable(feature = "condvar_default", since = "1.10.0")]
impl Default for Condvar {
/// Creates a `Condvar` which is ready to be waited on and notified.
fn default() -> Condvar {
Condvar::new()
}
}

View File

@@ -0,0 +1,946 @@
use crate::cell::UnsafeCell;
use crate::fmt;
use crate::marker::PhantomData;
use crate::mem::{self, ManuallyDrop};
use crate::ops::{Deref, DerefMut};
use crate::ptr::NonNull;
use crate::sync::{LockResult, PoisonError, TryLockError, TryLockResult, poison};
use crate::sys::sync as sys;
/// A mutual exclusion primitive useful for protecting shared data
///
/// This mutex will block threads waiting for the lock to become available. The
/// mutex can be created via a [`new`] constructor. Each mutex has a type parameter
/// which represents the data that it is protecting. The data can only be accessed
/// through the RAII guards returned from [`lock`] and [`try_lock`], which
/// guarantees that the data is only ever accessed when the mutex is locked.
///
/// # Poisoning
///
/// The mutexes in this module implement a strategy called "poisoning" where a
/// mutex becomes poisoned if it recognizes that the thread holding it has
/// panicked.
///
/// Once a mutex is poisoned, all other threads are unable to access the data by
/// default as it is likely tainted (some invariant is not being upheld). For a
/// mutex, this means that the [`lock`] and [`try_lock`] methods return a
/// [`Result`] which indicates whether a mutex has been poisoned or not. Most
/// usage of a mutex will simply [`unwrap()`] these results, propagating panics
/// among threads to ensure that a possibly invalid invariant is not witnessed.
///
/// Poisoning is only advisory: the [`PoisonError`] type has an [`into_inner`]
/// method which will return the guard that would have otherwise been returned
/// on a successful lock. This allows access to the data, despite the lock being
/// poisoned.
///
/// In addition, the panic detection is not ideal, so even unpoisoned mutexes
/// need to be handled with care, since certain panics may have been skipped.
/// Here is a non-exhaustive list of situations where this might occur:
///
/// - If a mutex is locked while a panic is underway, e.g. within a [`Drop`]
/// implementation or a [panic hook], panicking for the second time while the
/// lock is held will leave the mutex unpoisoned. Note that while double panic
/// usually aborts the program, [`catch_unwind`] can prevent this.
///
/// - Locking and unlocking the mutex across different panic contexts, e.g. by
/// storing the guard to a [`Cell`] within [`Drop::drop`] and accessing it
/// outside, or vice versa, can affect poisoning status in an unexpected way.
///
/// - Foreign exceptions do not currently trigger poisoning even in absence of
/// other panics.
///
/// While this rarely happens in realistic code, `unsafe` code cannot rely on
/// poisoning for soundness, since the behavior of poisoning can depend on
/// outside context. Here's an example of **incorrect** use of poisoning:
///
/// ```rust
/// use std::sync::Mutex;
///
/// struct MutexBox<T> {
/// data: Mutex<*mut T>,
/// }
///
/// impl<T> MutexBox<T> {
/// pub fn new(value: T) -> Self {
/// Self {
/// data: Mutex::new(Box::into_raw(Box::new(value))),
/// }
/// }
///
/// pub fn replace_with(&self, f: impl FnOnce(T) -> T) {
/// let ptr = self.data.lock().expect("poisoned");
/// // While `f` is running, the data is moved out of `*ptr`. If `f`
/// // panics, `*ptr` keeps pointing at a dropped value. The intention
/// // is that this will poison the mutex, so the following calls to
/// // `replace_with` will panic without reading `*ptr`. But since
/// // poisoning is not guaranteed to occur if this is run from a panic
/// // hook, this can lead to use-after-free.
/// unsafe {
/// (*ptr).write(f((*ptr).read()));
/// }
/// }
/// }
/// ```
///
/// [`new`]: Self::new
/// [`lock`]: Self::lock
/// [`try_lock`]: Self::try_lock
/// [`unwrap()`]: Result::unwrap
/// [`PoisonError`]: super::PoisonError
/// [`into_inner`]: super::PoisonError::into_inner
/// [panic hook]: core::panic::set_hook
/// [`catch_unwind`]: core::panic::catch_unwind
/// [`Cell`]: crate::cell::Cell
///
/// # Examples
///
/// ```
/// use std::sync::{Arc, Mutex};
/// use std::thread;
/// use std::sync::mpsc::channel;
///
/// const N: usize = 10;
///
/// // Spawn a few threads to increment a shared variable (non-atomically), and
/// // let the main thread know once all increments are done.
/// //
/// // Here we're using an Arc to share memory among threads, and the data inside
/// // the Arc is protected with a mutex.
/// let data = Arc::new(Mutex::new(0));
///
/// let (tx, rx) = channel();
/// for _ in 0..N {
/// let (data, tx) = (Arc::clone(&data), tx.clone());
/// thread::spawn(move || {
/// // The shared state can only be accessed once the lock is held.
/// // Our non-atomic increment is safe because we're the only thread
/// // which can access the shared state when the lock is held.
/// //
/// // We unwrap() the return value to assert that we are not expecting
/// // threads to ever fail while holding the lock.
/// let mut data = data.lock().unwrap();
/// *data += 1;
/// if *data == N {
/// tx.send(()).unwrap();
/// }
/// // the lock is unlocked here when `data` goes out of scope.
/// });
/// }
///
/// rx.recv().unwrap();
/// ```
///
/// To recover from a poisoned mutex:
///
/// ```
/// use std::sync::{Arc, Mutex};
/// use std::thread;
///
/// let lock = Arc::new(Mutex::new(0_u32));
/// let lock2 = Arc::clone(&lock);
///
/// let _ = thread::spawn(move || -> () {
/// // This thread will acquire the mutex first, unwrapping the result of
/// // `lock` because the lock has not been poisoned.
/// let _guard = lock2.lock().unwrap();
///
/// // This panic while holding the lock (`_guard` is in scope) will poison
/// // the mutex.
/// panic!();
/// }).join();
///
/// // The lock is poisoned by this point, but the returned result can be
/// // pattern matched on to return the underlying guard on both branches.
/// let mut guard = match lock.lock() {
/// Ok(guard) => guard,
/// Err(poisoned) => poisoned.into_inner(),
/// };
///
/// *guard += 1;
/// ```
///
/// To unlock a mutex guard sooner than the end of the enclosing scope,
/// either create an inner scope or drop the guard manually.
///
/// ```
/// use std::sync::{Arc, Mutex};
/// use std::thread;
///
/// const N: usize = 3;
///
/// let data_mutex = Arc::new(Mutex::new(vec![1, 2, 3, 4]));
/// let res_mutex = Arc::new(Mutex::new(0));
///
/// let mut threads = Vec::with_capacity(N);
/// (0..N).for_each(|_| {
/// let data_mutex_clone = Arc::clone(&data_mutex);
/// let res_mutex_clone = Arc::clone(&res_mutex);
///
/// threads.push(thread::spawn(move || {
/// // Here we use a block to limit the lifetime of the lock guard.
/// let result = {
/// let mut data = data_mutex_clone.lock().unwrap();
/// // This is the result of some important and long-ish work.
/// let result = data.iter().fold(0, |acc, x| acc + x * 2);
/// data.push(result);
/// result
/// // The mutex guard gets dropped here, together with any other values
/// // created in the critical section.
/// };
/// // The guard created here is a temporary dropped at the end of the statement, i.e.
/// // the lock would not remain being held even if the thread did some additional work.
/// *res_mutex_clone.lock().unwrap() += result;
/// }));
/// });
///
/// let mut data = data_mutex.lock().unwrap();
/// // This is the result of some important and long-ish work.
/// let result = data.iter().fold(0, |acc, x| acc + x * 2);
/// data.push(result);
/// // We drop the `data` explicitly because it's not necessary anymore and the
/// // thread still has work to do. This allows other threads to start working on
/// // the data immediately, without waiting for the rest of the unrelated work
/// // to be done here.
/// //
/// // It's even more important here than in the threads because we `.join` the
/// // threads after that. If we had not dropped the mutex guard, a thread could
/// // be waiting forever for it, causing a deadlock.
/// // As in the threads, a block could have been used instead of calling the
/// // `drop` function.
/// drop(data);
/// // Here the mutex guard is not assigned to a variable and so, even if the
/// // scope does not end after this line, the mutex is still released: there is
/// // no deadlock.
/// *res_mutex.lock().unwrap() += result;
///
/// threads.into_iter().for_each(|thread| {
/// thread
/// .join()
/// .expect("The thread creating or execution failed !")
/// });
///
/// assert_eq!(*res_mutex.lock().unwrap(), 800);
/// ```
///
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "Mutex")]
pub struct Mutex<T: ?Sized> {
inner: sys::Mutex,
poison: poison::Flag,
data: UnsafeCell<T>,
}
/// `T` must be `Send` for a [`Mutex`] to be `Send` because it is possible to acquire
/// the owned `T` from the `Mutex` via [`into_inner`].
///
/// [`into_inner`]: Mutex::into_inner
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}
/// `T` must be `Send` for [`Mutex`] to be `Sync`.
/// This ensures that the protected data can be accessed safely from multiple threads
/// without causing data races or other unsafe behavior.
///
/// [`Mutex<T>`] provides mutable access to `T` to one thread at a time. However, it's essential
/// for `T` to be `Send` because it's not safe for non-`Send` structures to be accessed in
/// this manner. For instance, consider [`Rc`], a non-atomic reference counted smart pointer,
/// which is not `Send`. With `Rc`, we can have multiple copies pointing to the same heap
/// allocation with a non-atomic reference count. If we were to use `Mutex<Rc<_>>`, it would
/// only protect one instance of `Rc` from shared access, leaving other copies vulnerable
/// to potential data races.
///
/// Also note that it is not necessary for `T` to be `Sync` as `&T` is only made available
/// to one thread at a time if `T` is not `Sync`.
///
/// [`Rc`]: crate::rc::Rc
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<T: ?Sized + Send> Sync for Mutex<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.
///
/// The data protected by the mutex can be accessed through this guard via its
/// [`Deref`] and [`DerefMut`] implementations.
///
/// This structure is created by the [`lock`] and [`try_lock`] methods on
/// [`Mutex`].
///
/// [`lock`]: Mutex::lock
/// [`try_lock`]: Mutex::try_lock
#[must_use = "if unused the Mutex will immediately unlock"]
#[must_not_suspend = "holding a MutexGuard across suspend \
points can cause deadlocks, delays, \
and cause Futures to not implement `Send`"]
#[stable(feature = "rust1", since = "1.0.0")]
#[clippy::has_significant_drop]
#[cfg_attr(not(test), rustc_diagnostic_item = "MutexGuard")]
pub struct MutexGuard<'a, T: ?Sized + 'a> {
lock: &'a Mutex<T>,
poison: poison::Guard,
}
/// A [`MutexGuard`] is not `Send` to maximize platform portability.
///
/// On platforms that use POSIX threads (commonly referred to as pthreads) there is a requirement to
/// release mutex locks on the same thread they were acquired.
/// For this reason, [`MutexGuard`] must not implement `Send` to prevent it being dropped from
/// another thread.
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> !Send for MutexGuard<'_, T> {}
/// `T` must be `Sync` for a [`MutexGuard<T>`] to be `Sync`
/// because it is possible to get a `&T` from `&MutexGuard` (via `Deref`).
#[stable(feature = "mutexguard", since = "1.19.0")]
unsafe impl<T: ?Sized + Sync> Sync for MutexGuard<'_, T> {}
/// An RAII mutex guard returned by `MutexGuard::map`, which can point to a
/// subfield of the protected data. When this structure is dropped (falls out
/// of scope), the lock will be unlocked.
///
/// The main difference between `MappedMutexGuard` and [`MutexGuard`] is that the
/// former cannot be used with [`Condvar`], since that
/// could introduce soundness issues if the locked object is modified by another
/// thread while the `Mutex` is unlocked.
///
/// The data protected by the mutex can be accessed through this guard via its
/// [`Deref`] and [`DerefMut`] implementations.
///
/// This structure is created by the [`map`] and [`filter_map`] methods on
/// [`MutexGuard`].
///
/// [`map`]: MutexGuard::map
/// [`filter_map`]: MutexGuard::filter_map
/// [`Condvar`]: crate::sync::Condvar
#[must_use = "if unused the Mutex will immediately unlock"]
#[must_not_suspend = "holding a MappedMutexGuard across suspend \
points can cause deadlocks, delays, \
and cause Futures to not implement `Send`"]
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
#[clippy::has_significant_drop]
pub struct MappedMutexGuard<'a, T: ?Sized + 'a> {
// NB: we use a pointer instead of `&'a mut T` to avoid `noalias` violations, because a
// `MappedMutexGuard` argument doesn't hold uniqueness for its whole scope, only until it drops.
// `NonNull` is covariant over `T`, so we add a `PhantomData<&'a mut T>` field
// below for the correct variance over `T` (invariance).
data: NonNull<T>,
inner: &'a sys::Mutex,
poison_flag: &'a poison::Flag,
poison: poison::Guard,
_variance: PhantomData<&'a mut T>,
}
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
impl<T: ?Sized> !Send for MappedMutexGuard<'_, T> {}
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
unsafe impl<T: ?Sized + Sync> Sync for MappedMutexGuard<'_, T> {}
impl<T> Mutex<T> {
/// Creates a new mutex in an unlocked state ready for use.
///
/// # Examples
///
/// ```
/// use std::sync::Mutex;
///
/// let mutex = Mutex::new(0);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
#[inline]
pub const fn new(t: T) -> Mutex<T> {
Mutex { inner: sys::Mutex::new(), poison: poison::Flag::new(), data: UnsafeCell::new(t) }
}
/// Returns the contained value by cloning it.
///
/// # Errors
///
/// If another user of this mutex panicked while holding the mutex, then
/// this call will return an error instead.
///
/// # Examples
///
/// ```
/// #![feature(lock_value_accessors)]
///
/// use std::sync::Mutex;
///
/// let mut mutex = Mutex::new(7);
///
/// assert_eq!(mutex.get_cloned().unwrap(), 7);
/// ```
#[unstable(feature = "lock_value_accessors", issue = "133407")]
pub fn get_cloned(&self) -> Result<T, PoisonError<()>>
where
T: Clone,
{
match self.lock() {
Ok(guard) => Ok((*guard).clone()),
Err(_) => Err(PoisonError::new(())),
}
}
/// Sets the contained value.
///
/// # Errors
///
/// If another user of this mutex panicked while holding the mutex, then
/// this call will return an error containing the provided `value` instead.
///
/// # Examples
///
/// ```
/// #![feature(lock_value_accessors)]
///
/// use std::sync::Mutex;
///
/// let mut mutex = Mutex::new(7);
///
/// assert_eq!(mutex.get_cloned().unwrap(), 7);
/// mutex.set(11).unwrap();
/// assert_eq!(mutex.get_cloned().unwrap(), 11);
/// ```
#[unstable(feature = "lock_value_accessors", issue = "133407")]
#[rustc_should_not_be_called_on_const_items]
pub fn set(&self, value: T) -> Result<(), PoisonError<T>> {
if mem::needs_drop::<T>() {
// If the contained value has non-trivial destructor, we
// call that destructor after the lock being released.
self.replace(value).map(drop)
} else {
match self.lock() {
Ok(mut guard) => {
*guard = value;
Ok(())
}
Err(_) => Err(PoisonError::new(value)),
}
}
}
/// Replaces the contained value with `value`, and returns the old contained value.
///
/// # Errors
///
/// If another user of this mutex panicked while holding the mutex, then
/// this call will return an error containing the provided `value` instead.
///
/// # Examples
///
/// ```
/// #![feature(lock_value_accessors)]
///
/// use std::sync::Mutex;
///
/// let mut mutex = Mutex::new(7);
///
/// assert_eq!(mutex.replace(11).unwrap(), 7);
/// assert_eq!(mutex.get_cloned().unwrap(), 11);
/// ```
#[unstable(feature = "lock_value_accessors", issue = "133407")]
#[rustc_should_not_be_called_on_const_items]
pub fn replace(&self, value: T) -> LockResult<T> {
match self.lock() {
Ok(mut guard) => Ok(mem::replace(&mut *guard, value)),
Err(_) => Err(PoisonError::new(value)),
}
}
}
impl<T: ?Sized> Mutex<T> {
/// Acquires a mutex, blocking the current thread until it is able to do so.
///
/// This function will block the local thread until it is available to acquire
/// the mutex. Upon returning, the thread is the only thread with the lock
/// held. An RAII guard is returned to allow scoped unlock of the lock. When
/// the guard goes out of scope, the mutex will be unlocked.
///
/// The exact behavior on locking a mutex in the thread which already holds
/// the lock is left unspecified. However, this function will not return on
/// the second call (it might panic or deadlock, for example).
///
/// # Errors
///
/// If another user of this mutex panicked while holding the mutex, then
/// this call will return an error once the mutex is acquired. The acquired
/// mutex guard will be contained in the returned error.
///
/// # Panics
///
/// This function might panic when called if the lock is already held by
/// the current thread.
///
/// # Examples
///
/// ```
/// use std::sync::{Arc, Mutex};
/// use std::thread;
///
/// let mutex = Arc::new(Mutex::new(0));
/// let c_mutex = Arc::clone(&mutex);
///
/// thread::spawn(move || {
/// *c_mutex.lock().unwrap() = 10;
/// }).join().expect("thread::spawn failed");
/// assert_eq!(*mutex.lock().unwrap(), 10);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_should_not_be_called_on_const_items]
pub fn lock(&self) -> LockResult<MutexGuard<'_, T>> {
unsafe {
self.inner.lock();
MutexGuard::new(self)
}
}
/// Attempts to acquire this lock.
///
/// 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.
///
/// This function does not block.
///
/// # Errors
///
/// If another user of this mutex panicked while holding the mutex, then
/// this call will return the [`Poisoned`] error if the mutex would
/// otherwise be acquired. An acquired lock guard will be contained
/// in the returned error.
///
/// If the mutex could not be acquired because it is already locked, then
/// this call will return the [`WouldBlock`] error.
///
/// [`Poisoned`]: TryLockError::Poisoned
/// [`WouldBlock`]: TryLockError::WouldBlock
///
/// # Examples
///
/// ```
/// use std::sync::{Arc, Mutex};
/// use std::thread;
///
/// let mutex = Arc::new(Mutex::new(0));
/// let c_mutex = Arc::clone(&mutex);
///
/// thread::spawn(move || {
/// let mut lock = c_mutex.try_lock();
/// if let Ok(ref mut mutex) = lock {
/// **mutex = 10;
/// } else {
/// println!("try_lock failed");
/// }
/// }).join().expect("thread::spawn failed");
/// assert_eq!(*mutex.lock().unwrap(), 10);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_should_not_be_called_on_const_items]
pub fn try_lock(&self) -> TryLockResult<MutexGuard<'_, T>> {
unsafe {
if self.inner.try_lock() {
Ok(MutexGuard::new(self)?)
} else {
Err(TryLockError::WouldBlock)
}
}
}
/// Determines whether the mutex is poisoned.
///
/// If another thread is active, the mutex can still become poisoned at any
/// time. You should not trust a `false` value for program correctness
/// without additional synchronization.
///
/// # Examples
///
/// ```
/// use std::sync::{Arc, Mutex};
/// use std::thread;
///
/// let mutex = Arc::new(Mutex::new(0));
/// let c_mutex = Arc::clone(&mutex);
///
/// let _ = thread::spawn(move || {
/// let _lock = c_mutex.lock().unwrap();
/// panic!(); // the mutex gets poisoned
/// }).join();
/// assert_eq!(mutex.is_poisoned(), true);
/// ```
#[inline]
#[stable(feature = "sync_poison", since = "1.2.0")]
pub fn is_poisoned(&self) -> bool {
self.poison.get()
}
/// Clear the poisoned state from a mutex.
///
/// If the mutex is poisoned, it will remain poisoned until this function is called. This
/// allows recovering from a poisoned state and marking that it has recovered. For example, if
/// the value is overwritten by a known-good value, then the mutex can be marked as
/// un-poisoned. Or possibly, the value could be inspected to determine if it is in a
/// consistent state, and if so the poison is removed.
///
/// # Examples
///
/// ```
/// use std::sync::{Arc, Mutex};
/// use std::thread;
///
/// let mutex = Arc::new(Mutex::new(0));
/// let c_mutex = Arc::clone(&mutex);
///
/// let _ = thread::spawn(move || {
/// let _lock = c_mutex.lock().unwrap();
/// panic!(); // the mutex gets poisoned
/// }).join();
///
/// assert_eq!(mutex.is_poisoned(), true);
/// let x = mutex.lock().unwrap_or_else(|mut e| {
/// **e.get_mut() = 1;
/// mutex.clear_poison();
/// e.into_inner()
/// });
/// assert_eq!(mutex.is_poisoned(), false);
/// assert_eq!(*x, 1);
/// ```
#[inline]
#[stable(feature = "mutex_unpoison", since = "1.77.0")]
#[rustc_should_not_be_called_on_const_items]
pub fn clear_poison(&self) {
self.poison.clear();
}
/// Consumes this mutex, returning the underlying data.
///
/// # Errors
///
/// If another user of this mutex panicked while holding the mutex, then
/// this call will return an error containing the underlying data
/// instead.
///
/// # Examples
///
/// ```
/// use std::sync::Mutex;
///
/// let mutex = Mutex::new(0);
/// assert_eq!(mutex.into_inner().unwrap(), 0);
/// ```
#[stable(feature = "mutex_into_inner", since = "1.6.0")]
pub fn into_inner(self) -> LockResult<T>
where
T: Sized,
{
let data = self.data.into_inner();
poison::map_result(self.poison.borrow(), |()| data)
}
/// Returns a mutable reference to the underlying data.
///
/// Since this call borrows the `Mutex` mutably, no actual locking needs to
/// take place -- the mutable borrow statically guarantees no new locks can be acquired
/// while this reference exists. Note that this method does not clear any previous abandoned locks
/// (e.g., via [`forget()`] on a [`MutexGuard`]).
///
/// # Errors
///
/// If another user of this mutex panicked while holding the mutex, then
/// this call will return an error containing a mutable reference to the
/// underlying data instead.
///
/// # Examples
///
/// ```
/// use std::sync::Mutex;
///
/// let mut mutex = Mutex::new(0);
/// *mutex.get_mut().unwrap() = 10;
/// assert_eq!(*mutex.lock().unwrap(), 10);
/// ```
///
/// [`forget()`]: mem::forget
#[stable(feature = "mutex_get_mut", since = "1.6.0")]
pub fn get_mut(&mut self) -> LockResult<&mut T> {
let data = self.data.get_mut();
poison::map_result(self.poison.borrow(), |()| data)
}
/// Returns a raw pointer to the underlying data.
///
/// The returned pointer is always non-null and properly aligned, but it is
/// the user's responsibility to ensure that any reads and writes through it
/// are properly synchronized to avoid data races, and that it is not read
/// or written through after the mutex is dropped.
#[unstable(feature = "mutex_data_ptr", issue = "140368")]
pub const fn data_ptr(&self) -> *mut T {
self.data.get()
}
}
#[stable(feature = "mutex_from", since = "1.24.0")]
impl<T> From<T> for Mutex<T> {
/// Creates a new mutex in an unlocked state ready for use.
/// This is equivalent to [`Mutex::new`].
fn from(t: T) -> Self {
Mutex::new(t)
}
}
#[stable(feature = "mutex_default", since = "1.10.0")]
impl<T: Default> Default for Mutex<T> {
/// Creates a `Mutex<T>`, with the `Default` value for T.
fn default() -> Mutex<T> {
Mutex::new(Default::default())
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut d = f.debug_struct("Mutex");
match self.try_lock() {
Ok(guard) => {
d.field("data", &&*guard);
}
Err(TryLockError::Poisoned(err)) => {
d.field("data", &&**err.get_ref());
}
Err(TryLockError::WouldBlock) => {
d.field("data", &"<locked>");
}
}
d.field("poisoned", &self.poison.get());
d.finish_non_exhaustive()
}
}
impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> {
unsafe fn new(lock: &'mutex Mutex<T>) -> LockResult<MutexGuard<'mutex, T>> {
poison::map_result(lock.poison.guard(), |guard| MutexGuard { lock, poison: guard })
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Deref for MutexGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.lock.data.get() }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> DerefMut for MutexGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.lock.data.get() }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Drop for MutexGuard<'_, T> {
#[inline]
fn drop(&mut self) {
unsafe {
self.lock.poison.done(&self.poison);
self.lock.inner.unlock();
}
}
}
#[stable(feature = "std_debug", since = "1.16.0")]
impl<T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
#[stable(feature = "std_guard_impls", since = "1.20.0")]
impl<T: ?Sized + fmt::Display> fmt::Display for MutexGuard<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}
/// For use in [`nonpoison::condvar`](super::condvar).
pub(super) fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex {
&guard.lock.inner
}
/// For use in [`nonpoison::condvar`](super::condvar).
pub(super) fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag {
&guard.lock.poison
}
impl<'a, T: ?Sized> MutexGuard<'a, T> {
/// Makes a [`MappedMutexGuard`] for a component of the borrowed data, e.g.
/// an enum variant.
///
/// The `Mutex` is already locked, so this cannot fail.
///
/// This is an associated function that needs to be used as
/// `MutexGuard::map(...)`. A method would interfere with methods of the
/// same name on the contents of the `MutexGuard` used through `Deref`.
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
pub fn map<U, F>(orig: Self, f: F) -> MappedMutexGuard<'a, U>
where
F: FnOnce(&mut T) -> &mut U,
U: ?Sized,
{
// SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard
// was created, and have been upheld throughout `map` and/or `filter_map`.
// The signature of the closure guarantees that it will not "leak" the lifetime of the reference
// passed to it. If the closure panics, the guard will be dropped.
let data = NonNull::from(f(unsafe { &mut *orig.lock.data.get() }));
let orig = ManuallyDrop::new(orig);
MappedMutexGuard {
data,
inner: &orig.lock.inner,
poison_flag: &orig.lock.poison,
poison: orig.poison.clone(),
_variance: PhantomData,
}
}
/// Makes a [`MappedMutexGuard`] for a component of the borrowed data. The
/// original guard is returned as an `Err(...)` if the closure returns
/// `None`.
///
/// The `Mutex` is already locked, so this cannot fail.
///
/// This is an associated function that needs to be used as
/// `MutexGuard::filter_map(...)`. A method would interfere with methods of the
/// same name on the contents of the `MutexGuard` used through `Deref`.
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
pub fn filter_map<U, F>(orig: Self, f: F) -> Result<MappedMutexGuard<'a, U>, Self>
where
F: FnOnce(&mut T) -> Option<&mut U>,
U: ?Sized,
{
// SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard
// was created, and have been upheld throughout `map` and/or `filter_map`.
// The signature of the closure guarantees that it will not "leak" the lifetime of the reference
// passed to it. If the closure panics, the guard will be dropped.
match f(unsafe { &mut *orig.lock.data.get() }) {
Some(data) => {
let data = NonNull::from(data);
let orig = ManuallyDrop::new(orig);
Ok(MappedMutexGuard {
data,
inner: &orig.lock.inner,
poison_flag: &orig.lock.poison,
poison: orig.poison.clone(),
_variance: PhantomData,
})
}
None => Err(orig),
}
}
}
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
impl<T: ?Sized> Deref for MappedMutexGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { self.data.as_ref() }
}
}
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
impl<T: ?Sized> DerefMut for MappedMutexGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { self.data.as_mut() }
}
}
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
impl<T: ?Sized> Drop for MappedMutexGuard<'_, T> {
#[inline]
fn drop(&mut self) {
unsafe {
self.poison_flag.done(&self.poison);
self.inner.unlock();
}
}
}
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
impl<T: ?Sized + fmt::Debug> fmt::Debug for MappedMutexGuard<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
impl<T: ?Sized + fmt::Display> fmt::Display for MappedMutexGuard<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}
impl<'a, T: ?Sized> MappedMutexGuard<'a, T> {
/// Makes a [`MappedMutexGuard`] for a component of the borrowed data, e.g.
/// an enum variant.
///
/// The `Mutex` is already locked, so this cannot fail.
///
/// This is an associated function that needs to be used as
/// `MappedMutexGuard::map(...)`. A method would interfere with methods of the
/// same name on the contents of the `MutexGuard` used through `Deref`.
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
pub fn map<U, F>(mut orig: Self, f: F) -> MappedMutexGuard<'a, U>
where
F: FnOnce(&mut T) -> &mut U,
U: ?Sized,
{
// SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard
// was created, and have been upheld throughout `map` and/or `filter_map`.
// The signature of the closure guarantees that it will not "leak" the lifetime of the reference
// passed to it. If the closure panics, the guard will be dropped.
let data = NonNull::from(f(unsafe { orig.data.as_mut() }));
let orig = ManuallyDrop::new(orig);
MappedMutexGuard {
data,
inner: orig.inner,
poison_flag: orig.poison_flag,
poison: orig.poison.clone(),
_variance: PhantomData,
}
}
/// Makes a [`MappedMutexGuard`] for a component of the borrowed data. The
/// original guard is returned as an `Err(...)` if the closure returns
/// `None`.
///
/// The `Mutex` is already locked, so this cannot fail.
///
/// This is an associated function that needs to be used as
/// `MappedMutexGuard::filter_map(...)`. A method would interfere with methods of the
/// same name on the contents of the `MutexGuard` used through `Deref`.
#[unstable(feature = "mapped_lock_guards", issue = "117108")]
pub fn filter_map<U, F>(mut orig: Self, f: F) -> Result<MappedMutexGuard<'a, U>, Self>
where
F: FnOnce(&mut T) -> Option<&mut U>,
U: ?Sized,
{
// SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard
// was created, and have been upheld throughout `map` and/or `filter_map`.
// The signature of the closure guarantees that it will not "leak" the lifetime of the reference
// passed to it. If the closure panics, the guard will be dropped.
match f(unsafe { orig.data.as_mut() }) {
Some(data) => {
let data = NonNull::from(data);
let orig = ManuallyDrop::new(orig);
Ok(MappedMutexGuard {
data,
inner: orig.inner,
poison_flag: orig.poison_flag,
poison: orig.poison.clone(),
_variance: PhantomData,
})
}
None => Err(orig),
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,432 @@
use crate::cell::UnsafeCell;
use crate::fmt;
use crate::ops::Deref;
use core::panic::{RefUnwindSafe, UnwindSafe};
use crate::sys::sync as sys;
use crate::thread::{ThreadId, current_id};
/// A re-entrant mutual exclusion lock
///
/// This lock will block *other* threads waiting for the lock to become
/// available. The thread which has already locked the mutex can lock it
/// multiple times without blocking, preventing a common source of deadlocks.
///
/// # Examples
///
/// Allow recursively calling a function needing synchronization from within
/// a callback (this is how [`StdoutLock`](crate::io::StdoutLock) is currently
/// implemented):
///
/// ```
/// #![feature(reentrant_lock)]
///
/// use std::cell::RefCell;
/// use std::sync::ReentrantLock;
///
/// pub struct Log {
/// data: RefCell<String>,
/// }
///
/// impl Log {
/// pub fn append(&self, msg: &str) {
/// self.data.borrow_mut().push_str(msg);
/// }
/// }
///
/// static LOG: ReentrantLock<Log> = ReentrantLock::new(Log { data: RefCell::new(String::new()) });
///
/// pub fn with_log<R>(f: impl FnOnce(&Log) -> R) -> R {
/// let log = LOG.lock();
/// f(&*log)
/// }
///
/// with_log(|log| {
/// log.append("Hello");
/// with_log(|log| log.append(" there!"));
/// });
/// ```
///
// # Implementation details
//
// The 'owner' field tracks which thread has locked the mutex.
//
// We use thread::current_id() as the thread identifier, which is just the
// current thread's ThreadId, so it's unique across the process lifetime.
//
// If `owner` is set to the identifier of the current thread,
// we assume the mutex is already locked and instead of locking it again,
// we increment `lock_count`.
//
// When unlocking, we decrement `lock_count`, and only unlock the mutex when
// it reaches zero.
//
// `lock_count` is protected by the mutex and only accessed by the thread that has
// locked the mutex, so needs no synchronization.
//
// `owner` can be checked by other threads that want to see if they already
// hold the lock, so needs to be atomic. If it compares equal, we're on the
// same thread that holds the mutex and memory access can use relaxed ordering
// since we're not dealing with multiple threads. If it's not equal,
// synchronization is left to the mutex, making relaxed memory ordering for
// the `owner` field fine in all cases.
//
// On systems without 64 bit atomics we also store the address of a TLS variable
// along the 64-bit TID. We then first check that address against the address
// of that variable on the current thread, and only if they compare equal do we
// compare the actual TIDs. Because we only ever read the TID on the same thread
// that it was written on (or a thread sharing the TLS block with that writer thread),
// we don't need to further synchronize the TID accesses, so they can be regular 64-bit
// non-atomic accesses.
#[unstable(feature = "reentrant_lock", issue = "121440")]
pub struct ReentrantLock<T: ?Sized> {
mutex: sys::Mutex,
owner: Tid,
lock_count: UnsafeCell<u32>,
data: T,
}
cfg_select!(
target_has_atomic = "64" => {
use crate::sync::atomic::{Atomic, AtomicU64, Ordering::Relaxed};
struct Tid(Atomic<u64>);
impl Tid {
const fn new() -> Self {
Self(AtomicU64::new(0))
}
#[inline]
fn contains(&self, owner: ThreadId) -> bool {
owner.as_u64().get() == self.0.load(Relaxed)
}
#[inline]
// This is just unsafe to match the API of the Tid type below.
unsafe fn set(&self, tid: Option<ThreadId>) {
let value = tid.map_or(0, |tid| tid.as_u64().get());
self.0.store(value, Relaxed);
}
}
}
_ => {
/// Returns the address of a TLS variable. This is guaranteed to
/// be unique across all currently alive threads.
fn tls_addr() -> usize {
thread_local! { static X: u8 = const { 0u8 } };
X.with(|p| <*const u8>::addr(p))
}
use crate::sync::atomic::{
Atomic,
AtomicUsize,
Ordering,
};
struct Tid {
// When a thread calls `set()`, this value gets updated to
// the address of a thread local on that thread. This is
// used as a first check in `contains()`; if the `tls_addr`
// doesn't match the TLS address of the current thread, then
// the ThreadId also can't match. Only if the TLS addresses do
// match do we read out the actual TID.
// Note also that we can use relaxed atomic operations here, because
// we only ever read from the tid if `tls_addr` matches the current
// TLS address. In that case, either the tid has been set by
// the current thread, or by a thread that has terminated before
// the current thread's `tls_addr` was allocated. In either case, no further
// synchronization is needed (as per <https://github.com/rust-lang/miri/issues/3450>)
tls_addr: Atomic<usize>,
tid: UnsafeCell<u64>,
}
unsafe impl Send for Tid {}
unsafe impl Sync for Tid {}
impl Tid {
const fn new() -> Self {
Self { tls_addr: AtomicUsize::new(0), tid: UnsafeCell::new(0) }
}
#[inline]
// NOTE: This assumes that `owner` is the ID of the current
// thread, and may spuriously return `false` if that's not the case.
fn contains(&self, owner: ThreadId) -> bool {
// We must call `tls_addr()` *before* doing the load to ensure that if we reuse an
// earlier thread's address, the `tls_addr.load()` below happens-after everything
// that thread did.
let tls_addr = tls_addr();
// SAFETY: See the comments in the struct definition.
self.tls_addr.load(Ordering::Relaxed) == tls_addr
&& unsafe { *self.tid.get() } == owner.as_u64().get()
}
#[inline]
// This may only be called by one thread at a time, and can lead to
// race conditions otherwise.
unsafe fn set(&self, tid: Option<ThreadId>) {
// It's important that we set `self.tls_addr` to 0 if the tid is
// cleared. Otherwise, there might be race conditions between
// `set()` and `get()`.
let tls_addr = if tid.is_some() { tls_addr() } else { 0 };
let value = tid.map_or(0, |tid| tid.as_u64().get());
self.tls_addr.store(tls_addr, Ordering::Relaxed);
unsafe { *self.tid.get() = value };
}
}
}
);
#[unstable(feature = "reentrant_lock", issue = "121440")]
unsafe impl<T: Send + ?Sized> Send for ReentrantLock<T> {}
#[unstable(feature = "reentrant_lock", issue = "121440")]
unsafe impl<T: Send + ?Sized> Sync for ReentrantLock<T> {}
// Because of the `UnsafeCell`, these traits are not implemented automatically
#[unstable(feature = "reentrant_lock", issue = "121440")]
impl<T: UnwindSafe + ?Sized> UnwindSafe for ReentrantLock<T> {}
#[unstable(feature = "reentrant_lock", issue = "121440")]
impl<T: RefUnwindSafe + ?Sized> RefUnwindSafe for ReentrantLock<T> {}
/// An RAII implementation of a "scoped lock" of a re-entrant lock. When this
/// structure is dropped (falls out of scope), the lock will be unlocked.
///
/// The data protected by the mutex can be accessed through this guard via its
/// [`Deref`] implementation.
///
/// This structure is created by the [`lock`](ReentrantLock::lock) method on
/// [`ReentrantLock`].
///
/// # Mutability
///
/// Unlike [`MutexGuard`](super::MutexGuard), `ReentrantLockGuard` does not
/// implement [`DerefMut`](crate::ops::DerefMut), because implementation of
/// the trait would violate Rusts reference aliasing rules. Use interior
/// mutability (usually [`RefCell`](crate::cell::RefCell)) in order to mutate
/// the guarded data.
#[must_use = "if unused the ReentrantLock will immediately unlock"]
#[unstable(feature = "reentrant_lock", issue = "121440")]
pub struct ReentrantLockGuard<'a, T: ?Sized + 'a> {
lock: &'a ReentrantLock<T>,
}
#[unstable(feature = "reentrant_lock", issue = "121440")]
impl<T: ?Sized> !Send for ReentrantLockGuard<'_, T> {}
#[unstable(feature = "reentrant_lock", issue = "121440")]
unsafe impl<T: ?Sized + Sync> Sync for ReentrantLockGuard<'_, T> {}
#[unstable(feature = "reentrant_lock", issue = "121440")]
impl<T> ReentrantLock<T> {
/// Creates a new re-entrant lock in an unlocked state ready for use.
///
/// # Examples
///
/// ```
/// #![feature(reentrant_lock)]
/// use std::sync::ReentrantLock;
///
/// let lock = ReentrantLock::new(0);
/// ```
pub const fn new(t: T) -> ReentrantLock<T> {
ReentrantLock {
mutex: sys::Mutex::new(),
owner: Tid::new(),
lock_count: UnsafeCell::new(0),
data: t,
}
}
/// Consumes this lock, returning the underlying data.
///
/// # Examples
///
/// ```
/// #![feature(reentrant_lock)]
///
/// use std::sync::ReentrantLock;
///
/// let lock = ReentrantLock::new(0);
/// assert_eq!(lock.into_inner(), 0);
/// ```
pub fn into_inner(self) -> T {
self.data
}
}
#[unstable(feature = "reentrant_lock", issue = "121440")]
impl<T: ?Sized> ReentrantLock<T> {
/// Acquires the lock, blocking the current thread until it is able to do
/// so.
///
/// This function will block the caller until it is available to acquire
/// the lock. Upon returning, the thread is the only thread with the lock
/// held. When the thread calling this method already holds the lock, the
/// call succeeds without blocking.
///
/// # Examples
///
/// ```
/// #![feature(reentrant_lock)]
/// use std::cell::Cell;
/// use std::sync::{Arc, ReentrantLock};
/// use std::thread;
///
/// let lock = Arc::new(ReentrantLock::new(Cell::new(0)));
/// let c_lock = Arc::clone(&lock);
///
/// thread::spawn(move || {
/// c_lock.lock().set(10);
/// }).join().expect("thread::spawn failed");
/// assert_eq!(lock.lock().get(), 10);
/// ```
pub fn lock(&self) -> ReentrantLockGuard<'_, T> {
let this_thread = current_id();
// Safety: We only touch lock_count when we own the inner mutex.
// Additionally, we only call `self.owner.set()` while holding
// the inner mutex, so no two threads can call it concurrently.
unsafe {
if self.owner.contains(this_thread) {
self.increment_lock_count().expect("lock count overflow in reentrant mutex");
} else {
self.mutex.lock();
self.owner.set(Some(this_thread));
debug_assert_eq!(*self.lock_count.get(), 0);
*self.lock_count.get() = 1;
}
}
ReentrantLockGuard { lock: self }
}
/// Returns a mutable reference to the underlying data.
///
/// Since this call borrows the `ReentrantLock` mutably, no actual locking
/// needs to take place -- the mutable borrow statically guarantees no locks
/// exist.
///
/// # Examples
///
/// ```
/// #![feature(reentrant_lock)]
/// use std::sync::ReentrantLock;
///
/// let mut lock = ReentrantLock::new(0);
/// *lock.get_mut() = 10;
/// assert_eq!(*lock.lock(), 10);
/// ```
pub fn get_mut(&mut self) -> &mut T {
&mut self.data
}
/// Attempts to acquire this lock.
///
/// If the lock could not be acquired at this time, then `None` is returned.
/// Otherwise, an RAII guard is returned.
///
/// This function does not block.
// FIXME maybe make it a public part of the API?
#[unstable(issue = "none", feature = "std_internals")]
#[doc(hidden)]
pub fn try_lock(&self) -> Option<ReentrantLockGuard<'_, T>> {
let this_thread = current_id();
// Safety: We only touch lock_count when we own the inner mutex.
// Additionally, we only call `self.owner.set()` while holding
// the inner mutex, so no two threads can call it concurrently.
unsafe {
if self.owner.contains(this_thread) {
self.increment_lock_count()?;
Some(ReentrantLockGuard { lock: self })
} else if self.mutex.try_lock() {
self.owner.set(Some(this_thread));
debug_assert_eq!(*self.lock_count.get(), 0);
*self.lock_count.get() = 1;
Some(ReentrantLockGuard { lock: self })
} else {
None
}
}
}
/// Returns a raw pointer to the underlying data.
///
/// The returned pointer is always non-null and properly aligned, but it is
/// the user's responsibility to ensure that any reads through it are
/// properly synchronized to avoid data races, and that it is not read
/// through after the lock is dropped.
#[unstable(feature = "reentrant_lock_data_ptr", issue = "140368")]
pub const fn data_ptr(&self) -> *const T {
&raw const self.data
}
unsafe fn increment_lock_count(&self) -> Option<()> {
unsafe {
*self.lock_count.get() = (*self.lock_count.get()).checked_add(1)?;
}
Some(())
}
}
#[unstable(feature = "reentrant_lock", issue = "121440")]
impl<T: fmt::Debug + ?Sized> fmt::Debug for ReentrantLock<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut d = f.debug_struct("ReentrantLock");
match self.try_lock() {
Some(v) => d.field("data", &&*v),
None => d.field("data", &format_args!("<locked>")),
};
d.finish_non_exhaustive()
}
}
#[unstable(feature = "reentrant_lock", issue = "121440")]
impl<T: Default> Default for ReentrantLock<T> {
fn default() -> Self {
Self::new(T::default())
}
}
#[unstable(feature = "reentrant_lock", issue = "121440")]
impl<T> From<T> for ReentrantLock<T> {
fn from(t: T) -> Self {
Self::new(t)
}
}
#[unstable(feature = "reentrant_lock", issue = "121440")]
impl<T: ?Sized> Deref for ReentrantLockGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
&self.lock.data
}
}
#[unstable(feature = "reentrant_lock", issue = "121440")]
impl<T: fmt::Debug + ?Sized> fmt::Debug for ReentrantLockGuard<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}
#[unstable(feature = "reentrant_lock", issue = "121440")]
impl<T: fmt::Display + ?Sized> fmt::Display for ReentrantLockGuard<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}
#[unstable(feature = "reentrant_lock", issue = "121440")]
impl<T: ?Sized> Drop for ReentrantLockGuard<'_, T> {
#[inline]
fn drop(&mut self) {
// Safety: We own the lock.
unsafe {
*self.lock.lock_count.get() -= 1;
if *self.lock.lock_count.get() == 0 {
self.lock.owner.set(None);
self.lock.mutex.unlock();
}
}
}
}

View File

@@ -12,6 +12,8 @@ pub mod random;
pub mod thread_local;
pub mod alloc;
pub mod io;
pub mod pipe;
pub mod stdio;
// pub mod fs;
/// A trait for viewing representations from std types.

View File

@@ -0,0 +1,20 @@
#![forbid(unsafe_op_in_unsafe_fn)]
cfg_select! {
unix => {
mod unix;
pub use unix::{Pipe, pipe};
}
windows => {
mod windows;
pub use windows::{Pipe, pipe};
}
target_os = "motor" => {
mod motor;
pub use motor::{Pipe, pipe};
}
_ => {
mod unsupported;
pub use unsupported::{Pipe, pipe};
}
}

View File

@@ -0,0 +1,101 @@
use crate::fmt;
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
pub struct Pipe(!);
#[inline]
pub fn pipe() -> io::Result<(Pipe, Pipe)> {
Err(io::Error::UNSUPPORTED_PLATFORM)
}
impl Pipe {
pub fn try_clone(&self) -> io::Result<Self> {
self.0
}
pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
self.0
}
pub fn read_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> {
self.0
}
pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
self.0
}
pub fn is_read_vectored(&self) -> bool {
self.0
}
pub fn read_to_end(&self, _buf: &mut Vec<u8>) -> io::Result<usize> {
self.0
}
pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
self.0
}
pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result<usize> {
self.0
}
pub fn is_write_vectored(&self) -> bool {
self.0
}
pub fn diverge(&self) -> ! {
self.0
}
}
impl fmt::Debug for Pipe {
fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0
}
}
#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
mod unix_traits {
use super::Pipe;
use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
use crate::sys::{FromInner, IntoInner};
impl AsRawFd for Pipe {
#[inline]
fn as_raw_fd(&self) -> RawFd {
self.0
}
}
impl AsFd for Pipe {
fn as_fd(&self) -> BorrowedFd<'_> {
self.0
}
}
impl IntoRawFd for Pipe {
fn into_raw_fd(self) -> RawFd {
self.0
}
}
impl FromRawFd for Pipe {
unsafe fn from_raw_fd(_: RawFd) -> Self {
panic!("creating pipe on this platform is unsupported!")
}
}
impl FromInner<OwnedFd> for Pipe {
fn from_inner(_: OwnedFd) -> Self {
panic!("creating pipe on this platform is unsupported!")
}
}
impl IntoInner<OwnedFd> for Pipe {
fn into_inner(self) -> OwnedFd {
self.0
}
}
}

View File

@@ -0,0 +1,52 @@
#![forbid(unsafe_op_in_unsafe_fn)]
cfg_select! {
any(target_family = "unix", target_os = "hermit", target_os = "wasi") => {
mod unix;
pub use unix::*;
}
target_os = "windows" => {
mod windows;
pub use windows::*;
}
all(target_vendor = "fortanix", target_env = "sgx") => {
mod sgx;
pub use sgx::*;
}
target_os = "motor" => {
mod motor;
pub use motor::*;
}
target_os = "solid_asp3" => {
mod solid;
pub use solid::*;
}
target_os = "teeos" => {
mod teeos;
pub use teeos::*;
}
target_os = "trusty" => {
mod trusty;
pub use trusty::*;
}
target_os = "uefi" => {
mod uefi;
pub use uefi::*;
}
target_os = "vexos" => {
mod vexos;
pub use vexos::*;
}
target_os = "xous" => {
mod xous;
pub use xous::*;
}
target_os = "zkvm" => {
mod zkvm;
pub use zkvm::*;
}
_ => {
mod unsupported;
pub use unsupported::*;
}
}

View File

@@ -0,0 +1,106 @@
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
pub struct Stdin;
pub struct Stdout;
pub type Stderr = Stdout;
impl Stdin {
pub const fn new() -> Stdin {
Stdin
}
}
impl io::Read for Stdin {
#[inline]
fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
Ok(0)
}
#[inline]
fn read_buf(&mut self, _cursor: BorrowedCursor<'_>) -> io::Result<()> {
Ok(())
}
#[inline]
fn read_vectored(&mut self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
Ok(0)
}
#[inline]
fn is_read_vectored(&self) -> bool {
// Do not force `Chain<Empty, T>` or `Chain<T, Empty>` to use vectored
// reads, unless the other reader is vectored.
false
}
#[inline]
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
if !buf.is_empty() { Err(io::Error::READ_EXACT_EOF) } else { Ok(()) }
}
#[inline]
fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
if cursor.capacity() != 0 { Err(io::Error::READ_EXACT_EOF) } else { Ok(()) }
}
#[inline]
fn read_to_end(&mut self, _buf: &mut Vec<u8>) -> io::Result<usize> {
Ok(0)
}
#[inline]
fn read_to_string(&mut self, _buf: &mut String) -> io::Result<usize> {
Ok(0)
}
}
impl Stdout {
pub const fn new() -> Stdout {
Stdout
}
}
impl io::Write for Stdout {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
Ok(buf.len())
}
#[inline]
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
let total_len = bufs.iter().map(|b| b.len()).sum();
Ok(total_len)
}
#[inline]
fn is_write_vectored(&self) -> bool {
true
}
#[inline]
fn write_all(&mut self, _buf: &[u8]) -> io::Result<()> {
Ok(())
}
#[inline]
fn write_all_vectored(&mut self, _bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
Ok(())
}
// Keep the default write_fmt so the `fmt::Arguments` are still evaluated.
#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
pub const STDIN_BUF_SIZE: usize = 0;
pub fn is_ebadf(_err: &io::Error) -> bool {
true
}
pub fn panic_output() -> Option<Vec<u8>> {
None
}

View File

@@ -5,7 +5,7 @@ use crate::cell::Cell;
use crate::marker::PhantomData;
use crate::mem::ManuallyDrop;
use crate::ops::Deref;
use crate::panic::{AssertUnwindSafe, catch_unwind, resume_unwind};
use core::panic::{AssertUnwindSafe, catch_unwind, resume_unwind};
use crate::ptr::{self, NonNull};
#[doc(hidden)]

View File

@@ -1,7 +1,23 @@
pub mod builder;
pub mod current;
pub mod functions;
pub mod id;
pub mod join_handle;
pub mod lifecycle;
pub mod local;
pub mod main_thread;
pub mod thread;
pub use crate::sys::thread::*;
use core::any::Any;
pub use crate::sys::thread::yield_now;
pub(crate) use current::current_or_unnamed;
pub use current::current_id;
pub use functions::sleep;
pub use id::ThreadId;
pub use local::LocalKey;
pub use thread::Thread;
pub(crate) use lifecycle::ThreadInit;
// Implementation details used by the thread_local!{} macro.
#[doc(hidden)]
@@ -11,14 +27,6 @@ pub mod local_impl {
pub use crate::sys::thread_local::*;
}
pub struct ThreadInit {
pub handle: Thread,
pub rust_start: Box<dyn FnOnce() + Send>,
}
impl ThreadInit {
/// Initialize the 'current thread' mechanism on this thread, returning the
/// Rust entry point.
pub fn init(self: Box<Self>) -> Box<dyn FnOnce() + Send> {
todo!()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(search_unbox)]
pub type Result<T> = crate::result::Result<T, Box<dyn Any + Send + 'static>>;

View File

@@ -0,0 +1,263 @@
use super::join_handle::JoinHandle;
use super::lifecycle::spawn_unchecked;
use crate::io;
/// Thread factory, which can be used in order to configure the properties of
/// a new thread.
///
/// Methods can be chained on it in order to configure it.
///
/// The two configurations available are:
///
/// - [`name`]: specifies an [associated name for the thread][naming-threads]
/// - [`stack_size`]: specifies the [desired stack size for the thread][stack-size]
///
/// The [`spawn`] method will take ownership of the builder and create an
/// [`io::Result`] to the thread handle with the given configuration.
///
/// The [`thread::spawn`] free function uses a `Builder` with default
/// configuration and [`unwrap`]s its return value.
///
/// You may want to use [`spawn`] instead of [`thread::spawn`], when you want
/// to recover from a failure to launch a thread, indeed the free function will
/// panic where the `Builder` method will return a [`io::Result`].
///
/// # Examples
///
/// ```
/// use std::thread;
///
/// let builder = thread::Builder::new();
///
/// let handler = builder.spawn(|| {
/// // thread code
/// }).unwrap();
///
/// handler.join().unwrap();
/// ```
///
/// [`stack_size`]: Builder::stack_size
/// [`name`]: Builder::name
/// [`spawn`]: Builder::spawn
/// [`thread::spawn`]: super::spawn
/// [`unwrap`]: crate::result::Result::unwrap
/// [naming-threads]: ./index.html#naming-threads
/// [stack-size]: ./index.html#stack-size
#[must_use = "must eventually spawn the thread"]
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug)]
pub struct Builder {
/// A name for the thread-to-be, for identification in panic messages
pub(super) name: Option<String>,
/// The size of the stack for the spawned thread in bytes
pub(super) stack_size: Option<usize>,
/// Skip running and inheriting the thread spawn hooks
pub(super) no_hooks: bool,
}
impl Builder {
/// Generates the base configuration for spawning a thread, from which
/// configuration methods can be chained.
///
/// # Examples
///
/// ```
/// use std::thread;
///
/// let builder = thread::Builder::new()
/// .name("foo".into())
/// .stack_size(32 * 1024);
///
/// let handler = builder.spawn(|| {
/// // thread code
/// }).unwrap();
///
/// handler.join().unwrap();
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new() -> Builder {
Builder { name: None, stack_size: None, no_hooks: false }
}
/// Names the thread-to-be. Currently the name is used for identification
/// only in panic messages.
///
/// The name must not contain null bytes (`\0`).
///
/// For more information about named threads, see
/// [this module-level documentation][naming-threads].
///
/// # Examples
///
/// ```
/// use std::thread;
///
/// let builder = thread::Builder::new()
/// .name("foo".into());
///
/// let handler = builder.spawn(|| {
/// assert_eq!(thread::current().name(), Some("foo"))
/// }).unwrap();
///
/// handler.join().unwrap();
/// ```
///
/// [naming-threads]: ./index.html#naming-threads
#[stable(feature = "rust1", since = "1.0.0")]
pub fn name(mut self, name: String) -> Builder {
self.name = Some(name);
self
}
/// Sets the size of the stack (in bytes) for the new thread.
///
/// The actual stack size may be greater than this value if
/// the platform specifies a minimal stack size.
///
/// For more information about the stack size for threads, see
/// [this module-level documentation][stack-size].
///
/// # Examples
///
/// ```
/// use std::thread;
///
/// let builder = thread::Builder::new().stack_size(32 * 1024);
/// ```
///
/// [stack-size]: ./index.html#stack-size
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stack_size(mut self, size: usize) -> Builder {
self.stack_size = Some(size);
self
}
/// Disables running and inheriting [spawn hooks].
///
/// Use this if the parent thread is in no way relevant for the child thread.
/// For example, when lazily spawning threads for a thread pool.
///
/// [spawn hooks]: super::add_spawn_hook
#[unstable(feature = "thread_spawn_hook", issue = "132951")]
pub fn no_hooks(mut self) -> Builder {
self.no_hooks = true;
self
}
/// Spawns a new thread by taking ownership of the `Builder`, and returns an
/// [`io::Result`] to its [`JoinHandle`].
///
/// The spawned thread may outlive the caller (unless the caller thread
/// is the main thread; the whole process is terminated when the main
/// thread finishes). The join handle can be used to block on
/// termination of the spawned thread, including recovering its panics.
///
/// For a more complete documentation see [`thread::spawn`].
///
/// # Errors
///
/// Unlike the [`spawn`] free function, this method yields an
/// [`io::Result`] to capture any failure to create the thread at
/// the OS level.
///
/// # Panics
///
/// Panics if a thread name was set and it contained null bytes.
///
/// # Examples
///
/// ```
/// use std::thread;
///
/// let builder = thread::Builder::new();
///
/// let handler = builder.spawn(|| {
/// // thread code
/// }).unwrap();
///
/// handler.join().unwrap();
/// ```
///
/// [`thread::spawn`]: super::spawn
/// [`spawn`]: super::spawn
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub fn spawn<F, T>(self, f: F) -> io::Result<JoinHandle<T>>
where
F: FnOnce() -> T,
F: Send + 'static,
T: Send + 'static,
{
unsafe { self.spawn_unchecked(f) }
}
/// Spawns a new thread without any lifetime restrictions by taking ownership
/// of the `Builder`, and returns an [`io::Result`] to its [`JoinHandle`].
///
/// The spawned thread may outlive the caller (unless the caller thread
/// is the main thread; the whole process is terminated when the main
/// thread finishes). The join handle can be used to block on
/// termination of the spawned thread, including recovering its panics.
///
/// This method is identical to [`thread::Builder::spawn`][`Builder::spawn`],
/// except for the relaxed lifetime bounds, which render it unsafe.
/// For a more complete documentation see [`thread::spawn`].
///
/// # Errors
///
/// Unlike the [`spawn`] free function, this method yields an
/// [`io::Result`] to capture any failure to create the thread at
/// the OS level.
///
/// # Panics
///
/// Panics if a thread name was set and it contained null bytes.
///
/// # Safety
///
/// The caller has to ensure that the spawned thread does not outlive any
/// references in the supplied thread closure and its return type.
/// This can be guaranteed in two ways:
///
/// - ensure that [`join`][`JoinHandle::join`] is called before any referenced
/// data is dropped
/// - use only types with `'static` lifetime bounds, i.e., those with no or only
/// `'static` references (both [`thread::Builder::spawn`][`Builder::spawn`]
/// and [`thread::spawn`] enforce this property statically)
///
/// # Examples
///
/// ```
/// use std::thread;
///
/// let builder = thread::Builder::new();
///
/// let x = 1;
/// let thread_x = &x;
///
/// let handler = unsafe {
/// builder.spawn_unchecked(move || {
/// println!("x = {}", *thread_x);
/// }).unwrap()
/// };
///
/// // caller has to ensure `join()` is called, otherwise
/// // it is possible to access freed memory if `x` gets
/// // dropped before the thread closure is executed!
/// handler.join().unwrap();
/// ```
///
/// [`thread::spawn`]: super::spawn
/// [`spawn`]: super::spawn
#[stable(feature = "thread_spawn_unchecked", since = "1.82.0")]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub unsafe fn spawn_unchecked<F, T>(self, f: F) -> io::Result<JoinHandle<T>>
where
F: FnOnce() -> T,
F: Send,
T: Send,
{
let Builder { name, stack_size, no_hooks } = self;
Ok(JoinHandle(unsafe { spawn_unchecked(name, stack_size, no_hooks, None, f) }?))
}
}

View File

@@ -0,0 +1,332 @@
use super::id::ThreadId;
use super::main_thread;
use super::thread::Thread;
use crate::mem::ManuallyDrop;
use crate::ptr;
use crate::sys::thread as imp;
use crate::sys::thread_local::local_pointer;
const NONE: *mut () = ptr::null_mut();
const BUSY: *mut () = ptr::without_provenance_mut(1);
const DESTROYED: *mut () = ptr::without_provenance_mut(2);
local_pointer! {
static CURRENT;
}
/// Persistent storage for the thread ID.
///
/// We store the thread ID so that it never gets destroyed during the lifetime
/// of a thread, either using `#[thread_local]` or multiple `local_pointer!`s.
pub(super) mod id {
use super::*;
cfg_select! {
target_thread_local => {
use crate::cell::Cell;
#[thread_local]
static ID: Cell<Option<ThreadId>> = Cell::new(None);
pub(super) const CHEAP: bool = true;
pub(crate) fn get() -> Option<ThreadId> {
ID.get()
}
pub(super) fn set(id: ThreadId) {
ID.set(Some(id))
}
}
target_pointer_width = "16" => {
local_pointer! {
static ID0;
static ID16;
static ID32;
static ID48;
}
pub(super) const CHEAP: bool = false;
pub(crate) fn get() -> Option<ThreadId> {
let id0 = ID0.get().addr() as u64;
let id16 = ID16.get().addr() as u64;
let id32 = ID32.get().addr() as u64;
let id48 = ID48.get().addr() as u64;
ThreadId::from_u64((id48 << 48) + (id32 << 32) + (id16 << 16) + id0)
}
pub(super) fn set(id: ThreadId) {
let val = id.as_u64().get();
ID0.set(ptr::without_provenance_mut(val as usize));
ID16.set(ptr::without_provenance_mut((val >> 16) as usize));
ID32.set(ptr::without_provenance_mut((val >> 32) as usize));
ID48.set(ptr::without_provenance_mut((val >> 48) as usize));
}
}
target_pointer_width = "32" => {
local_pointer! {
static ID0;
static ID32;
}
pub(super) const CHEAP: bool = false;
pub(crate) fn get() -> Option<ThreadId> {
let id0 = ID0.get().addr() as u64;
let id32 = ID32.get().addr() as u64;
ThreadId::from_u64((id32 << 32) + id0)
}
pub(super) fn set(id: ThreadId) {
let val = id.as_u64().get();
ID0.set(ptr::without_provenance_mut(val as usize));
ID32.set(ptr::without_provenance_mut((val >> 32) as usize));
}
}
_ => {
local_pointer! {
static ID;
}
pub(super) const CHEAP: bool = true;
pub(crate) fn get() -> Option<ThreadId> {
let id = ID.get().addr() as u64;
ThreadId::from_u64(id)
}
pub(super) fn set(id: ThreadId) {
let val = id.as_u64().get();
ID.set(ptr::without_provenance_mut(val as usize));
}
}
}
#[inline]
pub(super) fn get_or_init() -> ThreadId {
get().unwrap_or_else(
#[cold]
|| {
let id = ThreadId::new();
id::set(id);
id
},
)
}
}
/// Tries to set the thread handle for the current thread. Fails if a handle was
/// already set or if the thread ID of `thread` would change an already-set ID.
pub(super) fn set_current(thread: Thread) -> Result<(), Thread> {
if CURRENT.get() != NONE {
return Err(thread);
}
match id::get() {
Some(id) if id == thread.id() => {}
None => id::set(thread.id()),
_ => return Err(thread),
}
// Make sure that `crate::rt::thread_cleanup` will be run, which will
// call `drop_current`.
crate::sys::thread_local::guard::enable();
CURRENT.set(thread.into_raw().cast_mut());
Ok(())
}
/// Gets the unique identifier of the thread which invokes it.
///
/// Calling this function may be more efficient than accessing the current
/// thread id through the current thread handle. i.e. `thread::current().id()`.
///
/// This function will always succeed, will always return the same value for
/// one thread and is guaranteed not to call the global allocator.
///
/// # Examples
///
/// ```
/// #![feature(current_thread_id)]
///
/// use std::thread;
///
/// let other_thread = thread::spawn(|| {
/// thread::current_id()
/// });
///
/// let other_thread_id = other_thread.join().unwrap();
/// assert_ne!(thread::current_id(), other_thread_id);
/// ```
#[inline]
#[must_use]
#[unstable(feature = "current_thread_id", issue = "147194")]
pub fn current_id() -> ThreadId {
// If accessing the persistent thread ID takes multiple TLS accesses, try
// to retrieve it from the current thread handle, which will only take one
// TLS access.
if !id::CHEAP {
if let Some(id) = try_with_current(|t| t.map(|t| t.id())) {
return id;
}
}
id::get_or_init()
}
/// Gets the OS thread ID of the thread that invokes it, if available. If not, return the Rust
/// thread ID.
///
/// We use a `u64` to all possible platform IDs without excess `cfg`; most use `int`, some use a
/// pointer, and Apple uses `uint64_t`. This is a "best effort" approach for diagnostics and is
/// allowed to fall back to a non-OS ID (such as the Rust thread ID) or a non-unique ID (such as a
/// PID) if the thread ID cannot be retrieved.
pub(crate) fn current_os_id() -> u64 {
imp::current_os_id().unwrap_or_else(|| current_id().as_u64().get())
}
/// Gets a reference to the handle of the thread that invokes it, if the handle
/// has been initialized.
fn try_with_current<F, R>(f: F) -> R
where
F: FnOnce(Option<&Thread>) -> R,
{
let current = CURRENT.get();
if current > DESTROYED {
// SAFETY: `Arc` does not contain interior mutability, so it does not
// matter that the address of the handle might be different depending
// on where this is called.
unsafe {
let current = ManuallyDrop::new(Thread::from_raw(current));
f(Some(&current))
}
} else {
f(None)
}
}
/// Run a function with the current thread's name.
///
/// Modulo thread local accesses, this function is safe to call from signal
/// handlers and in similar circumstances where allocations are not possible.
pub(crate) fn with_current_name<F, R>(f: F) -> R
where
F: FnOnce(Option<&str>) -> R,
{
try_with_current(|thread| {
let name = if let Some(thread) = thread {
// If there is a current thread handle, try to use the name stored
// there.
thread.name()
} else if let Some(main) = main_thread::get()
&& let Some(id) = id::get()
&& id == main
{
// The main thread doesn't always have a thread handle, we must
// identify it through its ID instead. The checks are ordered so
// that the current ID is only loaded if it is actually needed,
// since loading it from TLS might need multiple expensive accesses.
Some("main")
} else {
None
};
f(name)
})
}
/// Gets a handle to the thread that invokes it. If the handle stored in thread-
/// local storage was already destroyed, this creates a new unnamed temporary
/// handle to allow thread parking in nearly all situations.
pub(crate) fn current_or_unnamed() -> Thread {
let current = CURRENT.get();
if current > DESTROYED {
unsafe {
let current = ManuallyDrop::new(Thread::from_raw(current));
(*current).clone()
}
} else if current == DESTROYED {
Thread::new(id::get_or_init(), None)
} else {
init_current(current)
}
}
/// Gets a handle to the thread that invokes it.
///
/// # Examples
///
/// Getting a handle to the current thread with `thread::current()`:
///
/// ```
/// use std::thread;
///
/// let handler = thread::Builder::new()
/// .name("named thread".into())
/// .spawn(|| {
/// let handle = thread::current();
/// assert_eq!(handle.name(), Some("named thread"));
/// })
/// .unwrap();
///
/// handler.join().unwrap();
/// ```
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn current() -> Thread {
let current = CURRENT.get();
if current > DESTROYED {
unsafe {
let current = ManuallyDrop::new(Thread::from_raw(current));
(*current).clone()
}
} else {
init_current(current)
}
}
#[cold]
fn init_current(current: *mut ()) -> Thread {
if current == NONE {
CURRENT.set(BUSY);
// If the thread ID was initialized already, use it.
let id = id::get_or_init();
let thread = Thread::new(id, None);
// Make sure that `crate::rt::thread_cleanup` will be run, which will
// call `drop_current`.
crate::sys::thread_local::guard::enable();
CURRENT.set(thread.clone().into_raw().cast_mut());
thread
} else if current == BUSY {
// BUSY exists solely for this check, but as it is in the slow path, the
// extra TLS write above shouldn't matter. The alternative is nearly always
// a stack overflow.
//
// If we reach this point it means our initialization routine ended up
// calling current() either directly, or indirectly through the global
// allocator, which is a bug either way as we may not call the global
// allocator in current().
rtabort!(
"init_current() was re-entrant, which indicates a bug in the Rust threading implementation"
)
} else {
debug_assert_eq!(current, DESTROYED);
panic!(
"use of std::thread::current() is not possible after the thread's \
local data has been destroyed"
)
}
}
/// This should be run in [`crate::rt::thread_cleanup`] to reset the thread
/// handle.
pub(crate) fn drop_current() {
let current = CURRENT.get();
if current > DESTROYED {
unsafe {
CURRENT.set(DESTROYED);
drop(Thread::from_raw(current));
}
}
}

View File

@@ -0,0 +1,692 @@
//! Free functions.
use super::builder::Builder;
use super::current::current;
use super::join_handle::JoinHandle;
use crate::mem::forget;
use crate::num::NonZero;
use crate::sys::thread as imp;
use crate::time::{Duration, Instant};
use crate::io;use core::panicking;
/// Spawns a new thread, returning a [`JoinHandle`] for it.
///
/// The join handle provides a [`join`] method that can be used to join the spawned
/// thread. If the spawned thread panics, [`join`] will return an [`Err`] containing
/// the argument given to [`panic!`].
///
/// If the join handle is dropped, the spawned thread will implicitly be *detached*.
/// In this case, the spawned thread may no longer be joined.
/// (It is the responsibility of the program to either eventually join threads it
/// creates or detach them; otherwise, a resource leak will result.)
///
/// This function creates a thread with the default parameters of [`Builder`].
/// To specify the new thread's stack size or the name, use [`Builder::spawn`].
///
/// As you can see in the signature of `spawn` there are two constraints on
/// both the closure given to `spawn` and its return value, let's explain them:
///
/// - The `'static` constraint means that the closure and its return value
/// must have a lifetime of the whole program execution. The reason for this
/// is that threads can outlive the lifetime they have been created in.
///
/// Indeed if the thread, and by extension its return value, can outlive their
/// caller, we need to make sure that they will be valid afterwards, and since
/// we *can't* know when it will return we need to have them valid as long as
/// possible, that is until the end of the program, hence the `'static`
/// lifetime.
/// - The [`Send`] constraint is because the closure will need to be passed
/// *by value* from the thread where it is spawned to the new thread. Its
/// return value will need to be passed from the new thread to the thread
/// where it is `join`ed.
/// As a reminder, the [`Send`] marker trait expresses that it is safe to be
/// passed from thread to thread. [`Sync`] expresses that it is safe to have a
/// reference be passed from thread to thread.
///
/// # Panics
///
/// Panics if the OS fails to create a thread; use [`Builder::spawn`]
/// to recover from such errors.
///
/// # Examples
///
/// Creating a thread.
///
/// ```
/// use std::thread;
///
/// let handler = thread::spawn(|| {
/// // thread code
/// });
///
/// handler.join().unwrap();
/// ```
///
/// As mentioned in the module documentation, threads are usually made to
/// communicate using [`channels`], here is how it usually looks.
///
/// This example also shows how to use `move`, in order to give ownership
/// of values to a thread.
///
/// ```
/// use std::thread;
/// use std::sync::mpsc::channel;
///
/// let (tx, rx) = channel();
///
/// let sender = thread::spawn(move || {
/// tx.send("Hello, thread".to_owned())
/// .expect("Unable to send on channel");
/// });
///
/// let receiver = thread::spawn(move || {
/// let value = rx.recv().expect("Unable to receive from channel");
/// println!("{value}");
/// });
///
/// sender.join().expect("The sender thread has panicked");
/// receiver.join().expect("The receiver thread has panicked");
/// ```
///
/// A thread can also return a value through its [`JoinHandle`], you can use
/// this to make asynchronous computations (futures might be more appropriate
/// though).
///
/// ```
/// use std::thread;
///
/// let computation = thread::spawn(|| {
/// // Some expensive computation.
/// 42
/// });
///
/// let result = computation.join().unwrap();
/// println!("{result}");
/// ```
///
/// # Notes
///
/// This function has the same minimal guarantee regarding "foreign" unwinding operations (e.g.
/// an exception thrown from C++ code, or a `panic!` in Rust code compiled or linked with a
/// different runtime) as [`catch_unwind`]; namely, if the thread created with `thread::spawn`
/// unwinds all the way to the root with such an exception, one of two behaviors are possible,
/// and it is unspecified which will occur:
///
/// * The process aborts.
/// * The process does not abort, and [`join`] will return a `Result::Err`
/// containing an opaque type.
///
/// [`catch_unwind`]: ../../std/panic/fn.catch_unwind.html
/// [`channels`]: crate::sync::mpsc
/// [`join`]: JoinHandle::join
/// [`Err`]: crate::result::Result::Err
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub fn spawn<F, T>(f: F) -> JoinHandle<T>
where
F: FnOnce() -> T,
F: Send + 'static,
T: Send + 'static,
{
Builder::new().spawn(f).expect("failed to spawn thread")
}
/// Cooperatively gives up a timeslice to the OS scheduler.
///
/// This calls the underlying OS scheduler's yield primitive, signaling
/// that the calling thread is willing to give up its remaining timeslice
/// so that the OS may schedule other threads on the CPU.
///
/// A drawback of yielding in a loop is that if the OS does not have any
/// other ready threads to run on the current CPU, the thread will effectively
/// busy-wait, which wastes CPU time and energy.
///
/// Therefore, when waiting for events of interest, a programmer's first
/// choice should be to use synchronization devices such as [`channel`]s,
/// [`Condvar`]s, [`Mutex`]es or [`join`] since these primitives are
/// implemented in a blocking manner, giving up the CPU until the event
/// of interest has occurred which avoids repeated yielding.
///
/// `yield_now` should thus be used only rarely, mostly in situations where
/// repeated polling is required because there is no other suitable way to
/// learn when an event of interest has occurred.
///
/// # Examples
///
/// ```
/// use std::thread;
///
/// thread::yield_now();
/// ```
///
/// [`channel`]: crate::sync::mpsc
/// [`join`]: JoinHandle::join
/// [`Condvar`]: crate::sync::Condvar
/// [`Mutex`]: crate::sync::Mutex
#[stable(feature = "rust1", since = "1.0.0")]
pub fn yield_now() {
imp::yield_now()
}
/// Determines whether the current thread is unwinding because of panic.
///
/// A common use of this feature is to poison shared resources when writing
/// unsafe code, by checking `panicking` when the `drop` is called.
///
/// This is usually not needed when writing safe code, as [`Mutex`es][Mutex]
/// already poison themselves when a thread panics while holding the lock.
///
/// This can also be used in multithreaded applications, in order to send a
/// message to other threads warning that a thread has panicked (e.g., for
/// monitoring purposes).
///
/// # Examples
///
/// ```should_panic
/// use std::thread;
///
/// struct SomeStruct;
///
/// impl Drop for SomeStruct {
/// fn drop(&mut self) {
/// if thread::panicking() {
/// println!("dropped while unwinding");
/// } else {
/// println!("dropped while not unwinding");
/// }
/// }
/// }
///
/// {
/// print!("a: ");
/// let a = SomeStruct;
/// }
///
/// {
/// print!("b: ");
/// let b = SomeStruct;
/// panic!()
/// }
/// ```
///
/// [Mutex]: crate::sync::Mutex
#[inline]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn panicking() -> bool {
panicking::panicking()
}
/// Uses [`sleep`].
///
/// Puts the current thread to sleep for at least the specified amount of time.
///
/// The thread may sleep longer than the duration specified due to scheduling
/// specifics or platform-dependent functionality. It will never sleep less.
///
/// This function is blocking, and should not be used in `async` functions.
///
/// # Platform-specific behavior
///
/// On Unix platforms, the underlying syscall may be interrupted by a
/// spurious wakeup or signal handler. To ensure the sleep occurs for at least
/// the specified duration, this function may invoke that system call multiple
/// times.
///
/// # Examples
///
/// ```no_run
/// use std::thread;
///
/// // Let's sleep for 2 seconds:
/// thread::sleep_ms(2000);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[deprecated(since = "1.6.0", note = "replaced by `std::thread::sleep`")]
pub fn sleep_ms(ms: u32) {
sleep(Duration::from_millis(ms as u64))
}
/// Puts the current thread to sleep for at least the specified amount of time.
///
/// The thread may sleep longer than the duration specified due to scheduling
/// specifics or platform-dependent functionality. It will never sleep less.
///
/// This function is blocking, and should not be used in `async` functions.
///
/// # Platform-specific behavior
///
/// On Unix platforms, the underlying syscall may be interrupted by a
/// spurious wakeup or signal handler. To ensure the sleep occurs for at least
/// the specified duration, this function may invoke that system call multiple
/// times.
/// Platforms which do not support nanosecond precision for sleeping will
/// have `dur` rounded up to the nearest granularity of time they can sleep for.
///
/// Currently, specifying a zero duration on Unix platforms returns immediately
/// without invoking the underlying [`nanosleep`] syscall, whereas on Windows
/// platforms the underlying [`Sleep`] syscall is always invoked.
/// If the intention is to yield the current time-slice you may want to use
/// [`yield_now`] instead.
///
/// [`nanosleep`]: https://linux.die.net/man/2/nanosleep
/// [`Sleep`]: https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-sleep
///
/// # Examples
///
/// ```no_run
/// use std::{thread, time};
///
/// let ten_millis = time::Duration::from_millis(10);
/// let now = time::Instant::now();
///
/// thread::sleep(ten_millis);
///
/// assert!(now.elapsed() >= ten_millis);
/// ```
#[stable(feature = "thread_sleep", since = "1.4.0")]
pub fn sleep(dur: Duration) {
imp::sleep(dur)
}
/// Puts the current thread to sleep until the specified deadline has passed.
///
/// The thread may still be asleep after the deadline specified due to
/// scheduling specifics or platform-dependent functionality. It will never
/// wake before.
///
/// This function is blocking, and should not be used in `async` functions.
///
/// # Platform-specific behavior
///
/// In most cases this function will call an OS specific function. Where that
/// is not supported [`sleep`] is used. Those platforms are referred to as other
/// in the table below.
///
/// # Underlying System calls
///
/// The following system calls are [currently] being used:
///
/// | Platform | System call |
/// |-----------|----------------------------------------------------------------------|
/// | Linux | [clock_nanosleep] (Monotonic clock) |
/// | BSD except OpenBSD | [clock_nanosleep] (Monotonic Clock)] |
/// | Android | [clock_nanosleep] (Monotonic Clock)] |
/// | Solaris | [clock_nanosleep] (Monotonic Clock)] |
/// | Illumos | [clock_nanosleep] (Monotonic Clock)] |
/// | Dragonfly | [clock_nanosleep] (Monotonic Clock)] |
/// | Hurd | [clock_nanosleep] (Monotonic Clock)] |
/// | Vxworks | [clock_nanosleep] (Monotonic Clock)] |
/// | Apple | `mach_wait_until` |
/// | Other | `sleep_until` uses [`sleep`] and does not issue a syscall itself |
///
/// [currently]: crate::io#platform-specific-behavior
/// [clock_nanosleep]: https://linux.die.net/man/3/clock_nanosleep
///
/// **Disclaimer:** These system calls might change over time.
///
/// # Examples
///
/// A simple game loop that limits the game to 60 frames per second.
///
/// ```no_run
/// #![feature(thread_sleep_until)]
/// # use std::time::{Duration, Instant};
/// # use std::thread;
/// #
/// # fn update() {}
/// # fn render() {}
/// #
/// let max_fps = 60.0;
/// let frame_time = Duration::from_secs_f32(1.0/max_fps);
/// let mut next_frame = Instant::now();
/// loop {
/// thread::sleep_until(next_frame);
/// next_frame += frame_time;
/// update();
/// render();
/// }
/// ```
///
/// A slow API we must not call too fast and which takes a few
/// tries before succeeding. By using `sleep_until` the time the
/// API call takes does not influence when we retry or when we give up
///
/// ```no_run
/// #![feature(thread_sleep_until)]
/// # use std::time::{Duration, Instant};
/// # use std::thread;
/// #
/// # enum Status {
/// # Ready(usize),
/// # Waiting,
/// # }
/// # fn slow_web_api_call() -> Status { Status::Ready(42) }
/// #
/// # const MAX_DURATION: Duration = Duration::from_secs(10);
/// #
/// # fn try_api_call() -> Result<usize, ()> {
/// let deadline = Instant::now() + MAX_DURATION;
/// let delay = Duration::from_millis(250);
/// let mut next_attempt = Instant::now();
/// loop {
/// if Instant::now() > deadline {
/// break Err(());
/// }
/// if let Status::Ready(data) = slow_web_api_call() {
/// break Ok(data);
/// }
///
/// next_attempt = deadline.min(next_attempt + delay);
/// thread::sleep_until(next_attempt);
/// }
/// # }
/// # let _data = try_api_call();
/// ```
#[unstable(feature = "thread_sleep_until", issue = "113752")]
pub fn sleep_until(deadline: Instant) {
imp::sleep_until(deadline)
}
/// Used to ensure that `park` and `park_timeout` do not unwind, as that can
/// cause undefined behavior if not handled correctly (see #102398 for context).
struct PanicGuard;
impl Drop for PanicGuard {
fn drop(&mut self) {
rtabort!("an irrecoverable error occurred while synchronizing threads")
}
}
/// Blocks unless or until the current thread's token is made available.
///
/// A call to `park` does not guarantee that the thread will remain parked
/// forever, and callers should be prepared for this possibility. However,
/// it is guaranteed that this function will not panic (it may abort the
/// process if the implementation encounters some rare errors).
///
/// # `park` and `unpark`
///
/// Every thread is equipped with some basic low-level blocking support, via the
/// [`thread::park`][`park`] function and [`thread::Thread::unpark`][`unpark`]
/// method. [`park`] blocks the current thread, which can then be resumed from
/// another thread by calling the [`unpark`] method on the blocked thread's
/// handle.
///
/// Conceptually, each [`Thread`] handle has an associated token, which is
/// initially not present:
///
/// * The [`thread::park`][`park`] function blocks the current thread unless or
/// until the token is available for its thread handle, at which point it
/// atomically consumes the token. It may also return *spuriously*, without
/// consuming the token. [`thread::park_timeout`] does the same, but allows
/// specifying a maximum time to block the thread for.
///
/// * The [`unpark`] method on a [`Thread`] atomically makes the token available
/// if it wasn't already. Because the token can be held by a thread even if it is currently not
/// parked, [`unpark`] followed by [`park`] will result in the second call returning immediately.
/// However, note that to rely on this guarantee, you need to make sure that your `unpark` happens
/// after all `park` that may be done by other data structures!
///
/// The API is typically used by acquiring a handle to the current thread, placing that handle in a
/// shared data structure so that other threads can find it, and then `park`ing in a loop. When some
/// desired condition is met, another thread calls [`unpark`] on the handle. The last bullet point
/// above guarantees that even if the `unpark` occurs before the thread is finished `park`ing, it
/// will be woken up properly.
///
/// Note that the coordination via the shared data structure is crucial: If you `unpark` a thread
/// without first establishing that it is about to be `park`ing within your code, that `unpark` may
/// get consumed by a *different* `park` in the same thread, leading to a deadlock. This also means
/// you must not call unknown code between setting up for parking and calling `park`; for instance,
/// if you invoke `println!`, that may itself call `park` and thus consume your `unpark` and cause a
/// deadlock.
///
/// The motivation for this design is twofold:
///
/// * It avoids the need to allocate mutexes and condvars when building new
/// synchronization primitives; the threads already provide basic
/// blocking/signaling.
///
/// * It can be implemented very efficiently on many platforms.
///
/// # Memory Ordering
///
/// Calls to `unpark` _synchronize-with_ calls to `park`, meaning that memory
/// operations performed before a call to `unpark` are made visible to the thread that
/// consumes the token and returns from `park`. Note that all `park` and `unpark`
/// operations for a given thread form a total order and _all_ prior `unpark` operations
/// synchronize-with `park`.
///
/// In atomic ordering terms, `unpark` performs a `Release` operation and `park`
/// performs the corresponding `Acquire` operation. Calls to `unpark` for the same
/// thread form a [release sequence].
///
/// Note that being unblocked does not imply a call was made to `unpark`, because
/// wakeups can also be spurious. For example, a valid, but inefficient,
/// implementation could have `park` and `unpark` return immediately without doing anything,
/// making *all* wakeups spurious.
///
/// # Examples
///
/// ```
/// use std::thread;
/// use std::sync::atomic::{Ordering, AtomicBool};
/// use std::time::Duration;
///
/// static QUEUED: AtomicBool = AtomicBool::new(false);
/// static FLAG: AtomicBool = AtomicBool::new(false);
///
/// let parked_thread = thread::spawn(move || {
/// println!("Thread spawned");
/// // Signal that we are going to `park`. Between this store and our `park`, there may
/// // be no other `park`, or else that `park` could consume our `unpark` token!
/// QUEUED.store(true, Ordering::Release);
/// // We want to wait until the flag is set. We *could* just spin, but using
/// // park/unpark is more efficient.
/// while !FLAG.load(Ordering::Acquire) {
/// // We can *not* use `println!` here since that could use thread parking internally.
/// thread::park();
/// // We *could* get here spuriously, i.e., way before the 10ms below are over!
/// // But that is no problem, we are in a loop until the flag is set anyway.
/// }
/// println!("Flag received");
/// });
///
/// // Let some time pass for the thread to be spawned.
/// thread::sleep(Duration::from_millis(10));
///
/// // Ensure the thread is about to park.
/// // This is crucial! It guarantees that the `unpark` below is not consumed
/// // by some other code in the parked thread (e.g. inside `println!`).
/// while !QUEUED.load(Ordering::Acquire) {
/// // Spinning is of course inefficient; in practice, this would more likely be
/// // a dequeue where we have no work to do if there's nobody queued.
/// std::hint::spin_loop();
/// }
///
/// // Set the flag, and let the thread wake up.
/// // There is no race condition here: if `unpark`
/// // happens first, `park` will return immediately.
/// // There is also no other `park` that could consume this token,
/// // since we waited until the other thread got queued.
/// // Hence there is no risk of a deadlock.
/// FLAG.store(true, Ordering::Release);
/// println!("Unpark the thread");
/// parked_thread.thread().unpark();
///
/// parked_thread.join().unwrap();
/// ```
///
/// [`Thread`]: super::Thread
/// [`unpark`]: super::Thread::unpark
/// [`thread::park_timeout`]: park_timeout
/// [release sequence]: https://en.cppreference.com/w/cpp/atomic/memory_order#Release_sequence
#[stable(feature = "rust1", since = "1.0.0")]
pub fn park() {
let guard = PanicGuard;
// SAFETY: park_timeout is called on the parker owned by this thread.
unsafe {
current().park();
}
// No panic occurred, do not abort.
forget(guard);
}
/// Uses [`park_timeout`].
///
/// Blocks unless or until the current thread's token is made available or
/// the specified duration has been reached (may wake spuriously).
///
/// The semantics of this function are equivalent to [`park`] except
/// that the thread will be blocked for roughly no longer than `dur`. This
/// method should not be used for precise timing due to anomalies such as
/// preemption or platform differences that might not cause the maximum
/// amount of time waited to be precisely `ms` long.
///
/// See the [park documentation][`park`] for more detail.
#[stable(feature = "rust1", since = "1.0.0")]
#[deprecated(since = "1.6.0", note = "replaced by `std::thread::park_timeout`")]
pub fn park_timeout_ms(ms: u32) {
park_timeout(Duration::from_millis(ms as u64))
}
/// Blocks unless or until the current thread's token is made available or
/// the specified duration has been reached (may wake spuriously).
///
/// The semantics of this function are equivalent to [`park`][park] except
/// that the thread will be blocked for roughly no longer than `dur`. This
/// method should not be used for precise timing due to anomalies such as
/// preemption or platform differences that might not cause the maximum
/// amount of time waited to be precisely `dur` long.
///
/// See the [park documentation][park] for more details.
///
/// # Platform-specific behavior
///
/// Platforms which do not support nanosecond precision for sleeping will have
/// `dur` rounded up to the nearest granularity of time they can sleep for.
///
/// # Examples
///
/// Waiting for the complete expiration of the timeout:
///
/// ```rust,no_run
/// use std::thread::park_timeout;
/// use std::time::{Instant, Duration};
///
/// let timeout = Duration::from_secs(2);
/// let beginning_park = Instant::now();
///
/// let mut timeout_remaining = timeout;
/// loop {
/// park_timeout(timeout_remaining);
/// let elapsed = beginning_park.elapsed();
/// if elapsed >= timeout {
/// break;
/// }
/// println!("restarting park_timeout after {elapsed:?}");
/// timeout_remaining = timeout - elapsed;
/// }
/// ```
#[stable(feature = "park_timeout", since = "1.4.0")]
pub fn park_timeout(dur: Duration) {
let guard = PanicGuard;
// SAFETY: park_timeout is called on a handle owned by this thread.
unsafe {
current().park_timeout(dur);
}
// No panic occurred, do not abort.
forget(guard);
}
/// Returns an estimate of the default amount of parallelism a program should use.
///
/// Parallelism is a resource. A given machine provides a certain capacity for
/// parallelism, i.e., a bound on the number of computations it can perform
/// simultaneously. This number often corresponds to the amount of CPUs a
/// computer has, but it may diverge in various cases.
///
/// Host environments such as VMs or container orchestrators may want to
/// restrict the amount of parallelism made available to programs in them. This
/// is often done to limit the potential impact of (unintentionally)
/// resource-intensive programs on other programs running on the same machine.
///
/// # Limitations
///
/// The purpose of this API is to provide an easy and portable way to query
/// the default amount of parallelism the program should use. Among other things it
/// does not expose information on NUMA regions, does not account for
/// differences in (co)processor capabilities or current system load,
/// and will not modify the program's global state in order to more accurately
/// query the amount of available parallelism.
///
/// Where both fixed steady-state and burst limits are available the steady-state
/// capacity will be used to ensure more predictable latencies.
///
/// Resource limits can be changed during the runtime of a program, therefore the value is
/// not cached and instead recomputed every time this function is called. It should not be
/// called from hot code.
///
/// The value returned by this function should be considered a simplified
/// approximation of the actual amount of parallelism available at any given
/// time. To get a more detailed or precise overview of the amount of
/// parallelism available to the program, you may wish to use
/// platform-specific APIs as well. The following platform limitations currently
/// apply to `available_parallelism`:
///
/// On Windows:
/// - It may undercount the amount of parallelism available on systems with more
/// than 64 logical CPUs. However, programs typically need specific support to
/// take advantage of more than 64 logical CPUs, and in the absence of such
/// support, the number returned by this function accurately reflects the
/// number of logical CPUs the program can use by default.
/// - It may overcount the amount of parallelism available on systems limited by
/// process-wide affinity masks, or job object limitations.
///
/// On Linux:
/// - It may overcount the amount of parallelism available when limited by a
/// process-wide affinity mask or cgroup quotas and `sched_getaffinity()` or cgroup fs can't be
/// queried, e.g. due to sandboxing.
/// - It may undercount the amount of parallelism if the current thread's affinity mask
/// does not reflect the process' cpuset, e.g. due to pinned threads.
/// - If the process is in a cgroup v1 cpu controller, this may need to
/// scan mountpoints to find the corresponding cgroup v1 controller,
/// which may take time on systems with large numbers of mountpoints.
/// (This does not apply to cgroup v2, or to processes not in a
/// cgroup.)
/// - It does not attempt to take `ulimit` into account. If there is a limit set on the number of
/// threads, `available_parallelism` cannot know how much of that limit a Rust program should
/// take, or know in a reliable and race-free way how much of that limit is already taken.
///
/// On all targets:
/// - It may overcount the amount of parallelism available when running in a VM
/// with CPU usage limits (e.g. an overcommitted host).
///
/// # Errors
///
/// This function will, but is not limited to, return errors in the following
/// cases:
///
/// - If the amount of parallelism is not known for the target platform.
/// - If the program lacks permission to query the amount of parallelism made
/// available to it.
///
/// # Examples
///
/// ```
/// # #![allow(dead_code)]
/// use std::{io, thread};
///
/// fn main() -> io::Result<()> {
/// let count = thread::available_parallelism()?.get();
/// assert!(count >= 1_usize);
/// Ok(())
/// }
/// ```
#[doc(alias = "available_concurrency")] // Alias for a previous name we gave this API on unstable.
#[doc(alias = "hardware_concurrency")] // Alias for C++ `std::thread::hardware_concurrency`.
#[doc(alias = "num_cpus")] // Alias for a popular ecosystem crate which provides similar functionality.
#[stable(feature = "available_parallelism", since = "1.59.0")]
pub fn available_parallelism() -> io::Result<NonZero<usize>> {
imp::available_parallelism()
}

120
crates/std/src/thread/id.rs Normal file
View File

@@ -0,0 +1,120 @@
use crate::num::NonZero;
use crate::sync::atomic::{Atomic, Ordering};
/// A unique identifier for a running thread.
///
/// A `ThreadId` is an opaque object that uniquely identifies each thread
/// created during the lifetime of a process. `ThreadId`s are guaranteed not to
/// be reused, even when a thread terminates. `ThreadId`s are under the control
/// of Rust's standard library and there may not be any relationship between
/// `ThreadId` and the underlying platform's notion of a thread identifier --
/// the two concepts cannot, therefore, be used interchangeably. A `ThreadId`
/// can be retrieved from the [`id`] method on a [`Thread`].
///
/// # Examples
///
/// ```
/// use std::thread;
///
/// let other_thread = thread::spawn(|| {
/// thread::current().id()
/// });
///
/// let other_thread_id = other_thread.join().unwrap();
/// assert!(thread::current().id() != other_thread_id);
/// ```
///
/// [`Thread`]: super::Thread
/// [`id`]: super::Thread::id
#[stable(feature = "thread_id", since = "1.19.0")]
#[derive(Eq, PartialEq, Clone, Copy, Hash, Debug)]
pub struct ThreadId(NonZero<u64>);
impl ThreadId {
// Generate a new unique thread ID.
pub(crate) fn new() -> ThreadId {
#[cold]
fn exhausted() -> ! {
panic!("failed to generate unique thread ID: bitspace exhausted")
}
cfg_select! {
target_has_atomic = "64" => {
use crate::sync::atomic::AtomicU64;
static COUNTER: Atomic<u64> = AtomicU64::new(0);
let mut last = COUNTER.load(Ordering::Relaxed);
loop {
let Some(id) = last.checked_add(1) else {
exhausted();
};
match COUNTER.compare_exchange_weak(last, id, Ordering::Relaxed, Ordering::Relaxed) {
Ok(_) => return ThreadId(NonZero::new(id).unwrap()),
Err(id) => last = id,
}
}
}
_ => {
use crate::cell::SyncUnsafeCell;
use crate::hint::spin_loop;
use crate::sync::atomic::AtomicBool;
use crate::thread::yield_now;
// If we don't have a 64-bit atomic we use a small spinlock. We don't use Mutex
// here as we might be trying to get the current thread id in the global allocator,
// and on some platforms Mutex requires allocation.
static COUNTER_LOCKED: Atomic<bool> = AtomicBool::new(false);
static COUNTER: SyncUnsafeCell<u64> = SyncUnsafeCell::new(0);
// Acquire lock.
let mut spin = 0;
// Miri doesn't like it when we yield here as it interferes with deterministically
// scheduling threads, so avoid `compare_exchange_weak` to avoid spurious yields.
while COUNTER_LOCKED.swap(true, Ordering::Acquire) {
if spin <= 3 {
for _ in 0..(1 << spin) {
spin_loop();
}
} else {
yield_now();
}
spin += 1;
}
// This was `false` before the swap, so we got the lock.
// SAFETY: we have an exclusive lock on the counter.
unsafe {
if let Some(id) = (*COUNTER.get()).checked_add(1) {
*COUNTER.get() = id;
COUNTER_LOCKED.store(false, Ordering::Release);
ThreadId(NonZero::new(id).unwrap())
} else {
COUNTER_LOCKED.store(false, Ordering::Release);
exhausted()
}
}
}
}
}
#[cfg(any(not(target_thread_local), target_has_atomic = "64"))]
pub(super) fn from_u64(v: u64) -> Option<ThreadId> {
NonZero::new(v).map(ThreadId)
}
/// This returns a numeric identifier for the thread identified by this
/// `ThreadId`.
///
/// As noted in the documentation for the type itself, it is essentially an
/// opaque ID, but is guaranteed to be unique for each thread. The returned
/// value is entirely opaque -- only equality testing is stable. Note that
/// it is not guaranteed which values new threads will return, and this may
/// change across Rust versions.
#[must_use]
#[unstable(feature = "thread_id_value", issue = "67939")]
pub fn as_u64(&self) -> NonZero<u64> {
self.0
}
}

View File

@@ -0,0 +1,186 @@
use super::Result;
use super::lifecycle::JoinInner;
use super::thread::Thread;
use crate::fmt;
use crate::sys::{AsInner, IntoInner, thread as imp};
/// An owned permission to join on a thread (block on its termination).
///
/// A `JoinHandle` *detaches* the associated thread when it is dropped, which
/// means that there is no longer any handle to the thread and no way to `join`
/// on it.
///
/// Due to platform restrictions, it is not possible to [`Clone`] this
/// handle: the ability to join a thread is a uniquely-owned permission.
///
/// This `struct` is created by the [`thread::spawn`] function and the
/// [`thread::Builder::spawn`] method.
///
/// # Examples
///
/// Creation from [`thread::spawn`]:
///
/// ```
/// use std::thread;
///
/// let join_handle: thread::JoinHandle<_> = thread::spawn(|| {
/// // some work here
/// });
/// ```
///
/// Creation from [`thread::Builder::spawn`]:
///
/// ```
/// use std::thread;
///
/// let builder = thread::Builder::new();
///
/// let join_handle: thread::JoinHandle<_> = builder.spawn(|| {
/// // some work here
/// }).unwrap();
/// ```
///
/// A thread being detached and outliving the thread that spawned it:
///
/// ```no_run
/// use std::thread;
/// use std::time::Duration;
///
/// let original_thread = thread::spawn(|| {
/// let _detached_thread = thread::spawn(|| {
/// // Here we sleep to make sure that the first thread returns before.
/// thread::sleep(Duration::from_millis(10));
/// // This will be called, even though the JoinHandle is dropped.
/// println!("♫ Still alive ♫");
/// });
/// });
///
/// original_thread.join().expect("The thread being joined has panicked");
/// println!("Original thread is joined.");
///
/// // We make sure that the new thread has time to run, before the main
/// // thread returns.
///
/// thread::sleep(Duration::from_millis(1000));
/// ```
///
/// [`thread::Builder::spawn`]: super::Builder::spawn
/// [`thread::spawn`]: super::spawn
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(target_os = "teeos", must_use)]
pub struct JoinHandle<T>(pub(super) JoinInner<'static, T>);
#[stable(feature = "joinhandle_impl_send_sync", since = "1.29.0")]
unsafe impl<T> Send for JoinHandle<T> {}
#[stable(feature = "joinhandle_impl_send_sync", since = "1.29.0")]
unsafe impl<T> Sync for JoinHandle<T> {}
impl<T> JoinHandle<T> {
/// Extracts a handle to the underlying thread.
///
/// # Examples
///
/// ```
/// use std::thread;
///
/// let builder = thread::Builder::new();
///
/// let join_handle: thread::JoinHandle<_> = builder.spawn(|| {
/// // some work here
/// }).unwrap();
///
/// let thread = join_handle.thread();
/// println!("thread id: {:?}", thread.id());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[must_use]
pub fn thread(&self) -> &Thread {
self.0.thread()
}
/// Waits for the associated thread to finish.
///
/// This function will return immediately if the associated thread has already finished.
/// Otherwise, it fully waits for the thread to finish, including all destructors
/// for thread-local variables that might be running after the main function of the thread.
///
/// In terms of [atomic memory orderings], the completion of the associated
/// thread synchronizes with this function returning. In other words, all
/// operations performed by that thread [happen
/// before](https://doc.rust-lang.org/nomicon/atomics.html#data-accesses) all
/// operations that happen after `join` returns.
///
/// If the associated thread panics, [`Err`] is returned with the parameter given
/// to [`panic!`] (though see the Notes below).
///
/// [`Err`]: crate::result::Result::Err
/// [atomic memory orderings]: crate::sync::atomic
///
/// # Panics
///
/// This function may panic on some platforms if a thread attempts to join
/// itself or otherwise may create a deadlock with joining threads.
///
/// # Examples
///
/// ```
/// use std::thread;
///
/// let builder = thread::Builder::new();
///
/// let join_handle: thread::JoinHandle<_> = builder.spawn(|| {
/// // some work here
/// }).unwrap();
/// join_handle.join().expect("Couldn't join on the associated thread");
/// ```
///
/// # Notes
///
/// If a "foreign" unwinding operation (e.g. an exception thrown from C++
/// code, or a `panic!` in Rust code compiled or linked with a different
/// runtime) unwinds all the way to the thread root, the process may be
/// aborted; see the Notes on [`thread::spawn`]. If the process is not
/// aborted, this function will return a `Result::Err` containing an opaque
/// type.
///
/// [`catch_unwind`]: ../../std/panic/fn.catch_unwind.html
/// [`thread::spawn`]: super::spawn
#[stable(feature = "rust1", since = "1.0.0")]
pub fn join(self) -> Result<T> {
self.0.join()
}
/// Checks if the associated thread has finished running its main function.
///
/// `is_finished` supports implementing a non-blocking join operation, by checking
/// `is_finished`, and calling `join` if it returns `true`. This function does not block. To
/// block while waiting on the thread to finish, use [`join`][Self::join].
///
/// This might return `true` for a brief moment after the thread's main
/// function has returned, but before the thread itself has stopped running.
/// However, once this returns `true`, [`join`][Self::join] can be expected
/// to return quickly, without blocking for any significant amount of time.
#[stable(feature = "thread_is_running", since = "1.61.0")]
pub fn is_finished(&self) -> bool {
self.0.is_finished()
}
}
impl<T> AsInner<imp::Thread> for JoinHandle<T> {
fn as_inner(&self) -> &imp::Thread {
self.0.as_inner()
}
}
impl<T> IntoInner<imp::Thread> for JoinHandle<T> {
fn into_inner(self) -> imp::Thread {
self.0.into_inner()
}
}
#[stable(feature = "std_debug", since = "1.16.0")]
impl<T> fmt::Debug for JoinHandle<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("JoinHandle").finish_non_exhaustive()
}
}

View File

@@ -0,0 +1,265 @@
//! The inner logic for thread spawning and joining.
use super::current::set_current;
use super::id::ThreadId;
use super::scoped::ScopeData;
use super::thread::Thread;
use super::{Result, spawnhook};
use crate::cell::UnsafeCell;
use crate::marker::PhantomData;
use crate::mem::{ManuallyDrop, MaybeUninit};
use alloc_crate::sync::Arc;
use crate::sync::atomic::{Atomic, AtomicUsize, Ordering};
use crate::sys::{AsInner, IntoInner, thread as imp};
use crate::{env, io};use core::panic;
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub(super) unsafe fn spawn_unchecked<'scope, F, T>(
name: Option<String>,
stack_size: Option<usize>,
no_hooks: bool,
scope_data: Option<Arc<ScopeData>>,
f: F,
) -> io::Result<JoinInner<'scope, T>>
where
F: FnOnce() -> T,
F: Send,
T: Send,
{
let stack_size = stack_size.unwrap_or_else(|| {
static MIN: Atomic<usize> = AtomicUsize::new(0);
match MIN.load(Ordering::Relaxed) {
0 => {}
n => return n - 1,
}
let amt = env::var_os("RUST_MIN_STACK")
.and_then(|s| s.to_str().and_then(|s| s.parse().ok()))
.unwrap_or(imp::DEFAULT_MIN_STACK_SIZE);
// 0 is our sentinel value, so ensure that we'll never see 0 after
// initialization has run
MIN.store(amt + 1, Ordering::Relaxed);
amt
});
let id = ThreadId::new();
let thread = Thread::new(id, name);
let hooks = if no_hooks {
spawnhook::ChildSpawnHooks::default()
} else {
spawnhook::run_spawn_hooks(&thread)
};
let my_packet: Arc<Packet<'scope, T>> =
Arc::new(Packet { scope: scope_data, result: UnsafeCell::new(None), _marker: PhantomData });
let their_packet = my_packet.clone();
// Pass `f` in `MaybeUninit` because actually that closure might *run longer than the lifetime of `F`*.
// See <https://github.com/rust-lang/rust/issues/101983> for more details.
// To prevent leaks we use a wrapper that drops its contents.
#[repr(transparent)]
struct MaybeDangling<T>(MaybeUninit<T>);
impl<T> MaybeDangling<T> {
fn new(x: T) -> Self {
MaybeDangling(MaybeUninit::new(x))
}
fn into_inner(self) -> T {
// Make sure we don't drop.
let this = ManuallyDrop::new(self);
// SAFETY: we are always initialized.
unsafe { this.0.assume_init_read() }
}
}
impl<T> Drop for MaybeDangling<T> {
fn drop(&mut self) {
// SAFETY: we are always initialized.
unsafe { self.0.assume_init_drop() };
}
}
let f = MaybeDangling::new(f);
// The entrypoint of the Rust thread, after platform-specific thread
// initialization is done.
let rust_start = move || {
let f = f.into_inner();
let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
crate::sys::backtrace::__rust_begin_short_backtrace(|| hooks.run());
crate::sys::backtrace::__rust_begin_short_backtrace(f)
}));
// SAFETY: `their_packet` as been built just above and moved by the
// closure (it is an Arc<...>) and `my_packet` will be stored in the
// same `JoinInner` as this closure meaning the mutation will be
// safe (not modify it and affect a value far away).
unsafe { *their_packet.result.get() = Some(try_result) };
// Here `their_packet` gets dropped, and if this is the last `Arc` for that packet that
// will call `decrement_num_running_threads` and therefore signal that this thread is
// done.
drop(their_packet);
// Here, the lifetime `'scope` can end. `main` keeps running for a bit
// after that before returning itself.
};
if let Some(scope_data) = &my_packet.scope {
scope_data.increment_num_running_threads();
}
// SAFETY: dynamic size and alignment of the Box remain the same. See below for why the
// lifetime change is justified.
let rust_start = unsafe {
let ptr = Box::into_raw(Box::new(rust_start));
let ptr = crate::mem::transmute::<
*mut (dyn FnOnce() + Send + '_),
*mut (dyn FnOnce() + Send + 'static),
>(ptr);
Box::from_raw(ptr)
};
let init = Box::new(ThreadInit { handle: thread.clone(), rust_start });
Ok(JoinInner {
// SAFETY:
//
// `imp::Thread::new` takes a closure with a `'static` lifetime, since it's passed
// through FFI or otherwise used with low-level threading primitives that have no
// notion of or way to enforce lifetimes.
//
// As mentioned in the `Safety` section of this function's documentation, the caller of
// this function needs to guarantee that the passed-in lifetime is sufficiently long
// for the lifetime of the thread.
//
// Similarly, the `sys` implementation must guarantee that no references to the closure
// exist after the thread has terminated, which is signaled by `Thread::join`
// returning.
native: unsafe { imp::Thread::new(stack_size, init)? },
thread,
packet: my_packet,
})
}
/// The data passed to the spawned thread for thread initialization. Any thread
/// implementation should start a new thread by calling .init() on this before
/// doing anything else to ensure the current thread is properly initialized and
/// the global allocator works.
pub(crate) struct ThreadInit {
pub handle: Thread,
pub rust_start: Box<dyn FnOnce() + Send>,
}
impl ThreadInit {
/// Initialize the 'current thread' mechanism on this thread, returning the
/// Rust entry point.
pub fn init(self: Box<Self>) -> Box<dyn FnOnce() + Send> {
// Set the current thread before any (de)allocations on the global allocator occur,
// so that it may call std::thread::current() in its implementation. This is also
// why we take Box<Self>, to ensure the Box is not destroyed until after this point.
// Cloning the handle does not invoke the global allocator, it is an Arc.
if let Err(_thread) = set_current(self.handle.clone()) {
// The current thread should not have set yet. Use an abort to save binary size (see #123356).
rtabort!("current thread handle already set during thread spawn");
}
if let Some(name) = self.handle.cname() {
imp::set_name(name);
}
self.rust_start
}
}
// This packet is used to communicate the return value between the spawned
// thread and the rest of the program. It is shared through an `Arc` and
// there's no need for a mutex here because synchronization happens with `join()`
// (the caller will never read this packet until the thread has exited).
//
// An Arc to the packet is stored into a `JoinInner` which in turns is placed
// in `JoinHandle`.
struct Packet<'scope, T> {
scope: Option<Arc<ScopeData>>,
result: UnsafeCell<Option<Result<T>>>,
_marker: PhantomData<Option<&'scope ScopeData>>,
}
// Due to the usage of `UnsafeCell` we need to manually implement Sync.
// The type `T` should already always be Send (otherwise the thread could not
// have been created) and the Packet is Sync because all access to the
// `UnsafeCell` synchronized (by the `join()` boundary), and `ScopeData` is Sync.
unsafe impl<'scope, T: Send> Sync for Packet<'scope, T> {}
impl<'scope, T> Drop for Packet<'scope, T> {
fn drop(&mut self) {
// If this packet was for a thread that ran in a scope, the thread
// panicked, and nobody consumed the panic payload, we make sure
// the scope function will panic.
let unhandled_panic = matches!(self.result.get_mut(), Some(Err(_)));
// Drop the result without causing unwinding.
// This is only relevant for threads that aren't join()ed, as
// join() will take the `result` and set it to None, such that
// there is nothing left to drop here.
// If this panics, we should handle that, because we're outside the
// outermost `catch_unwind` of our thread.
// We just abort in that case, since there's nothing else we can do.
// (And even if we tried to handle it somehow, we'd also need to handle
// the case where the panic payload we get out of it also panics on
// drop, and so on. See issue #86027.)
if let Err(_) = panic::catch_unwind(panic::AssertUnwindSafe(|| {
*self.result.get_mut() = None;
})) {
rtabort!("thread result panicked on drop");
}
// Book-keeping so the scope knows when it's done.
if let Some(scope) = &self.scope {
// Now that there will be no more user code running on this thread
// that can use 'scope, mark the thread as 'finished'.
// It's important we only do this after the `result` has been dropped,
// since dropping it might still use things it borrowed from 'scope.
scope.decrement_num_running_threads(unhandled_panic);
}
}
}
/// Inner representation for JoinHandle
pub(super) struct JoinInner<'scope, T> {
native: imp::Thread,
thread: Thread,
packet: Arc<Packet<'scope, T>>,
}
impl<'scope, T> JoinInner<'scope, T> {
pub(super) fn is_finished(&self) -> bool {
Arc::strong_count(&self.packet) == 1
}
pub(super) fn thread(&self) -> &Thread {
&self.thread
}
pub(super) fn join(mut self) -> Result<T> {
self.native.join();
Arc::get_mut(&mut self.packet)
// FIXME(fuzzypixelz): returning an error instead of panicking here
// would require updating the documentation of
// `std::thread::Result`; currently we can return `Err` if and only
// if the thread had panicked.
.expect("threads should not terminate unexpectedly")
.result
.get_mut()
.take()
.unwrap()
}
}
impl<T> AsInner<imp::Thread> for JoinInner<'static, T> {
fn as_inner(&self) -> &imp::Thread {
&self.native
}
}
impl<T> IntoInner<imp::Thread> for JoinInner<'static, T> {
fn into_inner(self) -> imp::Thread {
self.native
}
}

View File

@@ -0,0 +1,56 @@
//! Store the ID of the main thread.
//!
//! The thread handle for the main thread is created lazily, and this might even
//! happen pre-main. Since not every platform has a way to identify the main
//! thread when that happens macOS's `pthread_main_np` function being a notable
//! exception we cannot assign it the right name right then. Instead, in our
//! runtime startup code, we remember the thread ID of the main thread (through
//! this modules `set` function) and use it to identify the main thread from then
//! on. This works reliably and has the additional advantage that we can report
//! the right thread name on main even after the thread handle has been destroyed.
//! Note however that this also means that the name reported in pre-main functions
//! will be incorrect, but that's just something we have to live with.
cfg_select! {
target_has_atomic = "64" => {
use super::id::ThreadId;
use crate::sync::atomic::{Atomic, AtomicU64};
use crate::sync::atomic::Ordering::Relaxed;
static MAIN: Atomic<u64> = AtomicU64::new(0);
pub(super) fn get() -> Option<ThreadId> {
ThreadId::from_u64(MAIN.load(Relaxed))
}
/// # Safety
/// May only be called once.
pub(crate) unsafe fn set(id: ThreadId) {
MAIN.store(id.as_u64().get(), Relaxed)
}
}
_ => {
use super::id::ThreadId;
use crate::mem::MaybeUninit;
use crate::sync::atomic::{Atomic, AtomicBool};
use crate::sync::atomic::Ordering::{Acquire, Release};
static INIT: Atomic<bool> = AtomicBool::new(false);
static mut MAIN: MaybeUninit<ThreadId> = MaybeUninit::uninit();
pub(super) fn get() -> Option<ThreadId> {
if INIT.load(Acquire) {
Some(unsafe { MAIN.assume_init() })
} else {
None
}
}
/// # Safety
/// May only be called once.
pub(crate) unsafe fn set(id: ThreadId) {
unsafe { MAIN = MaybeUninit::new(id) };
INIT.store(true, Release);
}
}
}

View File

@@ -0,0 +1,326 @@
use super::id::ThreadId;
use super::main_thread;
use crate::alloc::System;
use crate::ffi::CStr;
use crate::fmt;
use crate::pin::Pin;
use alloc_crate::sync::Arc;
use crate::sys::sync::Parker;
use crate::time::Duration;
// This module ensures private fields are kept private, which is necessary to enforce the safety requirements.
mod thread_name_string {
use crate::ffi::{CStr, CString};
use crate::str;
/// Like a `String` it's guaranteed UTF-8 and like a `CString` it's null terminated.
pub(crate) struct ThreadNameString {
inner: CString,
}
impl From<String> for ThreadNameString {
fn from(s: String) -> Self {
Self {
inner: CString::new(s).expect("thread name may not contain interior null bytes"),
}
}
}
impl ThreadNameString {
pub fn as_cstr(&self) -> &CStr {
&self.inner
}
pub fn as_str(&self) -> &str {
// SAFETY: `ThreadNameString` is guaranteed to be UTF-8.
unsafe { str::from_utf8_unchecked(self.inner.to_bytes()) }
}
}
}
use thread_name_string::ThreadNameString;
/// The internal representation of a `Thread` handle
///
/// We explicitly set the alignment for our guarantee in Thread::into_raw. This
/// allows applications to stuff extra metadata bits into the alignment, which
/// can be rather useful when working with atomics.
#[repr(align(8))]
struct Inner {
name: Option<ThreadNameString>,
id: ThreadId,
parker: Parker,
}
impl Inner {
fn parker(self: Pin<&Self>) -> Pin<&Parker> {
unsafe { Pin::map_unchecked(self, |inner| &inner.parker) }
}
}
#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
/// A handle to a thread.
///
/// Threads are represented via the `Thread` type, which you can get in one of
/// two ways:
///
/// * By spawning a new thread, e.g., using the [`thread::spawn`]
/// function, and calling [`thread`] on the [`JoinHandle`].
/// * By requesting the current thread, using the [`thread::current`] function.
///
/// The [`thread::current`] function is available even for threads not spawned
/// by the APIs of this module.
///
/// There is usually no need to create a `Thread` struct yourself, one
/// should instead use a function like `spawn` to create new threads, see the
/// docs of [`Builder`] and [`spawn`] for more details.
///
/// [`thread::spawn`]: super::spawn
/// [`thread`]: super::JoinHandle::thread
/// [`JoinHandle`]: super::JoinHandle
/// [`thread::current`]: super::current::current
/// [`Builder`]: super::Builder
/// [`spawn`]: super::spawn
pub struct Thread {
// We use the System allocator such that creating or dropping this handle
// does not interfere with a potential Global allocator using thread-local
// storage.
inner: Pin<Arc<Inner, System>>,
}
impl Thread {
pub(crate) fn new(id: ThreadId, name: Option<String>) -> Thread {
let name = name.map(ThreadNameString::from);
// We have to use `unsafe` here to construct the `Parker` in-place,
// which is required for the UNIX implementation.
//
// SAFETY: We pin the Arc immediately after creation, so its address never
// changes.
let inner = unsafe {
let mut arc = Arc::<Inner, _>::new_uninit_in(System);
let ptr = Arc::get_mut_unchecked(&mut arc).as_mut_ptr();
(&raw mut (*ptr).name).write(name);
(&raw mut (*ptr).id).write(id);
Parker::new_in_place(&raw mut (*ptr).parker);
Pin::new_unchecked(arc.assume_init())
};
Thread { inner }
}
/// Like the public [`park`], but callable on any handle. This is used to
/// allow parking in TLS destructors.
///
/// # Safety
/// May only be called from the thread to which this handle belongs.
///
/// [`park`]: super::park
pub(crate) unsafe fn park(&self) {
unsafe { self.inner.as_ref().parker().park() }
}
/// Like the public [`park_timeout`], but callable on any handle. This is
/// used to allow parking in TLS destructors.
///
/// # Safety
/// May only be called from the thread to which this handle belongs.
///
/// [`park_timeout`]: super::park_timeout
pub(crate) unsafe fn park_timeout(&self, dur: Duration) {
unsafe { self.inner.as_ref().parker().park_timeout(dur) }
}
/// Atomically makes the handle's token available if it is not already.
///
/// Every thread is equipped with some basic low-level blocking support, via
/// the [`park`] function and the `unpark()` method. These can be used as a
/// more CPU-efficient implementation of a spinlock.
///
/// See the [park documentation] for more details.
///
/// # Examples
///
/// ```
/// use std::thread;
/// use std::time::Duration;
/// use std::sync::atomic::{AtomicBool, Ordering};
///
/// static QUEUED: AtomicBool = AtomicBool::new(false);
///
/// let parked_thread = thread::Builder::new()
/// .spawn(|| {
/// println!("Parking thread");
/// QUEUED.store(true, Ordering::Release);
/// thread::park();
/// println!("Thread unparked");
/// })
/// .unwrap();
///
/// // Let some time pass for the thread to be spawned.
/// thread::sleep(Duration::from_millis(10));
///
/// // Wait until the other thread is queued.
/// // This is crucial! It guarantees that the `unpark` below is not consumed
/// // by some other code in the parked thread (e.g. inside `println!`).
/// while !QUEUED.load(Ordering::Acquire) {
/// // Spinning is of course inefficient; in practice, this would more likely be
/// // a dequeue where we have no work to do if there's nobody queued.
/// std::hint::spin_loop();
/// }
///
/// println!("Unpark the thread");
/// parked_thread.thread().unpark();
///
/// parked_thread.join().unwrap();
/// ```
///
/// [`park`]: super::park
/// [park documentation]: super::park
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn unpark(&self) {
self.inner.as_ref().parker().unpark();
}
/// Gets the thread's unique identifier.
///
/// # Examples
///
/// ```
/// use std::thread;
///
/// let other_thread = thread::spawn(|| {
/// thread::current().id()
/// });
///
/// let other_thread_id = other_thread.join().unwrap();
/// assert!(thread::current().id() != other_thread_id);
/// ```
#[stable(feature = "thread_id", since = "1.19.0")]
#[must_use]
pub fn id(&self) -> ThreadId {
self.inner.id
}
/// Gets the thread's name.
///
/// For more information about named threads, see
/// [this module-level documentation][naming-threads].
///
/// # Examples
///
/// Threads by default have no name specified:
///
/// ```
/// use std::thread;
///
/// let builder = thread::Builder::new();
///
/// let handler = builder.spawn(|| {
/// assert!(thread::current().name().is_none());
/// }).unwrap();
///
/// handler.join().unwrap();
/// ```
///
/// Thread with a specified name:
///
/// ```
/// use std::thread;
///
/// let builder = thread::Builder::new()
/// .name("foo".into());
///
/// let handler = builder.spawn(|| {
/// assert_eq!(thread::current().name(), Some("foo"))
/// }).unwrap();
///
/// handler.join().unwrap();
/// ```
///
/// [naming-threads]: ./index.html#naming-threads
#[stable(feature = "rust1", since = "1.0.0")]
#[must_use]
pub fn name(&self) -> Option<&str> {
if let Some(name) = &self.inner.name {
Some(name.as_str())
} else if main_thread::get() == Some(self.inner.id) {
Some("main")
} else {
None
}
}
/// Consumes the `Thread`, returning a raw pointer.
///
/// To avoid a memory leak the pointer must be converted
/// back into a `Thread` using [`Thread::from_raw`]. The pointer is
/// guaranteed to be aligned to at least 8 bytes.
///
/// # Examples
///
/// ```
/// #![feature(thread_raw)]
///
/// use std::thread::{self, Thread};
///
/// let thread = thread::current();
/// let id = thread.id();
/// let ptr = Thread::into_raw(thread);
/// unsafe {
/// assert_eq!(Thread::from_raw(ptr).id(), id);
/// }
/// ```
#[unstable(feature = "thread_raw", issue = "97523")]
pub fn into_raw(self) -> *const () {
// Safety: We only expose an opaque pointer, which maintains the `Pin` invariant.
let inner = unsafe { Pin::into_inner_unchecked(self.inner) };
Arc::into_raw_with_allocator(inner).0 as *const ()
}
/// Constructs a `Thread` from a raw pointer.
///
/// The raw pointer must have been previously returned
/// by a call to [`Thread::into_raw`].
///
/// # Safety
///
/// This function is unsafe because improper use may lead
/// to memory unsafety, even if the returned `Thread` is never
/// accessed.
///
/// Creating a `Thread` from a pointer other than one returned
/// from [`Thread::into_raw`] is **undefined behavior**.
///
/// Calling this function twice on the same raw pointer can lead
/// to a double-free if both `Thread` instances are dropped.
#[unstable(feature = "thread_raw", issue = "97523")]
pub unsafe fn from_raw(ptr: *const ()) -> Thread {
// Safety: Upheld by caller.
unsafe {
Thread { inner: Pin::new_unchecked(Arc::from_raw_in(ptr as *const Inner, System)) }
}
}
pub(crate) fn cname(&self) -> Option<&CStr> {
if let Some(name) = &self.inner.name {
Some(name.as_cstr())
} else if main_thread::get() == Some(self.inner.id) {
Some(c"main")
} else {
None
}
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Debug for Thread {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Thread")
.field("id", &self.id())
.field("name", &self.name())
.finish_non_exhaustive()
}
}

View File

@@ -30,6 +30,8 @@ update_std:
@just cp_std "bstr.rs"
@just cp_std "io/error.rs"
@just cp_std "io/error/repr_bitpacked.rs"
@just cp_std "io/error/repr_unpacked.rs"
@just cp_std "io/error/tests.rs"
@just cp_std "io/cursor.rs"
@just cp_std "io/cursor/tests.rs"
@just cp_std "io/prelude.rs"
@@ -37,13 +39,43 @@ update_std:
@just cp_std "io/impls/tests.rs"
@just cp_std "io/tests.rs"
@just cp_std "io/util.rs"
@just cp_std "io/util/tests.rs"
@just cp_std "io/copy.rs"
@just cp_std "io/copy/tests.rs"
@just cp_std "io/pipe.rs"
@just cp_std "io/pipe/tests.rs"
@just cp_std "io/stdio.rs"
@just cp_std "io/buffered/mod.rs"
@just cp_std "io/buffered/bufreader.rs"
@just cp_std "io/buffered/bufreader/buffer.rs"
@just cp_std "io/buffered/bufwriter.rs"
@just cp_std "io/buffered/linewriter.rs"
@just cp_std "io/buffered/linewritershim.rs"
@just cp_std "sync/once.rs"
@just cp_std "sync/once_lock.rs"
@just cp_std "sync/lazy_lock.rs"
@just cp_std "sync/nonpoison.rs"
@just cp_std "sync/nonpoison/condvar.rs"
@just cp_std "sync/nonpoison/mutex.rs"
@just cp_std "sync/nonpoison/rwlock.rs"
@just cp_std "sync/poison.rs"
@just cp_std "sync/poison/condvar.rs"
@just cp_std "sync/poison/mutex.rs"
@just cp_std "sync/poison/rwlock.rs"
@just cp_std "sync/barrier.rs"
@just cp_std "sync/reentrant_lock.rs"
@just cp_std "sync/mpsc.rs"
@just cp_std "sync/mpmc/mod.rs"
@just cp_std "sync/mpmc/array.rs"
@just cp_std "sync/mpmc/context.rs"
@just cp_std "sync/mpmc/counter.rs"
@just cp_std "sync/mpmc/error.rs"
@just cp_std "sync/mpmc/list.rs"
@just cp_std "sync/mpmc/select.rs"
@just cp_std "sync/mpmc/tests.rs"
@just cp_std "sync/mpmc/utils.rs"
@just cp_std "sync/mpmc/waker.rs"
@just cp_std "sync/mpmc/zero.rs"
@just cp_std "hash/mod.rs"
@just cp_std "hash/random.rs"
@just cp_std "num/mod.rs"
@@ -52,6 +84,14 @@ update_std:
@just cp_std "ffi/os_str.rs"
@just cp_std "ffi/os_str/tests.rs"
@just cp_std "thread/local.rs"
@just cp_std "thread/thread.rs"
@just cp_std "thread/id.rs"
@just cp_std "thread/main_thread.rs"
@just cp_std "thread/current.rs"
@just cp_std "thread/join_handle.rs"
@just cp_std "thread/functions.rs"
@just cp_std "thread/lifecycle.rs"
@just cp_std "thread/builder.rs"
@just cp_std "sys/exit.rs"
@just cp_std "sys/env_consts.rs"
@just cp_std "sys/configure_builtins.rs"
@@ -87,6 +127,10 @@ update_std:
@just cp_std "sys/io/is_terminal/unsupported.rs"
@just cp_std "sys/io/kernel_copy/mod.rs"
@just cp_std "sys/io/mod.rs"
@just cp_std "sys/pipe/mod.rs"
@just cp_std "sys/pipe/unsupported.rs"
@just cp_std "sys/stdio/mod.rs"
@just cp_std "sys/stdio/unsupported.rs"
@just insert_target 108 "sys/random/mod.rs"
@just insert_target 125 "sys/random/mod.rs"
@# Copied but edited for the moment

View File

@@ -5,6 +5,9 @@ s|alloc::slice::Join|alloc_crate::slice::Join|g
s|alloc::bstr|alloc_crate::bstr|g
s|alloc::collections::TryReserveError|alloc_crate::collections::TryReserveError|g
s|crate::collections::VecDeque|alloc_crate::collections::VecDeque|g
s|crate::panic|core::panic|g
s|use crate::{io, panicking};|use crate::io;use core::panicking;|g
s|use crate::{env, io, panic};|use crate::{env, io};use core::panic;|g
# /target_os = "xous",/a \ target_os = "survos",
# Ajouter d'autres modifications facilement ici :