diff --git a/tokio-util/src/sync/poll_semaphore.rs b/tokio-util/src/sync/poll_semaphore.rs index d0b1dedc273..99bb6bfcf7c 100644 --- a/tokio-util/src/sync/poll_semaphore.rs +++ b/tokio-util/src/sync/poll_semaphore.rs @@ -95,7 +95,7 @@ impl PollSemaphore { /// Adds `n` new permits to the semaphore. /// - /// The maximum number of permits is `usize::MAX >> 3`, and this function + /// The maximum number of permits is [`Semaphore::MAX_PERMITS`], and this function /// will panic if the limit is exceeded. /// /// This is equivalent to the [`Semaphore::add_permits`] method on the diff --git a/tokio/src/sync/semaphore.rs b/tokio/src/sync/semaphore.rs index ccf44ba8a88..6e5a1a88abb 100644 --- a/tokio/src/sync/semaphore.rs +++ b/tokio/src/sync/semaphore.rs @@ -123,7 +123,14 @@ fn bounds() { } impl Semaphore { + /// The maximum number of permits which a semaphore can hold. It is `usize::MAX >>> 3`. + /// + /// Exceeding this limit typically results in a panic. + pub const MAX_PERMITS: usize = super::batch_semaphore::Semaphore::MAX_PERMITS; + /// Creates a new semaphore with the initial number of permits. + /// + /// Panics if `permits` exceeds [`Semaphore::MAX_PERMITS`]. #[track_caller] pub fn new(permits: usize) -> Self { #[cfg(all(tokio_unstable, feature = "tracing"))] @@ -186,7 +193,7 @@ impl Semaphore { /// Adds `n` new permits to the semaphore. /// - /// The maximum number of permits is `usize::MAX >> 3`, and this function will panic if the limit is exceeded. + /// The maximum number of permits is [`Semaphore::MAX_PERMITS`], and this function will panic if the limit is exceeded. pub fn add_permits(&self, n: usize) { self.ll_sem.release(n); } diff --git a/tokio/tests/sync_semaphore.rs b/tokio/tests/sync_semaphore.rs index f12edb7dfbc..3d47ed0ed73 100644 --- a/tokio/tests/sync_semaphore.rs +++ b/tokio/tests/sync_semaphore.rs @@ -114,14 +114,37 @@ async fn stress_test() { #[test] fn add_max_amount_permits() { let s = tokio::sync::Semaphore::new(0); - s.add_permits(usize::MAX >> 3); - assert_eq!(s.available_permits(), usize::MAX >> 3); + s.add_permits(tokio::sync::Semaphore::MAX_PERMITS); + assert_eq!(s.available_permits(), tokio::sync::Semaphore::MAX_PERMITS); } #[cfg(not(tokio_wasm))] // wasm currently doesn't support unwinding #[test] #[should_panic] -fn add_more_than_max_amount_permits() { +fn add_more_than_max_amount_permits1() { let s = tokio::sync::Semaphore::new(1); - s.add_permits(usize::MAX >> 3); + s.add_permits(tokio::sync::Semaphore::MAX_PERMITS); +} + +#[cfg(not(tokio_wasm))] // wasm currently doesn't support unwinding +#[test] +#[should_panic] +fn add_more_than_max_amount_permits2() { + let s = Semaphore::new(Semaphore::MAX_PERMITS - 1); + s.add_permits(1); + s.add_permits(1); +} + +#[cfg(not(tokio_wasm))] // wasm currently doesn't support unwinding +#[test] +#[should_panic] +fn panic_when_exceeds_maxpermits() { + let _ = Semaphore::new(Semaphore::MAX_PERMITS + 1); +} + +#[test] +fn no_panic_at_maxpermits() { + let _ = Semaphore::new(Semaphore::MAX_PERMITS); + let s = Semaphore::new(Semaphore::MAX_PERMITS - 1); + s.add_permits(1); }