rust-embedded / rust-embedded/heapless

Queue not thread/interrupt safe?

Open
#355 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

question
Dominant language
Rust
Stars
2k
Forks
253
Avg merge
1d 2h
Merged PRs (30d)
1

Description

I am developing in RISC-V and in my understanding the Queue is not thread or interrupt safe. Imagine the following scenario where an item is dequeued:

    unsafe fn inner_dequeue(&self) -> Option<T> {
        let current_head = self.head.load(Ordering::Relaxed); // holds head before second dequeue
        // (1) interrupt or thread switch happens here, inner_dequeue is executed in second context
        // -> head is incremented by second context

        // current head is no longer up to date and still holds the not yet incremented value
        if current_head == self.tail.load(Ordering::Acquire) { 
            None
        } else {
            // the same elemet is returned twice
            // once here and once in the second context
            let v = (self.buffer.get_unchecked(current_head).get() as *const T).read();  

            self.head
                .store(Self::increment(current_head), Ordering::Release);

            Some(v)
        }
    }

Imagine if the inner_dequeue function is interrupted at position (1), right between the load of the head and the tail and in the other context (either interrupt or different thread) inner_dequeue is executed. Now the head still is already incremented by the second context, but the original context still uses the old value. Like this, one value is returned/dequeued twice.

As far as I understand, the atomics do not prevent this behavior. Or at least not for the single core risv32imc target. Here, interrupts get disabled and re-enabled just for the two load instructions. But they are enabled in between the two loads:

// disable interrupts
let current_head = self.head.load(Ordering::Relaxed);
// enable interrupts

// disable interrupts
if current_head == self.tail.load(Ordering::Acquire) { 
// disable interrupts
...
}

So I am not sure if thread/interrupt safety is guaranteed, but if it is, I would suggest using a critical section around the whole dequeue process.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing the Queue implementation around inner_dequeue and its atomic ordering. Reproduce the reported interleaving on the single-core RISC-V target with interrupts or concurrent execution, then inspect existing queue tests for coverage. Done means the thread and interrupt-safety guarantee is established or the issue is reduced to a documented, test-backed fix.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
embedded-iot
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.