Какие бывают прерывания linux

Обновлено: 03.07.2024

Я просто знаю , что Interrupt это hardware signal assertion вызвано в процессоре штифтом. Но я хотел бы знать, как ОС Linux справляется с этим.
Что все происходит, когда происходит прерывание?

Вот высокоуровневое представление низкоуровневой обработки. Я описываю простую типичную архитектуру, реальные архитектуры могут быть более сложными или отличаться способами, которые не имеют значения на этом уровне детализации.

Когда происходит прерывание , процессор смотрит, маскируются ли прерывания. Если они есть, ничего не происходит, пока они не будут разоблачены. Когда прерывания становятся не маскированными, и если есть какие-либо ожидающие прерывания, процессор выбирает одно.

Затем процессор выполняет прерывание путем ветвления по определенному адресу в памяти. Код по этому адресу называется обработчиком прерываний . Когда процессор там разветвляется, он маскирует прерывания (поэтому обработчик прерываний имеет исключительный контроль) и сохраняет содержимое некоторых регистров в определенном месте (обычно в других регистрах).

Обработчик прерываний делает то, что должен, обычно посредством связи с периферийным устройством, которое инициировало прерывание для отправки или получения данных. Если прерывание было вызвано таймером, обработчик может запустить планировщик ОС, чтобы переключиться на другой поток. Когда обработчик заканчивает выполнение, он выполняет специальную инструкцию возврата из прерывания, которая восстанавливает сохраненные регистры и снимает маскировку прерываний.

Обработчик прерываний должен работать быстро, потому что он предотвращает запуск любого другого прерывания. В ядре Linux обработка прерываний делится на две части:

  • «Верхняя половина» - это обработчик прерываний. Он выполняет необходимый минимум, обычно связывается с оборудованием и устанавливает флаг где-то в памяти ядра.
  • «Нижняя половина» выполняет любую другую необходимую обработку, например копирование данных в память процесса, обновление структур данных ядра и т. Д. Это может занять некоторое время и даже заблокировать ожидание какой-либо другой части системы, поскольку она работает с включенными прерываниями.

Как обычно по этой теме, для получения дополнительной информации прочитайте Драйверы устройств Linux ; Глава 10 о прерываниях.

Жиль уже описал общий случай прерывания, следующее относится конкретно к Linux 2.6 на архитектуре Intel (часть этого также основана на спецификациях Intel).

Прерывание - это событие, которое изменяет последовательность команд, выполняемых процессором.
Существует два вида прерываний:

  • Синхронное прерывание (исключение), создаваемое процессором при обработке инструкций
  • Асинхронное прерывание (Interrupt), выдаваемое другими аппаратными устройствами

Исключения вызваны ошибками программирования (ФЭ ошибка Divide , Page Fault , переполнение ) , которые должны быть обработаны ядром. Он посылает сигнал программе и пытается восстановиться после ошибки.

Следующие два исключения классифицируются:

  • Обнаруженное процессором исключение, сгенерированное ЦП при обнаружении аномального состояния; разделены на три группы: ошибки, как правило, могут быть исправлены, ловушки сообщают о выполнении, прерывания - серьезные ошибки.
  • Запрограммированное исключение, запрошенное программистом, обрабатывается как ловушка.

Прерывания могут выдаваться устройствами ввода-вывода (клавиатура, сетевой адаптер, . ), интервальными таймерами и (в многопроцессорных системах) другими процессорами. Когда происходит прерывание, ЦПУ должен остановить свою текущую инструкцию и выполнить вновь прибывшее прерывание. Он должен сохранить старое состояние прерванного процесса, чтобы (возможно) возобновить его после обработки прерывания.

Обработка прерываний является деликатной задачей:

  • Прерывания могут произойти в любое время, ядро ​​пытается убрать его с дороги как можно скорее.
  • Прерывание может быть прервано другим прерыванием
  • В ядре есть области, которые вообще не должны прерываться

Определены два разных уровня прерывания:

  • Маскируемые прерывания, выдаваемые устройствами ввода / вывода; может быть в двух состояниях, в маске или без маски. Только немаскированные прерывания обрабатываются.
  • Немаскируемые прерывания ; критические неисправности (например, сбой оборудования); всегда обрабатывается процессором.

Каждое аппаратное устройство имеет свою собственную линию запроса прерывания (IRQ). IRQ нумеруются начиная с 0. Все линии IRQ подключены к программируемому контроллеру прерываний (PIC). PIC прослушивает IRQ и назначает их ЦПУ. Также возможно отключить конкретную линию IRQ.
Современные многопроцессорные системы Linux обычно включают в себя более новый Advanced PIC (APIC), который равномерно распределяет запросы IRQ между процессорами.

Промежуточным шагом между прерыванием или исключением и его обработкой является таблица дескрипторов прерываний (IDT). Эта таблица связывает каждый вектор прерывания или исключения (число) с указанным обработчиком (например, ошибка деления обрабатывается функцией divide_error() ).

Благодаря IDT ядро ​​точно знает, как обрабатывать возникшие прерывания или исключения.

Итак, что же делает ядро ​​при возникновении прерывания?

  • Процессор проверяет после каждой инструкции, есть ли IRQ от (A) PIC
  • Если это так, консультируется с IDT для сопоставления полученного вектора с функцией
  • Проверяет, было ли прерывание выдано авторизованным источником
  • Сохраняет регистры прерванного процесса
  • Вызовите соответствующую функцию для обработки прерывания
  • Загрузите недавно сохраненные регистры прерванного процесса и попытайтесь возобновить его
