Skip to content

Commit ceb5649

Browse files
appaquetdwrensha
authored andcommitted
Atomic read limiter: better logic
1 parent 5255129 commit ceb5649

File tree

2 files changed

+20
-15
lines changed

2 files changed

+20
-15
lines changed

capnp/Cargo.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ quickcheck = { version = "0.9", optional = true }
2525
quickcheck = "0.9"
2626

2727
[features]
28-
default = ["std", "sync_reader"]
28+
default = ["std"]
2929

3030
rpc_try = []
3131

@@ -37,8 +37,7 @@ unaligned = []
3737
# with the Rust standard library.
3838
std = []
3939

40-
# If disabled, message reader will not be `Sync`. This can be used
41-
# to support platforms where `AtomicUsize` is not available.
40+
# If enabled, message reader will be `Sync`.
4241
# To be replaced by #[cfg(target_has_atomic = ...)] once it lands.
4342
# See: https://github.com/rust-lang/rust/issues/32976
4443
sync_reader = []

capnp/src/private/read_limiter.rs

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ pub use sync::ReadLimiter;
2525
#[cfg(feature = "sync_reader")]
2626
mod sync {
2727
use crate::{Error, Result};
28-
use core::sync::atomic::{AtomicUsize, Ordering};
28+
use core::sync::atomic::{AtomicUsize, AtomicBool, Ordering};
2929

3030
pub struct ReadLimiter {
31-
pub limit: usize,
32-
pub read: AtomicUsize,
31+
pub limit: AtomicUsize,
32+
pub limit_reached: AtomicBool,
3333
}
3434

3535
impl ReadLimiter {
@@ -39,21 +39,27 @@ mod sync {
3939
}
4040

4141
ReadLimiter {
42-
limit: limit as usize,
43-
read: AtomicUsize::new(0),
42+
limit: AtomicUsize::new(limit as usize),
43+
limit_reached: AtomicBool::new(false),
4444
}
4545
}
4646

4747
#[inline]
4848
pub fn can_read(&self, amount: usize) -> Result<()> {
49-
let read = self.read.load(Ordering::Relaxed) + amount;
49+
let limit_reached = self.limit_reached.load(Ordering::Relaxed);
50+
if limit_reached {
51+
return Err(Error::failed(format!("read limit exceeded")));
52+
}
5053

51-
if read > self.limit {
52-
Err(Error::failed(format!("read limit exceeded")))
53-
} else {
54-
self.read.fetch_add(amount, Ordering::Relaxed);
55-
Ok(())
54+
let prev_limit = self.limit.fetch_sub(amount, Ordering::Relaxed);
55+
if prev_limit == amount {
56+
self.limit_reached.store(true, Ordering::Relaxed);
57+
} else if prev_limit < amount {
58+
self.limit_reached.store(true, Ordering::Relaxed);
59+
return Err(Error::failed(format!("read limit exceeded")));
5660
}
61+
62+
Ok(())
5763
}
5864
}
5965
}
@@ -63,8 +69,8 @@ pub use unsync::ReadLimiter;
6369

6470
#[cfg(not(feature = "sync_reader"))]
6571
mod unsync {
66-
use core::cell::Cell;
6772
use crate::{Error, Result};
73+
use core::cell::Cell;
6874

6975
pub struct ReadLimiter {
7076
pub limit: Cell<u64>,

0 commit comments

Comments
 (0)