Рассматриваются практики отладки обработчиков прерываний (ISR)
Статья включает:
ISR исполняется в контексте ядра ОС и на его стеке. Таким образом, его отказоустойчивость влияет на всю систему в целом. При этом из обработчика нельзя вызывать любую функцию системной библиотеки, которая приводит к системному вызову.
Если функция небезопасна, то ее вызов из обработчика может привести к фатальным общесистемным последствиям. Каждый задокументированный вызов системной библиотеки содержит таблицу, характеризующую рамки её безопасного использования (см. раздел Безопасность использования функций).
В частности, все функции, которые порождают отправку сообщений не разрешены к применению в ISR. К ним относятся и функции семейства printf().
Поскольку в худшем случае некорректный ISR способен приводить к аварийному завершению ядра, идеальным является использование аппаратного отладчика центрального процессора, способного перехватывать управление в аварийном режиме и предоставлять доступ как минимум к памяти, MMU и регистрам CPU. К сожалению, этот инструмент доступен далеко не всегда.
Одной из самых простых практик, но в ряде случаев являющихся разновидностью разрушающего контроля, является перевод обработки ISR на уровень прикладного потока. Для этого достаточно лишь оказаться от использования InterruptAttach() в пользу InterruptAttachEvent(). Хотя бы на время отладки.
Недостатком метода является невозможность точного воспроизведения исходной логики обработки ISR, что не всегда позволяет синтезировать точный сценарий сбоя обработчика. Связано это как с задержками, привносимыми переносом кода обработчика на уровень приоритетов прикладного кода, так и с возможностью произвольных модификаций кода обработчика, в результате чего его логика наполняется системными вызовами, переключениями контекстов потоков и т.п.
Из обработчика прерываний возможно добавление отладочных сведений в системную трассу (см. TraceEvent()). До недавнего времени это был единственный способ получения печати из ISR. Преимущества данного способа вполне очевидны, если отладка не сопряжена с аварийным завершением ядра.
Недостатком метода является высокая степень асинхронности по отношению к действиям разработчика. Дело в том, что даже если системная трасса содержит нужные сведения, она еще должна быть захвачена (см. tracelogger) и отображена (см. traceprinter). Если же мы имеем дело с завершением ядра, получить адекватный тестовому сценарию вывод практически невозможно.
Тем не менее, начиная с редакции 2024
, ядро ЗОСРВ «Нейтрино» поддерживает postmortem трассировку ядра, которая позволяет получить фрагмент системной трассы, характеризующий последние мгновенья "жизни" ядра, включая отладку из ISR. Методика детально описана в статье Дампы ядра и их анализ.
Начиная с редакции 2024
, системная библиотека ЗОСРВ «Нейтрино» поддерживает группу функций, безопасных для получения печати из ISR в отладочную консоль в реальном времени:
![]() | Обратите внимание, что не все сценарии использования этих функций безопасны для применения в контексте ISR. Подробнее см. на страницах документации к самим функциям. |
Пример получения ISR-безопасной отладки:
#include <stdio.h>#include <stdlib.h>#include <sys/kprintf.h>#include <sys/types.h>#include <sys/neutrino.h>struct sigevent *isr( void *arg, int id ){kprintf( "Hello, dudes!\n" );return (NULL);}int main( int argc, char *argv[] ){...kprintf_setup( kcallout_putchar, KPRINTF_DEFAULT_BEHAVIOR );...InterruptAttach( irq, isr, NULL, 0, _NTO_INTR_FLAGS_TRK_MSK );...}
Предыдущий раздел: Обработчики прерываний