Можете ли вы уточнить «Процессор проверяет после каждой инструкции, есть ли IRQ от (A) PIC» . Как именно это происходит? VIP Связано ли это с -flag в регистре флагов или как? Заранее спасибо

Прежде всего, участниками обработки прерываний являются периферийные аппаратные устройства, контроллер прерываний, процессор, ядро ​​операционной системы и драйверы. Периферийные аппаратные устройства отвечают за генерацию прерываний. Они утверждают строки запроса прерывания, когда хотят внимания от ядра операционной системы. Эти сигналы мультиплексируются контроллером прерываний, который отвечает за сбор сигналов прерываний. Он также отвечает за определение порядка, в котором сигналы прерывания будут передаваться в CPU. Контроллер прерываний может временно отключить определенную строку запроса прерывания (IRQL) и снова включить ее (маскировка IRQL). Контроллер прерываний передает собранные запросы на прерывание ЦП последовательно. CPU после завершения выполнения каждой команды CPU проверяет, есть ли ожидающие запросы прерывания от контроллера прерываний. Если ЦПУ обнаруживает, что имеется ожидающий запрос И флаг включения прерывания установлен во внутреннем регистре управления ЦП, то ЦПУ начинает обработку прерываний. Как вы можете видеть, манипулируя флагом прерывания в ЦП и связываясь с контроллером прерываний, ядро ​​Linux может контролировать принятие прерывания. Например, Linux может отключить прием прерываний от конкретного устройства или вообще запретить прием прерываний. Ядро Linux способно контролировать принятие прерываний. Например, Linux может отключить прием прерываний от конкретного устройства или вообще запретить прием прерываний. Ядро Linux способно контролировать принятие прерываний. Например, Linux может отключить прием прерываний от конкретного устройства или вообще запретить прием прерываний.

Что происходит, когда процессор получает запрос на прерывание? Во-первых, CPU автоматически отключает прерывания путем сброса флага прерываний. Они будут включены после завершения обработки прерываний. В то же время ЦП выполняет минимальный объем работы, необходимый для переключения ЦП из режима пользователя в режим ядра таким образом, чтобы он мог возобновить выполнение прерванного кода. CPU консультируется со специальными структурами управления CPU, заполненными ядром Linux, чтобы найти адрес кода, на который будет передано управление. Этот адрес является адресом первой инструкции обработчика прерываний, которая является частью ядра Linux.

В качестве первого шага обработки прерывания ядро ​​идентифицирует вектор полученного прерывания, чтобы определить, какое событие произошло в системе. Вектор прерывания определяет, какие действия предпримет Linux. В качестве второго шага Linux сохраняет остальные регистры процессора (которые не были сохранены процессором автоматически) и которые потенциально могут использоваться прерванной программой. Это очень важное действие, потому что оно позволяет Linux прозрачно обрабатывать прерывания относительно прерванной программы. В качестве третьего шага Linux завершает переключение в режим ядра, устанавливая среду ядра и устанавливая состояние процессора, необходимое для этого. И, наконец, вызывается вектор-зависимый обработчик прерываний. (Вы можете посмотреть макрос BUILD_INTERRUPT3 в arch \ x86 \ kernel \ entry_32. S, чтобы получить дополнительные подробности для примера, связанного с архитектурой x86) В случае периферийных устройств это процедура do_IRQ (). (Загляните в arch \ x86 \ kernel \ irq.c)

Зависимый от вектора обработчик прерываний обычно переносится вызовами irq_enter () и irq_exit (). Область кода, заключенная в паре этих функций, является атомарной по отношению к любым другим таким областям, а также атомарной по отношению к парам cli / sti. Irq_enter () и irq_exit () также собирают некоторую статистику, связанную с обработкой прерываний. Наконец, ядро ​​просматривает таблицу vector_irq, чтобы найти номер irq, назначенный вектору полученного прерывания, и вызвать handle_irq () (из arch \ x86 \ kernel \ irq_32.c).

На этом общая часть обработки прерываний в Linux заканчивается, потому что ядро ​​рассматривает зависимую от устройства подпрограмму обработчика прерываний, установленную драйвером устройства, как часть дескриптора irq и вызывает ее. Если такой обработчик не был установлен драйвером, ядро ​​просто подтверждает прерывание на контроллере прерываний и переходит к выходу из общего обработчика прерываний.

После окончания обработки прерывания ядро ​​восстанавливает состояние программы, которая была прервана ранее, и возобновляет выполнение этой программы.

Котейка и младшие братья

В предыдущей своей статье я затронула тему многопоточности. В ней речь шла о базовых понятиях: о типах многозадачности, планировщике, стратегиях планирования, машине состояний потока и прочем.

  1. Многозадачность в ядре Linux: прерывания и tasklet’ы

Рассказывать я постараюсь подробно, описывая основное API и иногда углубляясь в особенности реализации, особо заостряя внимание на задаче планирования.

