Многозадачность в ядре linux: прерывания и tasklet’ы
Содержание:
- Приоритизация
- Маскирование
- Программное прерывание
- Программное прерывание
- Дребезг контактов
- Прерывания
- Таблица — вектор — прерывание
- Сложность с разделением линий прерывания
- Анализируем причину
- Типы прерываний
- 4.2. Маскирование прерываний
- Приоритизация
- Общие рекомендации по написанию обработчиков прерываний
- attachInterrupt
Приоритизация
До окончания обработки прерывания обычно устанавливается запрет на обработку этого типа прерывания, чтобы процессор не входил в цикл обработки одного прерывания. Приоритизация означает, что все источники прерываний делятся на классы и каждому классу назначается свой уровень приоритета запроса на прерывание.
- Относительное обслуживание прерываний означает, что если во время обработки прерывания поступает более приоритетное прерывание, то это прерывание будет обработано только после завершения текущей процедуры обработки прерывания.
- Абсолютное обслуживание прерываний означает, что если во время обработки прерывания поступает более приоритетное прерывание, то текущая процедура обработки прерывания вытесняется, и процессор начинает выполнять обработку вновь поступившего более приоритетного прерывания. После завершения этой процедуры процессор возвращается к выполнению вытесненной процедуры обработки прерывания.
Маскирование
Внешние прерывания, в зависимости от возможности запрета, делятся на:
- маскируемые — прерывания, которые можно запрещать установкой соответствующих битов в регистре маскирования прерываний (в x86-процессорах — сбросом флага IF в регистре флагов);
- немаскируемые (англ. Non-maskable interrupt, NMI) — обрабатываются всегда, независимо от запретов на другие прерывания. К примеру, такое прерывание может быть вызвано сбоем в микросхеме памяти.
Обработчики прерываний обычно пишутся таким образом, чтобы время их обработки было как можно меньшим, поскольку во время их работы могут не обрабатываться другие прерывания, а если их будет много (особенно от одного источника), то они могут теряться. В Windows для этого применяется механизм отложенного вызова процедур.
Программное прерывание
Программное прерывание — синхронное прерывание, которое может осуществить программа с помощью специальной инструкции.
В процессорах архитектуры x86 для явного вызова синхронного прерывания имеется инструкция , аргументом которой является номер прерывания (от 0 до 255). В IBM PC-совместимых компьютерах обработку некоторых прерываний осуществляют подпрограммы BIOS, хранящиеся в ПЗУ, и прерывание служит интерфейсом для доступа к сервису, предоставляемому BIOS. Также обслуживание прерываний могут взять на себя BIOS карт расширений (например, сетевых или видеокарт), операционная система и даже обычные (прикладные) программы, которые постоянно находятся в памяти во время работы других программ (т. н. резидентные программы). В отличие от реального режима, в защищённом режиме x86-процессоров обычные программы не могут обслуживать прерывания, эта функция доступна только системному коду (операционной системе).
MS-DOS использует для взаимодействия со своими модулями и прикладными программами прерывания с номерами от 20h до 3Fh (числа даны в шестнадцатеричной системе счисления, как это принято при программировании на языке ассемблера x86). Например, доступ к основному множеству функций MS-DOS осуществляется исполнением инструкции (при этом номер функции и её аргументы передаются в регистрах). Это распределение номеров прерываний не закреплено аппаратно и другие программы могут устанавливать свои обработчики прерываний вместо или поверх уже имеющихся обработчиков, установленных MS-DOS или другими программами, что, как правило, используется для изменения функциональности или расширения списка системных функций. Также этой возможностью пользуются вирусы.
Программное прерывание
Программное прерывание — синхронное прерывание, которое может осуществить программа с помощью специальной инструкции.
В процессорах архитектуры x86 для явного вызова синхронного прерывания имеется инструкция , аргументом которой является номер прерывания (от 0 до 255). В IBM PC-совместимых компьютерах обработку некоторых прерываний осуществляют подпрограммы BIOS, хранящиеся в ПЗУ, и прерывание служит интерфейсом для доступа к сервису, предоставляемому BIOS. Также обслуживание прерываний могут взять на себя BIOS карт расширений (например, сетевых или видеокарт), операционная система и даже обычные (прикладные) программы, которые постоянно находятся в памяти во время работы других программ (т. н. резидентные программы). В отличие от реального режима, в защищённом режиме x86-процессоров обычные программы не могут обслуживать прерывания, эта функция доступна только системному коду (операционной системе).
MS-DOS использует для взаимодействия со своими модулями и прикладными программами прерывания с номерами от 20h до 3Fh (числа даны в шестнадцатеричной системе счисления, как это принято при программировании на языке ассемблера x86). Например, доступ к основному множеству функций MS-DOS осуществляется исполнением инструкции (при этом номер функции и её аргументы передаются в регистрах). Это распределение номеров прерываний не закреплено аппаратно и другие программы могут устанавливать свои обработчики прерываний вместо или поверх уже имеющихся обработчиков, установленных MS-DOS или другими программами, что, как правило, используется для изменения функциональности или расширения списка системных функций. Также этой возможностью пользуются вирусы.
Дребезг контактов
Очевидно, что при подаче на вход внешнего прерывания сигнала, искаженного дребезгом контактов, обработчик прерывания будет выполнен несколько раз. В некоторых случаях дребезг не является проблемой, например, если мы ожидаем нажатия на кнопку для выполнения в программе каких-либо действий: достаточно отключить отслеживание данного прерывания при входе в обработчик, а после выполнения нашего кода снова включить (подразумевается, что время выполнения наших действий превышает длительность дребезга контактов). Таким образом мы пропустим дребезг и обработчик будет выполнен только один раз. Другое дело, когда прерывания используются для регистрации событий. Хороший пример — механический энкодер вращения. В этом случае мы не можем отключить отслеживание прерываний, поскольку рискуем пропустить событие (импульс от энкодера). Принять решение о том, ложный это импульс или нет, обработчик не может, да и просто это не та задача, которой он должен заниматься. Поэтому единственным рациональным решением является применение аппаратных подавителей дребезга. Данной теме посвящены несколько моих публикаций, ссылки на них ниже:
Устранение дребезга контактов. Часть 1 — триггер ШмиттаУстранение дребезга контактов. Часть 2 — микросхема MC14490Устранение дребезга контактов. Часть 3 — микросхемы MAX6816/MAX6817/MAX6818
Прерывания
Для обработки событий, происходящих асинхронно
по отношению к выполнению программы, лучше всего
подходит механизм прерываний. Прерывание можно
рассматривать как некоторое особое событие в
системе, требующее моментальной реакции.
Практически все системы ввода/вывода в
компьютере работают с использованием
прерываний. В частности, когда вы нажимаете
клавиши или щелкаете мышью, аппаратура
вырабатывает прерывания. В ответ на них система,
соответственно, считывает код нажатой клавиши
или запоминает координаты курсора мыши.
Прерывания вырабатываются контроллером диска,
адаптером локальной сети, портами
последовательной передачи данных, звуковым
адаптером и другими устройствами.
Кажется очевидным, что возможны самые
разнообразные прерывания по самым различным
причинам. Поэтому с прерыванием связывают число —
так называемый номер прерывания.
Этот номер однозначно соответствует тому или
иному событию. Система умеет распознавать
прерывания и при их возникновении запускает
процедуру, соответствующую номеру прерывания.
Некоторые прерывания (первые пять по порядку
номеров) зарезервированы для использования
центральным процессором на случай каких-либо
особых событий вроде попытки деления на нуль,
переполнения и т. п.
Программы могут сами вызывать прерывания с
заданным номером. Для этого они используют
команду INT. Это так называемые программные
прерывания. Программные прерывания не являются
асинхронными, так как вызываются из программы.
Программные прерывания удобно использовать
для организации доступа к отдельным, общим для
всех программ функциям. Например, функции
операционной системы доступны прикладным
программам именно через прерывания. При вызове
этих модулей нет необходимости знать их текущий
адрес в памяти.
Прикладные программы и драйверы могут сами
устанавливать свои обработчики прерываний для
их последующего использования другими
программами. Для этого встраиваемые обработчики
прерываний должны быть резидентными в памяти.
Аппаратные прерывания вызываются физическими
устройствами и потому приходят асинхронно по
отношению к выполнению любых программ. Эти
прерывания информируют систему о событиях,
связанных с работой устройств. Например, о том,
что наконец-то завершилась печать символа на
принтере и неплохо было бы выдать следующий
символ, или о том, что сектор диска уже прочитан и
его содержимое доступно программе.
Использование прерываний при работе с
медленными внешними устройствами позволяют
совместить ввод/вывод с обработкой данных в
центральном процессоре. В результате этого
повышается общая производительность системы.
Иногда желательно сделать систему
нечувствительной ко всем или отдельным
аппаратным прерываниям . Для этого используют
так называемое маскирование прерываний, о
котором мы еще будем говорить. Но существует и
немаскируемое прерывание (которое, кстати,
все-таки можно замаскировать, или, точнее говоря,
заблокировать).
Заметим, что обработчики прерываний могут сами
вызывать программные прерывания, например, для
получения доступа к сервису BIOS или MS-DOS.
Составление собственных программ обработки
прерываний и замена стандартных обработчиков
MS-DOS и BIOS является достаточно сложной задачей.
Необходимо учитывать все тонкости работы
аппаратуры, а также взаимодействия программного
и аппаратного обеспечения. При отладке возможно
разрушение операционной системы с
непредсказуемыми последствиями, поэтому надо
очень внимательно следить за тем, что делает ваша
программа.
Таблица — вектор — прерывание
Вектора прерываний и ПДП EFCOP. |
Таблица векторов прерываний EFCOP показана ниже.
За таблицей векторов прерываний следует область, используемая для хранения ряда программ и данных MS DOS. Далее располагаются программы-обработчики прерываний. Самая большая область оперативной памяти, как правило, отведена для выполнения программы пользователя. Эта область, обычно, распадается на сегменты кода, данных стека и дополнительный, адресуемые соответствующими сегментными регистрами.
Упрощенный алгоритм обработки прерывания. |
Программное прерывание тоже обслуживается через таблицу векторов прерываний, но номер прерывания указывается в составе команды, вызывающей прерывание.
В младших адресах оперативной памяти расположена таблица векторов прерываний, содержащая двести пятьдесят шесть адресов программ-обработчиков прерываний.
Отметим, что в более сложных случаях в таблице векторов прерываний могут находиться не адреса начала программ обработки прерываний, атак называемые дескрипторы ( описатели) прерываний. Но конечным результатом обработки этого дескриптора все равно будет адрес начала программы обработки прерываний.
Последовательность инициализации ВН59А. |
Микропроцессор ВМ86 / ВМ88 использует эту информацию для вычисления адреса входа в таблицу векторов прерываний. Кроме того, в режиме ВМ86 функция ADI ( управления адресным интервалом) подавляется. Состояние поля А7 — А5 в ICW1, а также А10 — А8 в ICW2 игнорируется.
Процессор, получив аппаратное прерывание, заканчивает выполнение текущей команды и обращается к памяти в область таблицы векторов прерываний, в ту ее строку, которая определяется номером запрошенного прерывания. Затем процессор читает содержимое этой строки ( код вектора прерывания) и переходит в адрес памяти, задаваемый этим вектором. Начиная с этого адреса в памяти должна располагаться программа обработки прерывания с данным номером. В конце программы обработки прерываний обязательно должна располагаться команда выхода из прерывания, выполнив которую, процессор возвращается к выполнению прерванной основной программы. Параметры процессора на время выполнения программы обработки прерывания сохраняются в стеке.
При каждом включении напряжения питания или нажатии клавиши сброса ПО мМС1204 инициализирует систему прерываний с базой таблицы векторов прерываний. При этом все векторы принимают нулевое значение. Пользователь управляет средствами поддержки режима реального времени, используя вышеуказанные процедуры.
Начальный адрес желательно определять, начиная с ячейки 100 памяти, чтобы не было пересечения с областью памяти, отведенной под таблицу векторов прерываний.
Обслуживание таких переходов осуществляется точно так же, как и аппаратных прерываний. То есть для выполнения данного перехода процессор обращается к таблице векторов прерываний и получает из нее по номеру прерывания адрес памяти, в который ему необходимо перейти. Адрес вызова прерывания и содержимое регистра состояния процессора ( PSW) сохраняются в стеке.
Схема одноплатного микроконтроллера мМС1212. |
В составе подсистемы памяти МК мМС1212 ОЗУ используется для хранения данных, ПЗУ-для хранения констант и программного кода. ОЗУ статического типа реализовано на четырех БИС К541РУ2 ( 1Кх4бит) и размещено в области ОООООН — 007FFH 1М — байтового адресного пространства памяти МК. Первая половина ОЗУ резервируется под организацию 256-эле-ментной таблицы векторов прерываний, вторая предназначена для организации системного стека и хранения ряда переменных. Реальный раздел резидентного ОЗУ между таблицей прерываний и оставшейся областью пользователя зависит от конкретного приложения МК.
Сложность с разделением линий прерывания
Несколько устройств, совместно использующих линию прерывания (любого стиля запуска), действуют как источники паразитных прерываний по отношению друг к другу. При наличии множества устройств в одной линии рабочая нагрузка при обслуживании прерываний увеличивается пропорционально квадрату количества устройств. Поэтому предпочтительно распределять устройства равномерно по доступным линиям прерывания. Нехватка линий прерывания является проблемой в старых конструкциях системы, где линии прерывания являются различными физическими проводниками. Прерывания с сигналом сообщения, где линия прерывания является виртуальной, предпочтительны в новых системных архитектурах (таких как PCI Express) и в значительной степени решают эту проблему.
Некоторые устройства с плохо разработанным программным интерфейсом не позволяют определить, запросили ли они обслуживание. Они могут запереться или иным образом плохо себя вести, если их обслуживают, когда они этого не хотят. Такие устройства не могут терпеть паразитные прерывания, а также не могут терпеть совместное использование линии прерывания. Карты ISA , из-за зачастую дешевого дизайна и конструкции, печально известны этой проблемой. Такие устройства становятся все более редкими, поскольку аппаратная логика становится дешевле, а новые системные архитектуры требуют разделяемых прерываний.
Анализируем причину
Любая внештатная ситуация, в том числе и снижение производительности сервера,
требует тщательного анализа. Не собрав всей информации, можно нагородить дел.
Возьмем такой случай. Контроллер домена (КД) уже не справляется со своими
обязанностями — пользователи подолгу регистрируются в системе или не могут зайти
в сетевую папку. В зависимости от топологии Сети, вариантов решения может быть
несколько.
Например, можно модернизировать железо, перераспределить нагрузку между
серверами (в том случае, когда КД выполняет еще и другую задачу) или же снизить
нагрузку на основной КД за счет установки еще одного КД в отдельном
подразделении компании. При использовании Win2k8 в удаленном офисе есть вариант
установить контроллер домена только для чтения (RODC). Тогда в случае
компрометации сервера или банальной кражи оборудования можно не бояться за
нарушение функционирования всего леса (подробности смотри в статье «В лабиринте
AD»). Так мы разгрузим основной КД и снизим нагрузку на Сеть (в том числе и на
внешний канал, если для соединения между офисами используется интернет).
Узкие места могут возникать по нескольким причинам:
- системные ресурсы сервера или сети исчерпали свои возможности — как
правило, требуется наращивание или модернизация; - отдельные системы или участки сети нагружены неравномерно — требуется
перераспределение ресурсов; - ресурс используется в монопольном режиме — возможно, потребуется замена
программы на аналог, запуск ее только по требованию или в периоды низкой
загрузки; - неправильная настройка — необходимо изменение параметров.
Теперь разберем некоторые моменты подробнее.
Типы прерываний
Прерывания могут быть разделены на следующие типы:
- Маскируемое прерывание (IRQ): аппаратное прерывание, которое можно игнорировать, устанавливая бит в битовой маске регистра маски прерываний (IMR).
- Немаскируемое прерывание (NMI): аппаратное прерывание, в котором отсутствует связанная битовая маска, поэтому ее нельзя игнорировать. NMI используются для задач с высшим приоритетом, например таких как таймеры.
- Межпроцессорное прерывание (IPI): особый случай прерывания, которое генерируется одним процессором для прерывания другого процессора в многопроцессорной системе.
- Программное прерывание: прерывание, генерируемое в процессоре путем выполнения инструкции. Программные прерывания часто используются для реализации системных вызовов, поскольку они приводят к вызову подпрограммы с изменением уровня вызова ЦП.
- Ложное прерывание: нежелательное аппаратное прерывание. Как правило, такие прерывания генерируются системными условиями, такими как электрические помехи в линии прерывания или из-за технически неправильно разработанного оборудования.
Прерывание, которое оставляет машину в четко определенном состоянии, называется точным прерыванием. Такое прерывание имеет четыре свойства:
- Счетчик программ (PC — Program Counter) сохраняется в известном месте.
- Все инструкции перед тем, на который указывает счетчик программ, полностью выполнены.
- Никакая инструкция, кроме той, на которую указывает счетчик программ, не была выполнена, или любые такие инструкции отменяются до обработки прерывания.
- Состояние выполнения инструкции, на которую указывает счетчик программ, известно.
Прерывание, которое не соответствует указанным выше требованиям, называется неточным прерыванием.
4.2. Маскирование прерываний
Часто при выполнении критических участков
программ приходится запрещать прерывания для
того чтобы гарантировать непрерываемое
выполнение определенной последовательности
команд. Это можно сделать командой CLI. Ее нужно
поместить в начало критической
последовательности команд, а в конце расположить
команду STI, разрешающую процессору воспринимать
прерывания. Команда CLI запрещает только
маскируемые прерывания, на обработку
немаскируемого прерывания эта команда никакого
влияния не оказывает.
Если вы используете запрет прерываний с
помощью команды CLI, следите за тем, чтобы
прерывания не отключались на длительный период
времени, так как это может привести к
нежелательным последствиям. Например, к
отставанию системных часов или неправильной
работе периферийных устройств компьютера.
Если вам надо запретить не все прерывания, а
только некоторые, например, от клавиатуры, то для
этого надо воспользоваться услугами контроллера
прерываний. Записывая в этот контроллер
определенную управляющую информацию, можно
замаскировать прерывания от отдельных
устройств.
Приоритизация
До окончания обработки прерывания обычно устанавливается запрет на обработку этого типа прерывания, чтобы процессор не входил в цикл обработки одного прерывания. Приоритизация означает, что все источники прерываний делятся на классы и каждому классу назначается свой уровень приоритета запроса на прерывание.
- Относительное обслуживание прерываний означает, что если во время обработки прерывания поступает более приоритетное прерывание, то это прерывание будет обработано только после завершения текущей процедуры обработки прерывания.
- Абсолютное обслуживание прерываний означает, что если во время обработки прерывания поступает более приоритетное прерывание, то текущая процедура обработки прерывания вытесняется, и процессор начинает выполнять обработку вновь поступившего более приоритетного прерывания. После завершения этой процедуры процессор возвращается к выполнению вытесненной процедуры обработки прерывания.
Общие рекомендации по написанию обработчиков прерываний
В заключение хочу привести несколько рекомендаций по написанию обработчиков прерываний.
- Во-первых, делайте обработчики предельно короткими. Ведь они прерывают выполнение основной программы, а также блокируют обработку других прерываний. По возможности обработчик должен фиксировать только факт возникновения события, изменяя значение переменной. А сама реакция на событие должна выполняться в основной программе при анализе этой переменной.
- Как уже было сказано, при входе в обработчик устанавливается глобальный запрет на обработку других прерываний. А это в свою очередь влияет на работу функций, использующих прерывания. Будьте с ними осторожнее. Если не уверены в безопасности их вызова, то лучше откажитесь от их использования в обработчике.
- Возьмите за правило объявлять разделяемые между основной программой и обработчиком переменные как volatile. И не забывайте, что этого квалификатора недостаточно в случае многобайтных переменных — используйте при работе с ними атомарно исполняемые блоки или interrupts/noInterrupts
следующей части
attachInterrupt
Функция attachInterrupt сообщает микроконтроллеру, на какие события он должен реагировать и какой обработчик им соответствует. Функция имеет следующий синтаксис:
attachInterrupt(interrupt, function, mode)
- interrupt — номер внешнего прерывания. Его можно указать явно (таблица соответствия номеров прерываний выводам Ардуино приведена ниже) или воспользоваться функцией digitalPinToInterrupt(pin) — она вернет номер прерывания по номеру пина.
- function — функция-обработчик прерывания. Эта функция будет вызываться каждый раз при появлении запроса прерывания.
-
mode — определяет события какого типа будут рассматриваться как запрос прерывания. Для данного параметра предусмотрены следующие значения:
- LOW — генерировать запрос прерывания при наличии сигнала низкого уровня;
- RISING — генерировать запрос прерывания при изменении уровня сигнала от низкого к высокому;
- FALLING — генерировать запрос прерывания при изменении уровня сигнала от высокому к низкого;
- CHANGE — генерировать запрос прерывания при любом изменении уровня сигнала;
- для DUE и Zero также доступно значение HIGH.
Плата | INT0 | INT1 | INT2 | INT3 | INT4 | INT5 |
UNO и другие на базе ATmega328/P | 2 | 3 | ||||
Leonardo | 3 | 2 | 1 | 7 | ||
Mega2560 | 2 | 3 | 21 | 20 | 19 | 16 |
digitalPinToInterruptattachInterruptattachInterruptmode
#define ledPin 13 #define interruptPin 2 volatile byte state = LOW; void setup() { pinMode(ledPin, OUTPUT); pinMode(interruptPin, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(interruptPin), blink, FALLING); } void loop() { digitalWrite(ledPin, state); } void blink() { state = !state; }
setupattachInterruptblinkFALLINGblinkstateloopstate