Skip to content

Commit 0c69fac

Browse files
committed
Document #583 and deprecate mpmc
1 parent db26571 commit 0c69fac

File tree

3 files changed

+66
-0
lines changed

3 files changed

+66
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1717
- Added `truncate` to `Deque`
1818
- Added `retain` to `Deque`
1919
- Added `retain_mut` to `Deque`
20+
- Deprecate `mpmc` (see [#583](https://github.com/rust-embedded/heapless/issues/583#issuecomment-3469297720))
2021

2122
## [v0.9.1] - 2025-08-19
2223

src/mpmc.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,32 @@
11
//! A fixed capacity multiple-producer, multiple-consumer (MPMC) lock-free queue.
22
//!
3+
//! # Deprecation
4+
//!
5+
//! <div class="warning">
6+
//! The current implementation of `mpmc` is marked as deprecated due to not being truly lock-free
7+
//! </div>
8+
//!
9+
//! If a thread is parked, or pre-empted for a long time by an higher-priority task
10+
//! during an `enqueue` or `dequeue` operation, it is possible that the queue ends-up
11+
//! in a state were no other task can successfully enqueue or dequeue items from it
12+
//! until the pre-empted task can finish its operation.
13+
//!
14+
//! In that case, [`enqueue`](QueueInner::dequeue) and [`dequeue`](QueueInner::enqueue) will return an error, but will not panic or reach undefined behaviour
15+
//!
16+
//! This makes `mpmc` unsuitable for some use cases such as using it as a pool of objects.
17+
//!
18+
//! ## When can this queue be used?
19+
//!
20+
//! This queue should be used for cross-task communication only when items sent over the queue
21+
//! can be dropped in case of concurrent operations, or when it is possible to retry
22+
//! the dequeue/enqueue operation after other tasks have had the opportunity to make progress.
23+
//!
24+
//! In that case you can safely ignore the warnings using `#[expect(deprecated)]` when `new` is called
25+
//!
26+
//! For more information, and possible alternative, please see
27+
//! <https://github.com/rust-embedded/heapless/issues/583>
28+
//!
29+
//!
330
//! **Note:** This module requires atomic compare-and-swap (CAS) instructions. On
431
//! targets where they're not natively available, they are emulated by the
532
//! [`portable-atomic`](https://crates.io/crates/portable-atomic) crate.
@@ -121,7 +148,36 @@ pub type Queue<T, const N: usize> = QueueInner<T, OwnedStorage<N>>;
121148
pub type QueueView<T> = QueueInner<T, ViewStorage>;
122149

123150
impl<T, const N: usize> Queue<T, N> {
151+
#[deprecated(
152+
note = "See the documentation of Queue::new() for more information: https://docs.rs/heapless/latest/heapless/mpmc/type.Queue.html#method.new"
153+
)]
124154
/// Creates an empty queue.
155+
///
156+
/// # Deprecation
157+
///
158+
/// <div class="warning">
159+
/// The current implementation of `mpmc` is marked as deprecated due to not being truly lock-free
160+
/// </div>
161+
///
162+
/// If a thread is parked, or pre-empted for a long time by an higher-priority task
163+
/// during an `enqueue` or `dequeue` operation, it is possible that the queue ends-up
164+
/// in a state were no other task can successfully enqueue or dequeue items from it
165+
/// until the pre-empted task can finish its operation.
166+
///
167+
/// In that case, [`enqueue`](QueueInner::dequeue) and [`dequeue`](QueueInner::enqueue) will return an error, but will not panic or reach undefined behaviour
168+
///
169+
/// This makes `mpmc` unsuitable for some use cases such as using it as a pool of objects.
170+
///
171+
/// ## When can this queue be used?
172+
///
173+
/// This queue should be used for cross-task communication only when items sent over the queue
174+
/// can be dropped in case of concurrent operations, or when it is possible to retry
175+
/// the dequeue/enqueue operation after other tasks have had the opportunity to make progress.
176+
///
177+
/// In that case you can safely ignore the warnings using `#[expect(deprecated)]` when `new` is called
178+
///
179+
/// For more information, and possible alternative, please see
180+
/// <https://github.com/rust-embedded/heapless/issues/583>
125181
pub const fn new() -> Self {
126182
const {
127183
assert!(N > 1);
@@ -186,6 +242,7 @@ impl<T, S: Storage> QueueInner<T, S> {
186242
///
187243
/// ```rust
188244
/// # use heapless::mpmc::{Queue, QueueView};
245+
/// ##[expect(deprecated)]
189246
/// let mut queue: Queue<u8, 2> = Queue::new();
190247
/// let view: &mut QueueView<u8> = queue.as_mut_view();
191248
/// ```
@@ -194,6 +251,7 @@ impl<T, S: Storage> QueueInner<T, S> {
194251
///
195252
/// ```rust
196253
/// # use heapless::mpmc::{Queue, QueueView};
254+
/// ##[expect(deprecated)]
197255
/// let mut queue: Queue<u8, 2> = Queue::new();
198256
/// let view: &mut QueueView<u8> = &mut queue;
199257
/// ```
@@ -228,6 +286,7 @@ impl<T, S: Storage> QueueInner<T, S> {
228286

229287
impl<T, const N: usize> Default for Queue<T, N> {
230288
fn default() -> Self {
289+
#[allow(deprecated)]
231290
Self::new()
232291
}
233292
}
@@ -355,6 +414,7 @@ mod tests {
355414
fn memory_leak() {
356415
droppable!();
357416

417+
#[expect(deprecated)]
358418
let q = Queue::<_, 2>::new();
359419
q.enqueue(Droppable::new()).unwrap_or_else(|_| panic!());
360420
q.enqueue(Droppable::new()).unwrap_or_else(|_| panic!());
@@ -365,6 +425,7 @@ mod tests {
365425

366426
#[test]
367427
fn sanity() {
428+
#[expect(deprecated)]
368429
let q = Queue::<_, 2>::new();
369430
q.enqueue(0).unwrap();
370431
q.enqueue(1).unwrap();
@@ -377,6 +438,7 @@ mod tests {
377438

378439
#[test]
379440
fn drain_at_pos255() {
441+
#[expect(deprecated)]
380442
let q = Queue::<_, 2>::new();
381443
for _ in 0..255 {
382444
assert!(q.enqueue(0).is_ok());
@@ -389,6 +451,7 @@ mod tests {
389451

390452
#[test]
391453
fn full_at_wrapped_pos0() {
454+
#[expect(deprecated)]
392455
let q = Queue::<_, 2>::new();
393456
for _ in 0..254 {
394457
assert!(q.enqueue(0).is_ok());
@@ -408,6 +471,7 @@ mod tests {
408471
#[cfg(feature = "mpmc_large")]
409472
const CAPACITY: usize = 256;
410473

474+
#[expect(deprecated)]
411475
let q: Queue<u8, CAPACITY> = Queue::new();
412476

413477
assert_eq!(q.capacity(), CAPACITY);

tests/tsan.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ fn mpmc_contention() {
122122

123123
const N: u32 = 64;
124124

125+
#[expect(deprecated)]
125126
static Q: Queue<u32, 64> = Queue::new();
126127

127128
let (s, r) = mpsc::channel();

0 commit comments

Comments
 (0)