Прерывания и их обработка

  1. Приостанавливается текущий поток управления, сохраняется контекстная информация для возврата в поток.
  2. Выполняется функция-обработчик (ISR ) в контексте отключенных аппаратных прерываний. Обработчик должен выполнить действия, необходимые для данного прерывания.
  3. Оборудованию сообщается, что прерывание обработано. Теперь оно сможет генерировать новые прерывания.
  4. Восстанавливается контекст для выхода из прерывания.
  • Непосредственно ISR, которая вызывается при прерывании, выполняет только самую минимальную работу, которую невозможно отложить на потом: она собирает информацию о прерывании, необходимую для последующей обработки, как-то взаимодействует с аппаратурой, например, блокирует или очищает IRQ от устройства (спасибо jcmvbkbc и Zyoma за уточнение) и планирует вторую часть.
  • Вторая часть, где выполняется основная обработка, запускается уже в другом контексте процессора, где аппаратные прерывания разрешены. Вызов этой части обработчика будет совершен позже.

Tasklet

  • tasklet’ы атомарны, так что из них нельзя использовать sleep() и такие примитивы синхронизации, как мьютексы, семафоры и прочее. Но, например, spinlock (крутящуюся или циклическую блокировку) использовать можно;
  • вызываются в более “мягком” контексте, чем ISR. В этом контексте разрешены аппаратные прерывания, которые вытесняют tasklet’ы на время исполнения ISR. В ядре Linux этот контекст зовется softirq, и помимо запуска tasklet’ов, он используется еще несколькими подсистемами;
  • tasklet исполняется на том же ядре, что и планирует его. А точнее, успело запланировать его первым, вызвав softirq, обработчики которого всегда привязаны к вызывающему ядру;
  • разные tasklet’ы могут выполняться параллельно, но при этом сам с собой он одновременно не вызывается, поскольку исполняется только на одном ядре, первым запланировавшим его исполнение;
  • tasklet’ы выполняются по принципу невытесняющего планирования, один за другим, в порядке очереди. Можно планировать с двумя разными приоритетами: normal и high.

Прежде, чем пользоваться tasklet’ом, его сначала нужно инициализировать:

Планируются tasklet’ы просто: tasklet помещается в одну из двух очередей в зависимости от приоритета. Очереди организованы как односвязные списки. Причем, у каждого CPU эти очереди свои. Делается это с помощью функций:

Когда tasklet запланирован, ему выставляется состояние TASKLET_STATE_SCHED, и он добавляется в очередь. Пока он находится в этом состоянии, запланировать его еще раз не получится — в этом случае просто ничего не произойдет. Tasklet не может находиться сразу в нескольких местах в очереди на планирование, которая организуется через поле next структуры tasklet_struct. Это, впрочем, справедливо для любых списков, связанных через поле объекта, как, например, <linux/list.h>.
На время исполнения tasklet’у присваивается состояние TASKLET_STATE_RUN. Кстати, из очереди tasklet достается перед своим исполнением, а состояние TASKLET_STATE_SCHED снимается, то есть, его можно запланировать снова во время его исполнения. Это может сделать как он сам, так и, к примеру, прерывание на другом ядре. В последнем случае, правда, вызван он будет только после того, как он закончит свое исполнение на первом ядре.

Довольно интересно, что tasklet можно активировать и деактивировать, причем рекурсивно. За это отвечают следующие функции:

Если tasklet деактивирован, его по-прежнему можно добавить в очередь на планирование, но исполняться на процессоре он не будет до тех пор, пока не будет вновь активирован. Причем, если tasklet был деактивирован несколько раз, то он должен быть ровно столько же раз активирован, поле count в структуре как раз для этого.

А еще tasklet’ы можно убивать. Вот так:

Причем, убит он будет только после того, как tasklet исполнится, если он уже запланирован. Если вдруг tasklet планирует сам себя, то нужно перед вызовом этой функции не забыть запретить ему это делать — это на совести программиста.

Интереснее всего функции, которые играют роль планировщика:

Так как они практически одинаковые, то нет смысла приводить код обеих функций. Но вот на одну из них стоит взглянуть, чтобы разобраться поподробнее:

Обратите внимание на вызов функций tasklet_trylock() и tasklet_lock(). tasklet_trylock() выставляет tasklet’у состояние TASKLET_STATE_RUN и тем самым блокирует tasklet, что предотвращает исполнение одного и того же tasklet’а на разных CPU.

Эти функции-планировщики, по сути, реализуют кооперативную многозадачность, которую я подробно рассматривала в своей статье. Функции регистрируются как обработчики softirq, который инициируется при планировании tasklet’ов.

Реализацию всех вышеописанных функций можно посмотреть в файлах include/linux/interrupt.h и kernel/softirq.c.

Продолжение следует

В следующей части я расскажу о гораздо более мощном механизме — workqueue, который также часто используется для отложенной обработки прерываний.

Механизм обработки системы прерываний ядра Linux - детальный анализ

Прерывание означает, что во время нормальной работы ЦПУ ЦПУ временно останавливает работающую программу из-за внутренних или внешних событий или событий, запланированных программой, и вместо этого переходит к программе, которая обслуживает внутреннее или внешнее событие или запланированное событие. По окончании вернитесь, чтобы продолжить запуск временно прерванной программы.

1.1 Тип прерывания

Синхронные прерывания генерируются самим процессором, также известным как внутренние прерывания. Синхронизация здесь относится к синхронному выполнению между сигналом запроса прерывания и инструкцией кода.После завершения выполнения инструкции ЦПУ может прервать ее, и не может быть во время выполнения. Так что это также называется аномалией (exception)。

