.. include:: Spinlocks ========= .. topic:: Documentation * :doc:`../why-os/locking` * `Zephyr: Spinlock APIs `__ .. topic:: Trainer's note * Continue from :doc:`../interrupt/index`, :download:`../interrupt/code/sensor-irq.cpp` Producer/Consumer Interrupts ---------------------------- * Rationale: interrupt takes too long (``std::println()``) * |longrightarrow| defer that to main loop * Use a doubly linked list .. literalinclude:: code/sensor-enqueue-list.cpp :caption: :download:`code/sensor-enqueue-list.cpp` :language: c++ .. code-block:: console $ 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: .. code-block:: console $ 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; _Alloc = std::allocator >; reference = std::pair&]: 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 .. literalinclude:: code/sensor-enqueue-list-spinlock.cpp :caption: :download:`code/sensor-enqueue-list-spinlock.cpp` :language: c++ Bombard it like earlier, all well .. code-block:: console $ while true; do echo irq 2; done | \ why-shell code/why-spinlocks-sensor-enqueue-list-spinlock ...