Spinlocks#
Producer/Consumer Interrupts#
Rationale: interrupt takes too long (
std::println())⟶ defer that to main loop
Use a doubly linked list
#include <why-irq.h>
#include <why-time.h>
#include <why-sensor.h>
#include <print>
#include <list>
using sensor_data = std::pair<uint64_t/*timestamp*/, uint64_t/*value*/>;
std::list<sensor_data> the_data;
int main()
{
Why::init();
Why::RandomSensor sensor(0, 100);
auto isr = [&sensor](int irqnum){
the_data.emplace_back( // <-- produce
Why::now_monotonic(), sensor.get_value());
};
Why::IRQ::connect(2, isr);
while (true) {
if (the_data.size()) { // <-- consume
auto [timestamp, value] = the_data.front();
the_data.pop_front();
std::println("timestamp={}, value={}", timestamp, value);
}
else
/*power management?*/;
}
return 0;
}
$ why-shell code/why-spinlocks-sensor-enqueue-list
> irq 2
timestamp=199147898365133, value=100
Problem: Interrupt Asynchronity#
Interrupt service routine runs highly async
Will interrupt main loop at inopportune times
Bombard it, and see a crash at some point:
$ while true; do echo irq 2; done | \
why-shell code/why-spinlocks-sensor-enqueue-list
...
/usr/include/c++/15/bits/stl_list.h:1674: std::__cxx11::list<_Tp, _Allocator>::reference std::__cxx11::list<_Tp, _Allocator>::back() [with _Tp = std::pair<long unsigned int, long unsigned int>; _Alloc = std::allocator<std::pair<long unsigned int, long unsigned int> >; reference = std::pair<long unsigned int, long unsigned int>&]: Assertion '!this->empty()' failed.
child died: signal 6, core dumped: 128
Note
Try as root, to get realtime behavior and hard preemption rather than soft timeslices.
Solution: Spinlock#
Spinlock: safe to use in interrupt context
jjj blah
jjj check that
On a multiprocessor: spin until lock can be had
In schedulable context, disable interrupts on the local CPU
On a single processor:
In schedulable context: disable interrupts, be happy with the lock
In interrupt context: nothing to do - interrupts not disabled, that’s enough
#include <why-irq.h>
#include <why-spinlock.h>
#include <why-time.h>
#include <why-sensor.h>
#include <print>
#include <list>
using sensor_data = std::pair<uint64_t/*timestamp*/, uint64_t/*value*/>;
std::list<sensor_data> the_data;
Why::Spinlock the_lock; // <-- instantiate
int main()
{
Why::init();
Why::RandomSensor sensor(0, 100);
auto isr = [&sensor](int irqnum){
the_lock.lock(); // <-- use
the_data.emplace_back(
Why::now_monotonic(), sensor.get_value());
the_lock.unlock(); // <-- use
};
Why::IRQ::connect(2, isr);
while (true) {
if (the_data.size()) {
the_lock.lock(); // <-- use
auto [timestamp, value] = the_data.front();
the_data.pop_front();
the_lock.unlock(); // <-- use
std::println("timestamp={}, value={}", timestamp, value);
}
else
/*power management?*/;
}
return 0;
}
Bombard it like earlier, all well
$ while true; do echo irq 2; done | \
why-shell code/why-spinlocks-sensor-enqueue-list-spinlock
...