Асинхронные прерывания генерируются внешними аппаратными устройствами, также известными как внешние прерывания. В отличие от синхронных прерываний, асинхронные прерывания могут создаваться в любое время, в том числе во время выполнения инструкций, поэтому их также называют прерываниями (interrupt)。

Исключения можно разделить на маскируемые прерывания (Maskable interrupt) И немаскированное прерывание (Nomaskable interrupt). Прерывание можно разделить на неисправности (fault), Ловушка (trap), Прекращение (abort) Три категории.

Вообще говоря, прерывания можно разделить на четыре категории:Прерывание、Fault、ловушка、прекращение, Пожалуйста, обратитесь к таблице 1 для сходства и различий между этими категориями.

Таблица 1: Категории прерываний и их поведение

категория

причина

Асинхронный / синхронный

Возвращение поведения

Прерывание

Сигнал с устройства ввода / вывода

Всегда возвращайтесь к следующей инструкции

ловушка

Всегда возвращайтесь к следующей инструкции

Fault

Потенциально исправимые ошибки

Вернуться к текущей инструкции

прекращение

Некоторые справочные материалы классифицируются в соответствии с источником прерывания, как показано на следующем рисунке (личные рекомендации не используют этот метод):


Рисунок 1-1 Рисунок 1-1 Рисунки 1-1

1.2 Различают номер прерывания и направление прерывания

Существует три основных структуры данных для обработки прерываний в ядре Linux: irq_desc, irq_chip и irqaction.

Определено в \ include \ linux \ irq.h

1) irq_desc используется для описания свойств и статуса линии IRQ и называется дескриптором прерывания.

2) irq_chip используется для описания различных типов контроллеров прерываний.

В \ include \ linux \ interrupt.h определяется irqaction для описания дескриптора прерывания, сгенерированного конкретным устройством.

Механизм прерываний Linux состоит из трех частей:

  1. Инициализация подсистемы прерываний: Ядро само инициализирует механизм обработки прерываний в процессе инициализации, такой как структура данных прерываний и запрос прерываний.
  2. Обработка прерываний или исключений: прерывать общую обработку.
  3. API прерывания. Предоставьте API для драйверов устройств, таких как регистрация, освобождение и активация.

3.1Инициализация подсистемы прерываний

3.1.1 Инициализация таблицы дескрипторов прерываний (IDT)

Инициализация таблицы дескрипторов прерываний должна проходить через два процесса:

  1. Первый процесс находится в процессе загрузки ядра. Он состоит из двух этапов: во-первых, выделите пространство 2 КБ (256 векторов прерываний, каждый вектор состоит из 8 бит) для IDT и инициализируйте его, затем сохраните начальный адрес IDT в регистре IDTR.
  2. Во втором процессе ядро ​​использует trap_init для инициализации системы, чтобы сохранить вектор прерывания в своей собственной функции start_kernal, и использует init_IRQ для завершения оставшейся инициализации вектора прерывания.

3.1.2 Инициализация очереди запросов на прерывание

init_IRQ вызывает pre_intr_init_hook и, наконец, вызывает init_ISA_irqs для инициализации контроллера прерываний и очереди запросов на прерывание для каждой строки IRQ.

3.2Обработка прерываний или исключений

Обработка прерываний: устройство генерирует прерывание и отправляет сигнал прерывания на контроллер прерываний через линию прерывания. Если прерывание не маскируется, оно достигнет вывода INTR ЦПУ. ЦПУ немедленно останавливает текущую работу в соответствии с номером вектора прерывания, полученным из IDT. Найдите дескриптор шлюза и выполните соответствующую программу прерывания.

Процесс обработки исключений: Исключение генерируется внутренним процессором ЦПУ, поэтому оно не проходит контроллер прерываний.ЦП непосредственно находит дескриптор шлюза из IDT в соответствии с номером вектора прерывания и выполняет соответствующую программу прерывания.


Рисунок 3-1 Рисунок 3-1 Рисунок 3-1 Рисунок 3-2 Рисунок 3-1

Процесс обработки контроллера прерываний состоит из пяти основных этапов: 1. Запрос прерывания 2. Ответ на прерывание 3. Сравнение приоритетов 4. Передача вектора прерывания 5. Окончание прерывания. Конкретный поток из пяти шагов не будет повторяться здесь.

Процесс обработки состоит из 6 основных этапов: 1. Идентифицировать прерывание или ненормальный вектор прерывания. 2. Найти IDT через регистр IDTR. 3. Проверка привилегий. 4. Изменение уровня привилегий и переключение стека. 5. Если это исключение, поместите код исключения в стек. , Если это прерывание, закройте маскируемое прерывание 6. Введите прерывание или ненормальное выполнение служебной программы. Конкретный поток из шести шагов не будет повторяться здесь.

3.3API прерываний

API, предоставляемый ядром, в основном используется для разработки драйверов.

Примечание: ресурсы линии IRQ очень ценны, мы должны сначала зарегистрироваться при использовании, и должны освободить ресурсы IRQ, когда они не используются.

Активировать текущее прерывание процессора:

Отключить текущее прерывание процессора:

Активируйте указанную линию прерывания:

Запрещено указывать строку прерывания:

Запрещено указывать строку прерывания:

