.. include:: Spinlocks ========= .. topic:: Documentation * :doc:`../why-os/spinlock` .. topic:: Trainer's note Continue from :doc:`../interrupt/index` Deferring Work To Main Loop --------------------------- .. image:: sensor-list.svg :scale: 60% * Interrupt still produces samples * Consumption in main loop * Communication from producer (ISR) to consumer (main loop): doubly linked list Code: Deferring Work To Main Loop (Naively) ------------------------------------------- .. literalinclude:: code/sensor-enqueue-list.cpp :caption: :download:`code/sensor-enqueue-list.cpp` :language: c++ .. code-block:: console $ why-shell code/why-interrupt-sensor-enqueue-list > irq 7 timestamp=199147898365133, value=100 Problem: Critical Section ------------------------- * A ``std::list`` is not at all safe * Non-atomic manipulation of multiple pointers * Main loop dequeues samples * Possibly interleaved by ISR which enqueues a sample Bombard it, and see a crash at some point: .. code-block:: console $ while true; do echo irq 7; done | \ why-shell code/why-interupt-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. Spinlock: Interrupt Mutual Exclusion ------------------------------------ .. topic:: Documentation * :doc:`../why-os/spinlock` .. attention:: Although spinlocks are easy to use and wrap around one's own data structures, it is probably wiser to rely on OS capabilities and use :doc:`message queues <../messagequeue/index>` (or comparable devices) and :doc:`scheduling <../threads/index>`. * Need something that tests and sets a flags atomically * Safe to use in ISR (should be used, actually) * Also usable between threads (see :doc:`later <../threads/index>`) * On a multiprocessor: *spin* until lock can be had * In schedulable context, disable interrupts on the local CPU * Actual implementation/definition is much more complicated * |longrightarrow| Do not try to write one yourself * 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 7; done | \ why-shell code/why-interrupt-sensor-enqueue-list-spinlock ...