OS Primitives: Spinlocks#
Producer/Consumer Interrupts#
One interrupt (say a sensor) produces some data
Another (say device-buffer-empty) consumes
⟶ Parallelism
⟶ No good!
#include <why-thread.h>
#include <why-irq.h>
#include <why-irqengine.h>
#include <why-logger.h>
#include <string>
#include <list>
#include <thread>
#include <print>
using namespace std::chrono_literals;
std::list<std::string> the_list;
int main()
{
Why::init();
auto sensor_isr = [](int){
the_list.push_back("some data");
};
Why::IRQ::connect(2, sensor_isr);
auto device_buffer_empty = [](int){
if (! the_list.empty())
the_list.pop_front();
};
Why::IRQ::connect(3, device_buffer_empty);
size_t last_num = 0;
while (true) {
if (last_num != the_list.size()) {
last_num = the_list.size();
std::println("#elems: {}", the_list.size());
}
std::this_thread::sleep_for(0.5s);
}
return 0;
}
IRQ engine internals
In
why-shell#> pid
833252
> irqsig
60
In another terminal#
$ kill -s 60 -q 2 833252
Or, for short
In
why-shell#> irq 2
> #elems: 1
irq 3
> #elems: 0
Problem: Interrupt Parallelism#
Interrupt nesting
Awkward in total
IRQ2 and IRQ3 are considered parallel
Bombard it:
$ while true; do echo irq 2; echo irq 3; done|why-shell ./why-spinlocks-do-much-in-isr
double free or corruption (fasttop)
child died: signal 6, core dumped: 128
Solution: Spinlock#
jjj check this
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
Bombard it:
$ while true; do echo irq 2; echo irq 3; done|why-shell ./why-spinlocks-do-much-in-isr-spinlock
...
#include <why-spinlock.h> // <-- include it
#include <why-thread.h>
#include <why-irq.h>
#include <why-irqengine.h>
#include <why-logger.h>
#include <string>
#include <list>
#include <thread>
#include <print>
#include <unistd.h>
using namespace std::chrono_literals;
std::list<std::string> the_list;
Why::Spinlock the_lock; // <-- instantiate one
int main()
{
Why::init();
auto sensor_isr = [](int){
the_lock.lock(); // <-- use it
the_list.push_back("some data");
the_lock.unlock(); // <--
};
Why::IRQ::connect(2, sensor_isr);
auto device_buffer_empty = [](int){
the_lock.lock(); // <--
if (! the_list.empty())
the_list.pop_front();
the_lock.unlock(); // <--
};
Why::IRQ::connect(3, device_buffer_empty);
size_t last_num = 0;
while (true) {
if (last_num != the_list.size()) {
last_num = the_list.size();
std::println("#elems: {}", the_list.size());
}
std::this_thread::sleep_for(0.5s);
}
return 0;
}