Примечание. Эта функция вызывает отключение в irq_chip для отключения указанной строки прерывания, поэтому нет гарантии, что программа обработки прерывания, выполненная в строке прерывания, завершилась.

3.4 Механизм прерывания

Поскольку прерывания будут прерывать нормальное планирование и запуск процессов в ядре, программа обработки прерываний должна быть как можно более короткой и краткой, насколько это возможно, но в реальных системах, когда появляются прерывания, выполнение работы часто отнимает много времени. Поэтому я надеюсь, что обработчик прерываний будет работать быстро, и я хочу, чтобы он выполнял рабочую нагрузку, эти две цели ограничивают друг друга, механизм верхней / нижней половины.

Обработчик прерываний - это верхняя половина, принимающая прерывание, и он немедленно начнет выполнение, но выполняет работу только в строгих временных рамках. Работы, которые могут быть допущены к выполнению позднее, будут перенесены в нижнюю половину, после чего в соответствующее время нижняя половина будет открыта для выполнения. Верхняя половина проста и быстра, а некоторые или все прерывания запрещены во время исполнения.

Нижняя половина выполняется позже, и на все прерывания можно ответить во время выполнения. Такая конструкция может сделать систему в состоянии экранирования прерываний как можно короче, чтобы улучшить отзывчивость системы. В верхней половине есть только механизм обработки прерываний, а в нижней - программные прерывания, реализации тасклетов и очереди работ.


3.4.1Принцип деления верхней / нижней половины:

1) Если задача очень чувствительна ко времени, поместите ее в верхнюю половину;

2) Если задача связана с оборудованием, поместите ее в верхнюю половину для выполнения;

3) Если задача гарантированно не будет прервана другими прерываниями, поместите ее в верхнюю половину для выполнения;

4) Все остальные задачи должны быть размещены в нижней половине для выполнения.

3.4.2 Нижняя половина механизма реализации


Рисунок 3-3 Рисунок 3-3 Рисунок 3-3 Рисунок 3-3 Рисунок 3-3.

Мягкое прерывание:

Как представитель второй половины механизма, мягкое прерывание возникло с появлением SMP (процессора общей памяти), а также является основой для реализации тасклета (тасклет фактически добавляет только определенный механизм на основе мягкого прерывания). Мягкие прерывания, как правило, являются общим термином для «задерживаемых функций» и иногда включают в себя тасклеты (пожалуйста, сделайте вывод, включен ли тасклет на основе контекста, когда читатель встречает его). Он возник из-за разницы между верхней и нижней половинами, предложенной выше, так что независящие от времени задачи задерживаются, и обработчик прерываний выполнения мягкого прерывания остается для него для выполнения оставшихся задач, и это может быть Параллельное выполнение на нескольких процессорах повышает общую эффективность системы. Его функции включают в себя:

a) Он не может быть выполнен сразу после того, как сгенерирован, он должен ждать выполнения планирования ядра. Мягкие прерывания не могут быть прерваны сами по себе, но только аппаратными прерываниями (верхняя половина).

b ) Может работать одновременно на нескольких процессорах (даже один и тот же тип). Таким образом, мягкие прерывания должны быть спроектированы как повторяющиеся функции (позволяющие нескольким процессорам работать одновременно), поэтому спин-блокировки также необходимы для защиты их структур данных.

Назначение нескольких программных прерываний определено в ядре:

Tasklet :

Тасклет реализуется с помощью мягкого прерывания, поэтому оно также является программным прерыванием.

Мягкие прерывания обрабатываются опросом. Если это последний тип прерывания, все типы прерываний должны быть зациклены, прежде чем соответствующая функция обработки может быть наконец выполнена. Очевидно, что для обеспечения эффективности опроса разработчики ограничивали количество прерываний до 32.

Чтобы увеличить количество обработки прерываний и повысить эффективность обработки, был создан механизм тасклетов.

Тасклет использует беспорядочный механизм очереди и выполняется только при прерывании, что избавляет от необходимости поиска по круглой таблице. Как новый механизм, Tasklet, очевидно, может иметь больше преимуществ В настоящее время SMP становится все более популярным, поэтому механизм механизма SMP добавляется в тасклет, чтобы гарантировать, что один и тот же тип прерывания может быть выполнен только на одном процессоре. В эпоху мягких перерывов такого рассмотрения явно не было. Следовательно, одно и то же мягкое прерывание может выполняться одновременно на двух процессорах, что может вызвать конфликты.

Суммируйте преимущества тасклета:

(1) Нет ограничения по количеству типов;

(2) Высокая эффективность, нет необходимости в круглом столе поиска;

(3) Поддержка механизма SMP;

Его характеристики следующие:

1) Определенный тип тасклета может работать только на одном процессоре, не параллельно, а только последовательно.

2) Несколько разных типов тасклетов могут быть распараллелены на нескольких процессорах.

3 ) Мягкое прерывание статически размещено и не может быть изменено после компиляции ядра. Но тасклеты гораздо более гибки и могут быть изменены во время выполнения (например, при добавлении модулей).

Очередь работ:

