Skip to content

Fix mpsc bounded channel capacity to match documented (buffer + num_senders)#2998

Open
Emilie-Thome wants to merge 1 commit intorust-lang:masterfrom
Emilie-Thome:fix/mpsc-channel-capacity
Open

Fix mpsc bounded channel capacity to match documented (buffer + num_senders)#2998
Emilie-Thome wants to merge 1 commit intorust-lang:masterfrom
Emilie-Thome:fix/mpsc-channel-capacity

Conversation

@Emilie-Thome
Copy link
Copy Markdown

The documentation for channel(buffer) states:

The channel's capacity is equal to buffer + num-senders. Each sender gets a guaranteed slot in the channel capacity, and on top of that there are buffer "first come, first serve" slots.

However, the implementation only used buffer as the capacity threshold, ignoring num_senders.

This PR tries to fix two issues:

  1. Capacity didn't match documentation: the actual capacity was always buffer, regardless of how many senders existed.
  2. Behavioral gap between async send and try_send: async send would park after buffer messages, while try_send effectively allowed one extra message.

Changes in PR:

  • mpsc/mod.rs: Changed the park condition in do_send_b from num_messages > self.inner.buffer to num_messages >= self.inner.buffer + self.inner.num_senders.load(SeqCst), so capacity correctly accounts for the number of active senders.
  • mpsc/sink_impl.rs: Simplified Sender::poll_flush to always return Poll::Ready(Ok(())). The previous implementation forwarded poll_ready's result, which incorrectly blocked flush on channel capacity. Since start_send immediately enqueues messages into the shared queue, there is nothing to flush.
  • tests/mpsc.rs: Adjusted buffer sizes in existing tests to match the corrected semantics, removed a test that becomes obsolete with this patch, and added two new tests (send_recv_buffer_zero and send_recv_buffer_zero_async) that verify the dynamic buffer + num_senders capacity through both try_send and async Sink paths, including when senders are cloned at runtime.

The channel(buffer) documentation states capacity is buffer + num_senders,
but the implementation used a fixed capacity of buffer, ignoring the sender
count. This also caused a behavioral gap between async send and try_send.

Fix the park condition in do_send_b to account for num_senders, simplify
poll_flush which incorrectly blocked on capacity instead of being a no-op,
and update tests to match the documented semantics.

Signed-off-by: Emilie Thome <emilie.thome@ampere.cars>
@rustbot rustbot added A-channel Area: futures::channel S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-channel Area: futures::channel S-waiting-on-review Status: Awaiting review from the assignee but also interested parties.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants