The thread local LOCAL_STDOUT and LOCAL_STDERR are only used by the test
crate to capture output from tests when running them in the same process
in differen threads. However, every program will check these variables
on every print, even outside of testing.
This involves allocating a thread local key, and registering a thread
local destructor. This can be somewhat expensive.
This change keeps a global flag (LOCAL_STREAMS) which will be set to
true when either of these local streams is used. (So, effectively only
in test and benchmark runs.) When this flag is off, these thread locals
are not even looked at and therefore will not be initialized on the
first output on every thread, which also means no thread local
destructors will be registered.
The (unsafe) Mutex from sys_common had a rather complicated interface.
You were supposed to call init() manually, unless you could guarantee it
was neither moved nor used reentrantly.
Calling `destroy()` was also optional, although it was unclear if 1)
resources might be leaked or not, and 2) if destroy() should only be
called when `init()` was called.
This allowed for a number of interesting (confusing?) different ways to
use this Mutex, all captured in a single type.
In practice, this type was only ever used in two ways:
1. As a static variable. In this case, neither init() nor destroy() are
called. The variable is never moved, and it is never used
reentrantly. It is only ever locked using the LockGuard, never with
raw_lock.
2. As a Boxed variable. In this case, both init() and destroy() are
called, it will be moved and possibly used reentrantly.
No other combinations are used anywhere in `std`.
This change simplifies things by splitting this Mutex type into
two types matching the two use cases: StaticMutex and MovableMutex.
The interface of both new types is now both safer and simpler. The first
one does not call nor expose init/destroy, and the second one calls
those automatically in its new() and Drop functions. Also, the locking
functions of MovableMutex are no longer unsafe.
Remove std::io::lazy::Lazy in favour of SyncOnceCell
The (internal) std::io::lazy::Lazy was used to lazily initialize the stdout and stdin buffers (and mutexes). It uses atexit() to register a destructor to flush the streams on exit, and mark the streams as 'closed'. Using the stream afterwards would result in a panic.
Stdout uses a LineWriter which contains a BufWriter that will flush the buffer on drop. This one is important to be executed during shutdown, to make sure no buffered output is lost. It also forbids access to stdout afterwards, since the buffer is already flushed and gone.
Stdin uses a BufReader, which does not implement Drop. It simply forgets any previously read data that was not read from the buffer yet. This means that in the case of stdin, the atexit() function's only effect is making stdin inaccessible to the program, such that later accesses result in a panic. This is uncessary, as it'd have been safe to access stdin during shutdown of the program.
---
This change removes the entire io::lazy module in favour of SyncOnceCell. SyncOnceCell's fast path is much faster (a single atomic operation) than locking a sys_common::Mutex on every access like Lazy did.
However, SyncOnceCell does not use atexit() to drop the contained object during shutdown.
As noted above, this is not a problem for stdin. It simply means stdin is now usable during shutdown.
The atexit() call for stdout is moved to the stdio module. Unlike the now-removed Lazy struct, SyncOnceCell does not have a 'gone and unusable' state that panics. Instead of adding this again, this simply replaces the buffer with one with zero capacity. This effectively flushes the old buffer *and* makes any writes afterwards pass through directly without touching a buffer, making print!() available during shutdown without panicking.
---
In addition, because the contents of the SyncOnceCell are no longer dropped, we can now use `&'static` instead of `Arc` in `Stdout` and `Stdin`. This also saves two levels of indirection in `stdin()` and `stdout()`, since Lazy effectively stored a `Box<Arc<T>>`, and SyncOnceCell stores the `T` directly.
Rust vec bench import specific rand::RngCore
Using `RngCore` import for side effects is clearer than `*` which may bring it unnecessary more stuff than needed, it is also more explicit doing so.
@pickfire change `LEN = 16384` (and pos) and `once` instead of `[0].iter()` after this.
@rustbot modify labels: +C-cleanup +A-testsuite
Add `#![feature(const_fn_floating_point_arithmetic)]`
cc #76618
This is a template for splitting up `const_fn` into granular feature gates. I think this will make it easier, both for us and for users, to track stabilization of each individual feature. We don't *have* to do this, however. We could also keep stabilizing things out from under `const_fn`.
cc @rust-lang/wg-const-eval
r? @oli-obk
Explicitly document the size guarantees that Option makes.
Triggered by a discussion on wg-unsafe-code-guidelines about which layouts of `Option<T>` one can guarantee are optimised to a single pointer.
CC @RalfJung
Std/thread: deny unsafe op in unsafe fn
Partial fix of #73904.
This encloses `unsafe` operations in `unsafe fn` in `libstd/thread`.
`@rustbot` modify labels: F-unsafe-block-in-unsafe-fn
It's possible for method resolution to pick this method over a lower
priority stable method, causing compilation errors. Since this method
is permanently unstable, give it a name that is very unlikely to be used
in user code.
Make [].as_[mut_]ptr_range() (unstably) const.
Gated behind `const_ptr_offset`, as suggested by https://github.com/rust-lang/rust/issues/65807#issuecomment-697229404
This also marks `[].as_mut_ptr()` as const, because it's used by `as_mut_ptr_range`. I gated it behind the same feature, because I figured it's not worth adding a separate tracking issue for const `as_mut_ptr`.
BtreeMap: refactoring around edges
Parts chipped off a more daring effort, that the btree benchmarks judge to be performance-neutral.
r? @Mark-Simulacrum
Relax promises about condition variable.
For quite a while now, there have been plans to at some point use parking_lot or some other more efficient implementation of mutexes and condition variables. Right now, Mutex and CondVar both Box the 'real' mutex/condvar inside, to give it a stable address. This was done because implementations like pthread and Windows critical sections may not be moved. More efficient implementations based on futexes, WaitOnAddress, Windows SRW locks, parking_lot, etc. may be moved (while not borrowed), so wouldn't need boxing.
However, not boxing them (which would be great goal to achieve), breaks a promise std currently makes about CondVar. CondVar promises to panic when used with different mutexes, to ensure consistent behaviour on all platforms. To this check, a mutex is considered 'the same' if the address of the 'real mutex' in the Box is the same. This address doesn't change when moving a `std::mutex::Mutex` object, effectively giving it an identity that survives moves of the Mutex object. If we ever switch to a non-boxed version, they no longer carry such an identity, and this check can no longer be made.
Four options:
1. Always box mutexes.
2. Add a `MutexId` similar to `ThreadId`. Making mutexes bigger, and making it hard to ever have a `const fn new` for them.
3. Making the requirement of CondVar stricter: panic if the Mutex object itself moved.
4. Making the promise of CondVar weaker: don't promise to panic.
1, 2, and 3 seem like bad options. This PR updates the documentation for 4.