Отложенные функции, которые мы представили выше, выполняются в контексте прерывания, что вызывает некоторые проблемы, указывающие на то, что они не могут быть приостановлены, то есть мягкие прерывания не могут спать или блокироваться, потому что контекст прерывания находится в режиме ядра и нет переключения процессов. Таким образом, если мягкое прерывание находится в спящем режиме или заблокировано, оно не сможет выйти из этого состояния, в результате чего ядро ​​будет полностью мертвым. Поэтому блокируемые функции не могут быть реализованы с мягкими прерываниями. Но они часто имеют характеристики задержки. И поскольку он выполняется последовательно, пока одно время обработки больше, это вызовет задержку ответа другого прерывания. Для выполнения этих невозможных задач появляется рабочая очередь, которая может переключаться между разными процессами для выполнения разных задач.

Рабочая очередь может запускаться в контексте процесса, она будет работать с потоком ядра, как с потоком демона прерывания для использования. Несколько прерываний могут быть помещены в поток, или поток может быть назначен каждому прерыванию. Мы используем структуру workqueue_struct для представления рабочих потоков, рабочие потоки реализованы с помощью потоков ядра. И как рабочий поток выполняет отложенную работу - существует такой связанный список, который состоит из структуры work_struct, и эта work_struct описывает работу; после завершения работы соответствующий объект work_struct берется из связанного списка. Удалено, когда в связанном списке больше нет объектов, рабочий поток будет продолжать спать. Поскольку рабочие очереди являются потоками, мы можем использовать все методы, которые можно использовать в потоках.

Как выбрать механизм второй половины:

  1. Мягкое прерывание и tasklet Запуск в контексте прерывания, рабочая очередь выполняется в контексте процесса. Если вам нужно спать, выберите рабочую очередь, в противном случае выберите тасклет, а если требования к производительности высоки, выберите мягкое прерывание.
  2. Для простоты использования рабочая очередь предпочтительнее, а затем tasklet И, наконец, мягкое прерывание, потому что мягкое прерывание должно быть создано статически.
  3. С точки зрения безопасности кода, если нижняя половина защиты кода недостаточно безопасна, выберите tasklet Из-за относительно мягких прерываний у тасклетов низкие требования к блокировке. Выше также кратко описаны их методы работы и сценарии применения.

4.1 Межпроцессорное прерывание

В многопроцессорной системе операционной системе необходимо координировать операции между несколькими процессорами, поэтому требуется прерывание процессора (Inter-Processor-Interrupt, IPI). IPI - это специальное аппаратное прерывание, отправленное ЦП и полученное другими ЦП. Обработка связи и синхронизации между процессорами. Ниже приведен IPI, определенный SMP в x86. Номер вектора прерывания выражается в шестнадцатеричном виде:

4.2 Прерывание сродства

Связывание одной или нескольких подпрограмм обработки прерываний с конкретным ЦП - это сходство прерываний (сходство SMP IRQ). Мы можем использовать привязку прерываний, чтобы сбалансировать нагрузку каждого ЦП и улучшить вычислительную мощность системы.

Выше мое право Linux Прерванное понимание, если есть какие-либо ошибки, пожалуйста, исправьте меня!

Управление аппаратными устройствами, которые подключены к вычислительной машине, — это одна из самых ответственных функций ядра. Частью этой работы является необходимость взаимодействия с отдельными устройствами машины. Поскольку процессоры обычно работают во много раз быстрее, чем аппаратура, с которой они должны взаимодействовать, то для ядра получается неэффективным отправлять запросы и тратить время, ожидая ответы от потенциально более медленного оборудования. Учитывая небольшую скорость отклика оборудования, ядро должно иметь возможность оставлять на время работу с оборудованием и выполнять другие действия, пока аппаратное устройство не закончит обработку запроса. Одно из возможных решений этой проблемы — периодический опрос оборудования (polling). Ядро периодически может проверять состояние аппаратного устройства системы и соответственным образом реагировать. Однако такой подход вносит дополнительные накладные расходы, потому что, независимо от того, готов ответ от аппаратного устройства или оно еще выполняет запрос, все равно осуществляется постоянный систематический опрос состояния устройства через постоянные интервалы времени. Лучшим решением является обеспечение механизма, который позволяет подавать ядру сигнал о необходимости уделить внимание оборудованию. Такой механизм называется прерыванием (interrupt).

Прерывания позволяют аппаратным устройствам взаимодействовать с процессором. Например, при наборе на клавиатуре контроллер клавиатуры (или другое устройство, которое обслуживает клавиатуру) генерирует прерывание, чтобы объявить операционной системе о том, что произошли нажатия клавиш. Прерывания — это специальные электрические сигналы, которые аппаратные устройства посылают процессору. Процессор получает прерывание и дает сигнал операционной системе о том, что ОС может обработать новые данные. Аппаратные устройства генерируют прерывания асинхронно по отношению к тактовому генератору процессора — прерывания могут возникать непредсказуемо, в любой момент времени. Следовательно, работа ядра может быть прервана в любой момент для того, чтобы обработать прерывания.

Физически прерывания производятся электрическими сигналами, которые создаются устройствами и направляются на входные контакты микросхемы контроллера прерываний. Контроллер прерываний в свою очередь отправляет сигнал процессору. Процессор выполняет детектирование сигнала и прерывает выполнение работы для того, чтобы обработать прерывание. После этого процессор извещает операционную систему о том, что произошло прерывание и операционная система может соответствующим образом это прерывание обработать.

