Skip to content

Commit 8f39b77

Browse files
231: Avoid unnecessary synchronization in `{force,deref}_mut` r=matklad a=danielhenrymantilla - `DerefMut` was not delegating to `force_mut()` (contary to the by-ref APIs); - `Lazy::force_mut` was not taking advantage of exclusive-mutability access, and instead paying shared-mutability access. Mainly, in the `sync` case, it involved atomic operations which are now skipped. Fixes matklad#226 Co-authored-by: Daniel Henry-Mantilla <[email protected]>
2 parents 8c42266 + 060943b commit 8f39b77

File tree

5 files changed

+46
-17
lines changed

5 files changed

+46
-17
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
-
66

7+
## 1.17.2
8+
9+
- Avoid unnecessary synchronization in `Lazy::{force,deref}_mut()`, [#231](https://github.com/matklad/once_cell/pull/231).
10+
711
## 1.17.1
812

913
- Make `OnceRef` implementation compliant with [strict provenance](https://github.com/rust-lang/rust/issues/95228).

Cargo.lock.msrv

Lines changed: 8 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "once_cell"
3-
version = "1.17.1"
3+
version = "1.17.2"
44
authors = ["Aleksey Kladov <[email protected]>"]
55
license = "MIT OR Apache-2.0"
66
edition = "2021"

src/lib.rs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -796,8 +796,14 @@ pub mod unsync {
796796
/// assert_eq!(*lazy, 92);
797797
/// ```
798798
pub fn force_mut(this: &mut Lazy<T, F>) -> &mut T {
799-
Self::force(this);
800-
Self::get_mut(this).unwrap_or_else(|| unreachable!())
799+
if this.cell.get_mut().is_none() {
800+
let value = match this.init.get_mut().take() {
801+
Some(f) => f(),
802+
None => panic!("Lazy instance has previously been poisoned"),
803+
};
804+
this.cell = OnceCell::with_value(value);
805+
}
806+
this.cell.get_mut().unwrap_or_else(|| unreachable!())
801807
}
802808

803809
/// Gets the reference to the result of this lazy value if
@@ -844,8 +850,7 @@ pub mod unsync {
844850

845851
impl<T, F: FnOnce() -> T> DerefMut for Lazy<T, F> {
846852
fn deref_mut(&mut self) -> &mut T {
847-
Lazy::force(self);
848-
self.cell.get_mut().unwrap_or_else(|| unreachable!())
853+
Lazy::force_mut(self)
849854
}
850855
}
851856

@@ -1324,8 +1329,14 @@ pub mod sync {
13241329
/// assert_eq!(Lazy::force_mut(&mut lazy), &mut 92);
13251330
/// ```
13261331
pub fn force_mut(this: &mut Lazy<T, F>) -> &mut T {
1327-
Self::force(this);
1328-
Self::get_mut(this).unwrap_or_else(|| unreachable!())
1332+
if this.cell.get_mut().is_none() {
1333+
let value = match this.init.get_mut().take() {
1334+
Some(f) => f(),
1335+
None => panic!("Lazy instance has previously been poisoned"),
1336+
};
1337+
this.cell = OnceCell::with_value(value);
1338+
}
1339+
this.cell.get_mut().unwrap_or_else(|| unreachable!())
13291340
}
13301341

13311342
/// Gets the reference to the result of this lazy value if
@@ -1372,8 +1383,7 @@ pub mod sync {
13721383

13731384
impl<T, F: FnOnce() -> T> DerefMut for Lazy<T, F> {
13741385
fn deref_mut(&mut self) -> &mut T {
1375-
Lazy::force(self);
1376-
self.cell.get_mut().unwrap_or_else(|| unreachable!())
1386+
Lazy::force_mut(self)
13771387
}
13781388
}
13791389

xtask/src/main.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,21 @@ fn main() -> xshell::Result<()> {
4848
let _s = section("TEST_MSRV");
4949
let _e = push_toolchain(&sh, MSRV)?;
5050
sh.copy_file("Cargo.lock.msrv", "Cargo.lock")?;
51-
cmd!(sh, "cargo build").run()?;
51+
if let err @ Err(_) = cmd!(sh, "cargo update -w -v --locked").run() {
52+
// `Cargo.lock.msrv` is out of date! Probably from having bumped our own version number.
53+
println! {"\
54+
Error: `Cargo.lock.msrv` is out of date. \
55+
Please run:\n \
56+
(cp Cargo.lock{{.msrv,}} && cargo +{MSRV} update -w -v && cp Cargo.lock{{.msrv,}})\n\
57+
\n\
58+
Alternatively, `git apply` the `.patch` below:\
59+
"}
60+
cmd!(sh, "cargo update -q -w").quiet().run()?;
61+
sh.copy_file("Cargo.lock", "Cargo.lock.msrv")?;
62+
cmd!(sh, "git --no-pager diff --color=always -- Cargo.lock.msrv").quiet().run()?;
63+
return err;
64+
}
65+
cmd!(sh, "cargo build --locked").run()?;
5266
}
5367

5468
{

0 commit comments

Comments
 (0)