So I have this in my code:
static CONTROLLERS: Lazy<RwLock<Vec<NvmeController>>> = Lazy::new(||RwLock::new(Vec::new()));
static INTRS: Lazy<RwLock<Vec<Interrupt>>> = Lazy::new(|| RwLock::new(Vec::new()));
Where Interrupt is defined to be:
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
struct Interrupt(pub u128, pub u16);
At the same time, I have this code:
loop {
if matches!(INTRS.try_read(), Some(i) if i[self.intrspos].1 > 0) {
break;
}
hlt();
}
And:
register_interrupt_handler(
dev.int_line,
Box::new(move |_| {
INTRS
.write()
.iter_mut()
.filter(|i| dev.unique_dev_id == i.0)
.for_each(|i| i.1 += 1);
}),
);
This final function is called when a given interrupt is received. The issue is this:
- This code works perfectly fine the first time around. The driver sends the command to the controller, the controller responds, the writer lock is acquired, the update is performed and the lock is released. Then the driver attains a reader lock, checks to see if this particular instance of it has gotten something, acquires a writer lock to decrement the counter, then releases the lock.
- This doesn't, however, work the second time around. The driver gets stuck, no matter where I put the
hltinstruction. I've tried using classic mutexes, atomics (which didn't compile), SeqLocks and back to reader-writer locks. One of two things happens:- The interrupt is received and the function is called, but the driver never awakens to check to see if the interrupt handler was called to begin with; or
- The interrupt never occurs at all.
In both instances, the driver hangs.
I'm dealing with a (potential) situation of infinite controllers and infinite interrupts. I know the emulated system I'm programming this in has only one controller and, therefore, only one interrupt source for this driver, however I mustn't assume anything about the execution environment, because for all I know someone who runs this in the future might have 30 or 300 controllers.
I've thought about an MPMC queue. The problems I've hit are:
- The MPMC queues provided by the
heaplesscrate only offer up to 64 entries in the queue at a time. The NVMe specification mandates that a controller can have up to 65534 queues, plus the admin queue, so this is insufficient for my needs. - I (can't seem) to find an unbounded MPMC queue for no_std. Maybe one exists and I just skipped past it when I was looking in the Concurrency category on crates.io.
What do you guys suggest? I figured that I might hit a concurrency bug like this sooner or later, I just hadn't prepared for it.