Различные устройства связаны со своими прерываниями с помощью уникальных числовых значений, соответствующих каждому прерыванию. Отсюда следует, что прерывания, поступившие от клавиатуры, отличаются от прерываний, поступивших от жесткого диска. Это позволяет операционной системе различать прерывания и иметь информацию о том, какое аппаратное устройство произвело данное прерывание. Поэтому операционная система может обслуживать каждое прерывание с помощью своего уникального обработчика.

Идентификаторы, соответствующие прерываниям, часто называются линиями запросов на прерывание (interrupt request lines, IRQ lines). Обычно это некоторые числа. Например, для платформы PC значение IRQ, равное 0, — это прерывание таймера, a IRQ, равное 1, — прерывание клавиатуры. Однако не все номера прерываний жестко определены. Прерывания, связанные с устройствами шины PCI, например, назначаются динамически. Другие платформы, которые не поддерживают стандарт PCI, имеют аналогичные функции динамического назначения номеров прерываний. Основная идея состоит в том, что определенные прерывания связаны с определенными устройствами, и у ядра есть вся эта информация. Аппаратное обеспечение, чтобы привлечь внимание ядра, генерирует прерывание вроде «Эй! Было новое нажатие клавиши! Его необходимо обработать!».

Исключительные ситуации (exceptions) часто рассматриваются вместе с прерываниями. В отличие от прерываний, они возникают синхронно с тактовым генератором процессора. И действительно, их часто называют синхронными прерываниями. Исключительные ситуации генерируются процессором при выполнении машинных инструкций как реакция на ошибку программы (например, деление на нуль) или как реакция на аварийную ситуацию, которая может быть обработана ядром (например, прерывание из-за отсутствия страницы, page fault). Так как большинство аппаратных платформ обрабатывают исключительные ситуации аналогично обработке прерываний, то инфраструктуры ядра, для обоих видов обработки, также аналогичны. Большая часть материала, посвященная обработке прерываний (асинхронных, которые генерируются аппаратными устройствами), также относится и к исключительным ситуациям (синхронным, которые генерируются самим процессором).
С одним типом исключительной ситуации мы уже встречались в предыдущей главе. Там было рассказано, как для аппаратной платформы x86 реализованы системные вызовы на основе программных прерываний. При этом генерируется исключительная ситуация, которая заставляет переключиться в режим ядра и в конечном итоге приводит к выполнению определенного обработчика системного вызова. Прерывания работают аналогичным образом, за исключением того, что прерывания генерируются не программным, а аппаратным обеспечением.

Функция, которую выполняет ядро в ответ на определенное прерывание, называется обработчиком прерывания (interrupt handler) или подпрограммой обслуживания прерывания (interrupt service routine). Каждому устройству, которое генерирует прерывания, соответствует свой обработчик прерывания. Например, одна функция обрабатывает прерывание от системного таймера, а другая — прерывания, сгенерированные клавиатурой. Обработчик прерывания для какого-либо устройства является частью драйвера этого устройства — кода ядра, который управляет устройством.

В операционной системе Linux обработчики прерываний — это обычные функции, написанные на языке программирования С. Они должны соответствовать определенному прототипу, чтобы ядро могло стандартным образом принимать информацию об обработчике, а в остальном— это обычные функции. Единственное, что отличает обработчики прерываний от других функций ядра, — это то, что они вызываются ядром в ответ на прерывание и выполняются в специальном контексте, именуемом контекстом прерывания (interrupt context), который будет рассмотрен далее.

Верхняя и нижняя половины

Ясно, что два указанных требования о том, что обработчик прерывания должен выполняться быстро и, в дополнение к этому, выполнять много работы, являются противоречивыми. В связи с конфликтными требованиями, обработчик прерываний разбивается на две части, или половины. Обработчик прерывания является верхней половиной (top half) — он выполняется сразу после приема прерывания и выполняет работу, критичную к задержкам во времени, такую как отправка подтверждения о получении прерывания или сброс аппаратного устройства. Работа, которую можно выполнить позже, откладывается до выполнения нижней (или основной) половины (bottom half). Нижняя половина обрабатывается позже, в более удобное время, когда все прерывания разрешены. Достаточно часто нижняя половина выполняется сразу же после возврата из обработчика прерывания.

Операционная система предоставляет различные механизмы для реализации обработки нижних половин, которые обсуждаются в главе 7, "Обработка нижних половин и отложенные действия".

Обработчик прерывания выполняется, аппаратному обеспечению направляется подтверждение, пакеты копируются в основную память, и после этого сетевой адаптер готов к получению новых пакетов. Эта задача является важной, критичной ко времени выполнения и специфической для каждого типа аппаратного обеспечения. Остальная часть обработки сетевых пакетов выполняется позже — нижней половиной обработчика прерывания. В этой главе мы рассмотрим обработку верхних половин, а в следующей — нижних.

Ответственность за обработчики прерываний лежит на драйверах устройств, которые управляют определенным типом аппаратного обеспечения. С каждым устройством связан драйвер, и если устройство использует прерывания (а большинство использует), то драйвер должен выполнить регистрацию обработчика прерывания.

Драйвер может зарегистрировать обработчик прерывания для обработки заданной линии с помощью следующей функции.

/* request_irq: выделить заданную линию прерывания */

int request_irq(unsigned int irq,

irqreturn_t (*handler)(int, void*, struct pt_regs*),

unsigned long irqflags, const char* devname, void *dev_id);

Первый параметр, irq, указывает назначаемый номер прерывания. Для некоторых устройств, таких как, например, обычные устройства персонального компьютера, таймер и клавиатура, это значение, как правило, жестко закреплено. Для большинства других устройств это значение определяется путем проверки (probing) или другим динамическим способом.

Второй параметр, handler, — это указатель на функцию обработчика прерывания, которая обслуживает данное прерывание. Эта функция вызывается, когда в операционную систему приходит прерывание. Следует обратить внимание на специфический прототип функции-обработчика. Она принимает три параметра и возвращает значение типа irqreturn_t. Ниже в этой главе мы более подробно обсудим эту функцию.

Третий параметр, irqflags, может быть равным нулю или содержать битовую маску с одним или несколькими следующими флагами.

• SA_INTERRUPT. Этот флаг указывает, что данный обработчик прерывания — это быстрый обработчик прерывания. Исторически так сложилось, что операционная система Linux различает быстрые и медленные обработчики прерываний. Предполагается, что быстрые обработчики выполняются быстро, но потенциально очень часто, поэтому поведение обработчика прерывания изменяется, чтобы обеспечить максимально возможную скорость выполнения. Сегодня существует только одно отличие: при выполнении быстрого обработчика прерываний запрещаются все прерывания на локальном процессоре. Это позволяет быстрому обработчику завершится быстро, и другие прерывания никак этому не пометают. По умолчанию (если этот флаг не установлен) разрешены все прерывания, кроме тех, которые маскированы на всех процессорах и обработчики которых в данный момент выполняются. Для всех прерываний, кроме прерываний таймера, нет необходимости устанавливать этот флаг.

• SA_SAMPLE_RANDOM. Этот флаг указывает, что прерывания, сгенерированные данным устройством, должны вносить вклад в пул энтропии ядра. Пул энтропии ядра обеспечивает генерацию истинно случайных чисел на основе различных случайных событий. Если этот флаг указан, то моменты времени, когда приходят прерывания, будут введены в пул энтропии. Этот флаг нельзя устанавливать, если устройство генерирует прерывания в предсказуемые моменты времени (как, например, системный таймер) или на устройство может повлиять внешний злоумышленник (как, например, сетевое устройство). С другой стороны, большинство устройств генерируют прерывания в непредсказуемые моменты времени и поэтому являются хорошим источником энтропии. Для более подробного описания пула энтропии ядра см.. приложение Б, "Генератор случайных чисел ядра".

• SA_SHIRQ. Этот флаг указывает, что номер прерывания может совместно использоваться несколькими обработчиками прерываний (shared). Каждый обработчик, который регистрируется на одну и ту же линию прерывания, должен указывать этот флаг. В противном случае для каждой линии может существовать только один обработчик прерывания. Более подробная информация о совместно используемых обработчиках прерываний приведена в следующем разделе.

Четвертый параметр, devname, — это ASCII-строка, которая описывает, какое устройство связано с прерыванием. Например, для прерывания клавиатуры персонального компьютера это значение равно "keyboard". Текстовые имена устройств применяются для взаимодействия с пользователями с помощью интерфейсов /proc/irq и /proc/interrupts, которые вскоре будут рассмотрены.

Пятый параметр, dev_id, в основном, применяется для совместно используемых линий запросов на прерывания. Когда обработчик прерывания освобождается (описано ниже), параметр dev_id обеспечивает уникальный идентификатор (cookie), который позволяет удалять только необходимый обработчик линии прерывания. Без этого параметра было бы невозможно ядру определить, какой обработчик данной линии прерывания следует удалить. Если линия запроса на прерывание не является совместно используемой, то можно в качестве этого параметра указывать NULL, если же номер прерывания является совместно используемым, то необходимо указывать уникальный идентификатор (cookie) (если устройство не подключено к тине ISA, то, скорее всего, оно поддерживает совместно используемые номера прерываний).

Этот параметр также передается обработчику прерывания при каждом вызове. Обычная практика — это передача указателя на структуру устройства (контекст устройства), так как этот параметр является уникальным, и, кроме того, в обработчике прерывания может быть полезным иметь указатель на эту структуру.

Следует обратить внимание, что функция request_irq() может переходить в состояние ожидания (sleep) и, соответственно, не может вызываться из контекста прерывания, или в других ситуациях, когда код не может блокироваться. Распространенной ошибкой является мнение, что функцию request_irq() можно безопасно вызывать в случаях, когда нельзя переходить в состояние ожидания. Это происходит отчасти от того, что действительно сразу непонятно, почему функция request_irq() должна чего-то ожидать. Дело в том. что при регистрации происходит добавление информации о линии прерывания в каталоге /proc/irq. Функция proc_mkdir() используется для создания новых элементов на файловой системе procfs. Эта функция вызывает функцию proc_create() для создания новых элементов файловой системы procfs, которая в свою очередь вызывает функцию kmalloc() для выделения памяти. Как будет показано в главе 11, "Управление памятью", функция kmalloc() может переходить в состояние ожидания. Вот так вот!

Для регистрации линии прерывания и инсталляции обработчика в коде драйвера можно использовать следующий вызов.

if (request_irq(irqn, my_interrupt, SA_SHIRQ, "my_device", dev))

printk(KERN_ERR "my_device: cannot register IRQ %d\n", irqn);

Читайте также: