Отложенный вызов процедуры что должна показать. Процедуры обработки прерываний и текущий процесс. Всё произошло как-то вдруг, после перезагрузки

Объекты управления включают объекты-примитивы для потоков, прерываний, таймеров, синхронизации, профилирования, а также два специальных объекта для реализации DPC и APC. Объекты DPC (Deferred Procedure Call - отложенный вызов процедуры) используются для уменьшения времени выполнения ISR (Interrupt Service Routines - процедура обслуживания прерываний), которая запускается по прерыванию от устройства. Ограничение времени, затрачиваемого на ISR-процедуры, сокращает шансы утраты прерывания.

Оборудование системы присваивает прерываниям аппаратный уровень приоритета. Процессор также связывает уровень приоритета с выполняемой им работой. Процессор реагирует только на те прерывания, которые имеют более высокий приоритет, чем используемый им в данный момент. Нормальный уровень приоритета (в том числе уровень приоритета всего пользовательского режима) - это 0. Прерывания устройств происходят с уровнем 3 или более высоким, а ISR для прерывания устройства обычно выполняется с тем же уровнем приоритета, что и прерывание (чтобы другие менее важные прерывания не происходили при обработке более важного прерывания).

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

Для уменьшения времени обработки ISR выполняются только критические операции, такие как запись результатов операций ввода-вывода и повторная инициализация устройства. Дальнейшая обработка прерывания откладывается до тех пор, пока уровень приоритета процессора не снизится и не перестанет блокировать обслуживание других прерываний. Объект DPC используется для представления подлежащей выполнению работы, а ISR вызывает уровень ядра для того, чтобы поставить DPC в список DPC конкретного процессора. Если DPC является первым в списке, то ядро регистрирует специальный аппаратный запрос на прерывание процессора с уровнем 2 (на котором NT вызывает уровень DISPATCH). Когда завершается последняя из существующих ISR, уровень прерывания процессора падает ниже 2, и это разблокирует прерывание для обработки DPC. ISR для прерывания DPC обработает каждый из объектов DPC (которые ядро поставило в очередь).

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

Аналогичным примером в современной системе Windows может служить клавиатура. После нажатия клавиши клавиатурная ISR читает из регистра код клавиши, а затем опять разрешает клавиатурное прерывание, но не делает обработку клавиши немедленно. Вместо этого она использует DPC для постановки обработки кода клавиши в очередь (до того момента, пока все подлежащие обработке прерывания устройства не будут отработаны).

Поскольку DPC работают на уровне 2, они не мешают выполнению ISR для устройств, но мешают выполняться любым потокам до тех пор, пока все поставленные в очередь DPC не завершатся и уровень приоритета процессора не упадет ниже 2. Драйверы устройств и система не должны слишком долго выполнять ISR или DPC. Поскольку потокам не разрешается выполняться, то ISR и DPC могут сделать систему медлительной и породить сбои при проигрывании музыки (затормаживая те потоки, которые пишут музыку из буфера в звуковое устройство). Другой частый случай использования DPC - это выполнение процедур по прерыванию таймера. Во избежание блокирования потоков события таймера (которые должны выполняться продолжительное время) должны ставить в очередь запросы к пулу рабочих потоков (который ядро поддерживает для фоновой работы).

Вдобавок к использованию для работы Диспетчера (планировщика) NT, IRQL dispatch_level также используется для обработки Отложенных Вызовов Процедур (DPC). Вызовы DPC - обратные вызовы подпрограмм, которые будут выполнены на IRQL dispatchjevel. Вызовы DPC обычно запрашиваются с более высоких уровней IRQL, для осуществления расширенной, не критической по времени обработки.

Давайте рассмотрим пару примеров того, когда используются DPC. Драйверы устройств Windows NT выполняют очень небольшую обработку внутри своих подпрограмм обслуживания прерывания. Вместо этого, когда устройство прерывается (на уровне DIRQL) и его драйвер определяет, что требуется сложная обработка, драйвер запрашивает DPC. Запрос DPC приводит к обратному вызову определенной функции драйвера на уровне IRQL dispatch_level для выполнения оставшейся части требуемой обработки. Выполняя эту обработку на IRQL dispatch_level, драйвер проводит меньшее количество времени на уровне DIRQL, и, следовательно, уменьшает время задержки прерывания для всех других устройств в системе.

На рис. 15 изображена типовая последовательность событий.

Вначале ISR запрашивает DPC и NT помещает объект DPC в очередь целевого процессора. В зависимости от приоритета DPC и длины очереди DPC, NT генерирует программное прерывание DPC сразу же или спустя некоторое время. Когда процессор очищает очередь DPC, объект DPC покидает очередь и управление передается в его функцию DPC, завершающую обработку прерывания путем чтения данных из устройства или записи данных в устройство, сгенерировавшего прерывание.
Другое распространенное использование DPC - подпрограммы таймера. Драйвер может запросить выполнение конкретной функции для уведомления об истечении определенного периода времени (это делается путем использования функции KeSetTimer()). Программа обработки прерывания часов следит за прохождением времени, и, по истечении определенного периода времени, запрашивает DPC для подпрограммы, определенной драйвером. Использование DPC для таймерного уведомления позволяет программе обработки прерывания часов возвращаться быстро, но все же приводить к вызову указанной процедуры без чрезмерной задержки.

DPC-объекты

Вызов DPC описывается Объектом DPC. Определение Объекта DPC (KDPC) произведено в ntddk.h и показано на рис. 16.

Рис. 16. Объект DPC

Объект DPC может быть выделен драйвером из любого невыгружаемого пространства (типа невыгружаемого пула). Объекты DPC инициализируются, используя функцию KelnitializeDpc(), прототип которой:

VOID KelnitializeDpc (IN PKDPC Dpc,
IN PKDEFERRED^ROUTINE DeferredRoutine,
IN PVOID DeferredContext);

Где:
Dpc - Указатель на DPC объект, который надо инициализировать; DeferredRoutine - указатель на функцию, по которому должен быть сделан отложенный вызов на уровне IRQL DISPATCH_LEVEL. Прототип функции DeferredRoutine следующий:

VOID (*PKDEFERRED_ROUTINE)(
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgumentI,
IN PVOID SystemArgument2);

Где:
DeferredContext - значение для передачи к DeferredRoutine в качестве параметра, вместе с указателем на объект DPC и двумя дополнительными параметрами.
Запрос на выполнение конкретной подпрограммы DPC делается путем помещения объекта DPC, описывающего эту подпрограмму DPC, в Очередь DPC заданного CPU, и последующим (обычно) запросом программного прерывания уровня IRQL
dispatch_level. Имеется по одной Очереди DPC на процессор. CPU, к которому объект DPC поставлен в очередь, является обычно текущим процессором, на котором выдан запрос (на прерывание). Как выбирается процессор для конкретного DPC, обсуждается позже, в разделе "Характеристики Объекта DPC". Объект DPC ставится в очередь с помощью функцию KelnsertQueueDpc(), прототип которой:

VOID KelnsertQueueDpc (IN PKDPC Dpc,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2);

Где:
Dpc - Указывает на объект DPC, который нужно поставить в очередь;
SystemArgumentl, SystemArgument2 - произвольные значения, которые нужно передать функции DeferredRoutme как 3 и 4 параметры соответственно, наряду с указателем на объект DPC и параметром DeferredContext, определенным при инициализации Объекта DPC.

Активизация и обслуживание DPC

Происхождение программного прерывания уровня Dispatch_level распознается тогда, когда это прерывание становится наивысшим по уровню IRQL событием, ожидающем обработки на этом процессоре. Таким образом, после вызова функции KelnsertQueueDpc(), обычно в следующий раз, когда процессор готов возвратиться на уровень IRQL ниже dispatch_level, вместо этого он вернется на IRQL dispatch_level и попытается обработать содержимое Очереди DPC.
Как отмечено ранее в этой главе, IRQL DISPATCHJLEVEL используется как для диспетчеризации,так и для обработки Очереди DPC. В NT 4.0, когда обработано прерывание уровня DISPATCH_LEVEL, сначала обслуживается вся очередь DPC, и затем вызывается Диспетчер для планирования выполнения следующего потока. Это разумно, потому что обработка, сделанная подпрограммой DPC, могла изменить состояние базы данных планирования потоков, например, делая работоспособным ожидающий до того поток.
Очередь DPC обслуживается Микроядром. Каждый раз, когда обслуживается Очередь DPC, обрабатываются все элементы Очереди DPC для текущего процессора. По одному за раз, Микроядро удаляет Объект DPC из начала очереди и вызывает DeferredRoutine, указанную в объекте. Микроядро передает в качестве параметров для функции DeferredRoutine указатель на Объект DPC, содержимое полей DeferredContext, SystemArgumentl и SystemArgument2 Объекта DPC.
Поскольку Очередь DPC обслуживается на IRQL dispatch_level, подпрограммы DPC вызываются на IRQL dispatch_level. Поскольку Очередь DPC обслуживается всякий раз, когда IRQL dispatch_level является самым высокоприоритетным IRQL для обслуживания (например, сразу после того, как отработала программа обработки прерывания и перед возвращением к прерванному потоку пользователя), функции DPC работают в контексте произвольного потока (arbitrary thread context). Под контекстом произвольного потока мы подразумеваем, что DPC выполняется в процессе и потоке, которые могут вообще не иметь никакого отношения к запросу, который обрабатывает DPC. (Контекст выполнения описан более подробно в разделе "Многоуровневая Модель Драйверов".)
Подпрограмма DPC завершает обработку и возвращается. По возвращении из подпрограммы DPC, Микроядро пытается выбрать другой Объект DPC из Очереди DPC и обрабатывать его. Когда очередь DPC пуста, обработка DPC заканчивается. Микроядро переходит к вызову Диспетчера (планировщика).

Многочисленные обращения к DPC

Каждый DPC описан конкретным Объектом DPC. В результате всякий раз, когда вызывается функция KelnsertQueueDpc() и выясняется, что переданный ей Объект DPC уже находится в той же самой Очереди DPC, функция KelnsertQueueDpcQ просто возвращается (не выполняя никаких действий). Таким образом, всякий раз, когда Объект DPC уже находится в Очереди DPC, любые последующие попытки постановки в очередь того же самого Объекта DPC, осуществляемые до удаления Объекта DPC из очереди, игнорируются. Это имеет смысл, так как Объект DPC может физически быть включен только в одну Очередь DPC одновременно.
Может возникнуть очевидный вопрос: Что произойдет, когда сделан запрос постановки Объекта DPC в очередь, но система уже выполняет подпрограмму DPC, указанную этим Объектом DPC (на этом же или другом процессоре)? Ответ на этот вопрос может быть найден при внимательном чтении предыдущего раздела. Когда Микроядро обслуживает Очередь DPC, оно удаляет Объект DPC из головы очереди, и только потом вызывает подпрограмму DPC, указанную Объектом DPC. Таким образом, когда подпрограмма DPC вызвана, Объект DPC уже удален из Очереди DPC процессора. Поэтому, когда сделан запрос на постановку Объекта DPG в очередь и система находится внутри подпрограммы DPC, заданной в этом Объекте DPC, DPC ставится в очередь как обычно.

DPC на многопроцессорных системах

Вопреки тому, что утверждалось в некоторых других источниках, и, как должно быть очевидно из предшествующего обсуждения, одна и та же подпрограмма DPC может выполняться на нескольких процессорах одновременно. Нет абсолютно никакого блокирования со стороны Микроядра, чтобы предотвратить это.
Рассмотрим случай драйвера устройства, который в одно и то же время имеет несколько запросов, ожидающих обработки. Устройство драйвера прерывается на Процессоре 0, выполняется программа обработки прерывания драйвера и запрашивает DPC для завершения обработки прерывания. Это стандартный путь, которому следуют драйверы в Windows NT. Когда завершается программа обработки прерывания, и система готова возвратиться к прерванному потоку пользователя, уровень IRQL процессора О понижается от DIRQL, на котором выполнялась ISR, до IRQL dispatch_level. В результате, Микроядро обслуживает Очередь DPC, удаляя Объект DPC драйвера и вызывая указанную в нем подпрограмму DPC. На Процессоре 0 теперь выполняется подпрограмма DPC драйвера.
Сразу после вызова подпрограммы DPC драйвера, устройство генерирует прерывание еще раз. Однако на этот раз, по причинам, известным только аппаратуре, прерывание обслуживается на Процессоре 1. Снова, программа обработки прерывания драйвера запрашивает DPC. И, снова, когда программа обработки прерывания закончится, система (Процессор 1) готова возвратиться к прерванному потоку пользователя. При этом IRQL процессора 1 понижается до уровня IRQL dispatch_level, и Микроядро обслуживает Очередь DPC. Делая так (и по-прежнему выполняясь на Процессоре 1), микроядро удаляет Объект DPC драйвера, и вызывает подпрограмму DPC драйвера. Подпрограмма DPC драйвера теперь выполняется на Процессоре 1. Предполагая, что подпрограмма DPC драйвера еще не завершила выполнение на Процессоре 0, заметим, что та же самая подпрограмма DPC теперь выполняется параллельно на обоих процессорах.
Этот пример подчеркивает важность использования в драйверах надлежащего набора механизмов многопроцессорной синхронизации. В особенности, в функции DPC должны использоваться спин-блокировки для сериализации доступа к любым структурам данных, к которым нужно обратиться как к единому целому, при условии, что конструкция драйвера такая, что одновременно может произойти несколько вызовов DPC.

Характеристики Объекта DPC

Объекты DPC имеют две характеристики, которые влияют на путь, которым они обрабатываются. Этими характеристиками являются поля Importance и Number.

Важность DPC (DPC Importance)

Каждый Объект DPC имеет важность, которая хранится в поле Importance Объекта DPC. Значения для этого поля перечислены в ntddk.h под именами Highlmportance, Mediumlmportance, и Lowlmportance. Это значение DPC Объекта влияет на место в Очереди DPC, куда помещается Объект DPC при постановке в очередь, а также то, будет ли иметь место прерывание уровня IRQL dispatch_level при постановке Объекта DPC в очередь. Функция KelnitializeDpc() инициализирует Объекты DPC с важностью Mediumlmportance. Значение важности объекта DPC может быть установлено, используя функцию KeSetlmportanceDpc(), прототип которой:

VOID KeSetlmportanceDpc (IN PKDPC Dpc,
В KDPCIMPORTANCE Importance);

Где:
Dpc - Указатель на объект DPC, в котором должно быть установлено поле Importance;
Importance - значение важности для установки в Объекте DPC.
Объекты DPC с Mediumlmportance или Lowlmportance помещаются в конец Очереди DPC. Объекты DPC с Highlmportance ставятся в начало Очереди DPC.
Важность Объектов DPC также влияет на то, будет ли при помещении Объекта DPC в очередь сгенерировано программное прерывание уровня dispatch_level. Когда Объект DPC с Highlmportance или Mediumlmportance ставится в очередь текущего процессора, всегда генерируется прерывание dispatchjevel. Прерывание dispatch_level генерируется для Lowlmportance DPC или для тех DPC, которые предназначены для отличного от текущего процессора, согласно сложному (и недокументированному) алгоритму планирования.
В таблице 11 перечислены ситуации, инициирующие освобождение очереди объектов DPC.
Большинству драйверов устройства никогда не понадобится устанавливать важность своих Объектов DPC. В редких случаях, когда задержка между запросом DPC и выполнением DPC чрезмерна, и разработчик драйвера не в состоянии решить устранить эту задержку другим способом, Вы можете попытаться установить DPC Объекта в Highlmportance. Однако обычно драйверы устройств в Windows NT не изменяют свое значение DPC со значения по умолчанию Mediumlmportance.

Таблица 11. Ситуации, инициирующие очистку очереди DPC

Приоритет DPC

DPC выполняются на том же процессоре, что и ISR

DPC выполняются на другом процессоре

Низкий

Размер очереди DPC превышает максимум, частота появления запросов DPC меньше минимальной, или система простаивает

Размер очереди DPC превышает максимум или система простаивает (выполняется поток idle)

DPC может быть ограничено выполнением на указанном процессоре, используя функцию KeSetTargetProcessorDpc(), прототип которой:

VOID KeSetTargetProcessorDpc(IN PKDPC Dpc,
IN CCHAR Number);

Где:
Dpc - Указывает на объект DPC, для которого должен быть установлен целевой процессор;
Number - отсчитываемый от нуля номер процессора, на котором должен быть выполнен DPC.
Подобно важности DPC, целевой процессор DPC почти никогда не устанавливается драйвером устройства. Заданное по умолчанию значение, которое служит для выполнения DPC на текущем процессоре, почти всегда желательно.
Когда для Объекта DPC установлен конкретный целевой процессор, такой Объект DPC будет всегда ставиться в Очередь DPC указанного процессора. Таким образом, например, даже когда KelnsertQueueDpc() вызывается на процессоре 0, Объект DPC с установленным в качестве целевого процессора Процессором 1 будет вставлен в Очередь DPC Процессора 1.

Как уже было сказано ранее в этой главе, наиболее часто DPC используются для завершения Программы Обработки Прерывания (ISR). Для того, чтобы упростить драйверам устройств запросы DPC для завершения ISR из их функций ISR, Диспетчер ввода/вывода определяет специальный DPC, который может использоваться для этой цели. Этот DPC называется DpcForlsr.
Диспетчер ввода/вывода вставляет Объект DPC в каждый Объект Устройство, который он создает. Этот внедренный Объект DPC инициализируется драйвером устройства, обычно при первой загрузке драйвера, посредством вызова функции IoInitializeDpcRequest().
IoInitializeDpcRequest() принимает на входе указатель на Объект Устройство, в который внедрен Объект DPC, указатель на функцию драйвера для вызова, и значение контекста для передачи этой функции. IoInitializeDpcRequest(), в свою очередь, вызывает KelnitializeDpc(), чтобы инициализировать внедренный Объект DPC, передавая указатель на функцию драйвера как параметр DeferredRoutine , и значение контекста как параметр DeferredContext.
Чтобы запросить DPC из ISR, драйвер просто вызывает loRequestDpc(), передавая указатель на Объект Устройство. IoRequestDpc(), в свою очередь, вызывает KelnsertQueueDpc() для Объекта DPC, внедренного в Объект-Устройство.
Поскольку все драйверы устройства имеют Объекты-Устройства, и все драйверы, которые используют прерывания, также используют DPC, использование механизма DpcForlsr Диспетчера ввода/вывода очень удобно. Фактически, большинство драйверов устройств в Windows NT никогда напрямую не вызывают функции KelnitializeDpc() или KelnsertQueueDpc(), а вместо этого вызывают loInitializeDpcRequest() и IoRequestDpc().

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

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

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

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

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

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

Системные вызовы

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

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

Реализация системных вызовов должна удовлетворять следующим требованиям:

· обеспечивать переключение в привилегированный режим;

· обладать высокой скоростью вызова процедур ОС;

· обеспечивать единообразное обращение к системным вызовам для всех аппаратных платформ, на которых работают ОС;

· допускать легкое расширение набора системных вызовов;

· обеспечивать контроль со стороны ОС за корректным использованием системных вызовов

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

При любом системном вызове приложение выполняет программное прерывание с определенным и единственным номером вектора.

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

Адрес процедуры 21h
Адрес процедуры 22h
Адрес процедуры 23h
Адрес диспетчера системных вызовов
Диспетчер системных вызовов
Процедура обработки Системного вызова 21h
Процедура обработки Системного вызова 22h
Процедура обработки Системного вызова 23h

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

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

ОС может выполнять системные вызовы в синхронном или асинхронном режимах.

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

Асинхронный системный вызов не приводит к переводу процесса в режим ожидания после выполнения некоторых начальных системных действий, например запуска операции вывода-вывода, управление возвращается прикладному процессу.

Большинство системных вызовов в ОС являются синхронными.

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

  • запуск диспетчеризации потоков;
  • обработка не критичных по времени прерываний;
  • обработка истечения времени таймера;
  • асинхронное выполнение процедуры в контексте конкретного потока;
  • поддержка асинхронных операций ввода-вывода.

Эти задачи рассматриваются в следующих разделах.

Диспетчеризируемые прерывания или прерывания отложенного вызова процедуры (DeferredProcedureCall, DPC). Когда выполнение потока больше не может продолжаться, возможно, из-за того, что он был завершен или из-за того, что он добровольно вошел в состояние ожидания, ядро напрямую вызывает диспетчер для немедленного переключения контекста.

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

Ядро всегда поднимает IRQL процессора до уровня DPC/dispatch или выше, когда ему нужно синхронизировать доступ к общим структурам ядра. Тем самым блокируются дополнительные программные прерывания и диспетчеризация потоков. Когда ядро обнаруживает необходимость диспетчеризации, оно запрашивает прерывание уровня DPC/dispatch, но процессор задерживает прерывание, поскольку IRQL находится на этом или на более высоком уровне.

Когда ядро завершает свою текущую работу, процессор видит, что оно собирается поставить IRQL ниже уровня DPC/dispatch, и проверяет наличие каких-либо отложенных прерываний диспетчеризации. Если такие прерывания имеются, IRQL понижается до уровня DPC/dispatch, и происходит обработка прерываний диспетчеризации. Активизация диспетчера потоков с помощью программного прерывания является способом, позволяющим отложить диспетчеризацию, пока для нее не сложатся нужные обстоятельства. Но Windows использует программные прерывания для того, чтобы отложить и другие типы обработки.

Кроме диспетчеризации потоков ядро обрабатывает на этом уровне IRQL и отложенные вызовы процедур (DPC). DPC является функцией, выполняющей ту системную задачу, которая менее критична по времени, чем текущая задача.

Функции называются отложенными (deferred), потому что они не требуют немедленного выполнения.

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

Ядро использует DPC-вызовы для обслуживания истечений времени таймера (и освобождения потоков, которые ожидают истечения времени таймеров) и для перепланирования времени использования процессора после истечения времени, выделенного потоку (кванта потока). Драйверы устройств используют DPC-вызовы для обработки прерываний. Для обеспечения своевременного обслуживания программных прерываний Windows совместно с драйверами устройств старается сохранять IRQL ниже IRQL-уровней устройств. Одним из способов достижения этой цели является выполнение ISR-процедурами драйверов устройств минимально необходимой работы для оповещения своих устройств, сохранения временного состояния прерывания и задержки передачи данных или обработки других, менее критичных по времени прерываний для выполнения в DPC-вызовах на IRQL-уровне DPC/dispatch.

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

Они называются DPC-очередями. Для запроса DPC системный код вызывает ядро для инициализации DPC-объекта, а затем помещает этот объект в DPC-очередь.

По умолчанию ядро помещает DPC-объекты в конец DPC-очереди того процессора, при работе которого была запрошена DPC-процедура (обычно того процессора, на котором выполняется ISR-процедура). Но драйвер устройства может отменить такое поведение, указав DPC-приоритет (низкий, средний, выше среднего или высокий, где по умолчанию используется средний приоритет) и нацелив DPC на конкретный процессор. DPC-вызов, нацеленный на конкретный центральный процессор, известен как целевой DPC. Если DPC имеет высокий приоритет, ядро ставит DPC-объект в начало очереди, в противном случае для всех остальных приоритетов оно ставит объект в конец очереди.

Ядро обрабатывает DPC-вызовы, когда IRQL-уровень процессора готов понизиться с IRQL-уровня DPC/dispatch или более высокого уровня до более низкого IRQL-уровня (APCили passive). Windows обеспечивает пребывание IRQL на уровне DPC/dispatch и извлекает DPC-объекты из очереди текущего процессора до тех пор, пока она не будет исчерпана (то есть ядро «расходует» очередь), вызывая по очереди каждую DPC-функцию. Ядро даст возможность IRQL-уровню упасть ниже уровня DPC/dispatch и позволить продолжить обычное выполнение потока только когда очередь истощится. Обработка DPC изображена на рисунке DPC-приоритеты могут повлиять на поведение системы и другим образом.

Обычно ядро инициирует расход DPC-очереди прерыванием DPC/dispatch-уровня. Ядро генерирует такое прерывание только в том случае, когда DPC-вызов направлен на текущий процессор (тот, на котором выполняется ISR-процедура) и DPC имеет приоритет выше низкого (low). Если DPC имеет низкий приоритет, ядро запрашивает прерывание только в том случае, когда количество невыполненных запросов DPC процессора превышает пороговое значение или если количество DPC-вызовов, выполнение которых запрашивается на процессоре в данном окне времени, невелико.

Доставка DPC-вызова

Если DPC-вызов нацелен на центральный процессор, отличающийся от того, на котором запущена ISR-процедура, и приоритет DPC высокий (high) или выше среднего (medium-high), ядро немедленно сигнализирует целевому центральному процессору (посылая ему диспетчерское IPI) о необходимости расхода его DPC-очереди, но только если целевой процессор находится в режиме ожидания. Если приоритет средний или низкий, то для выдачи ядром прерывания DPC/dispatch количество DPC-вызовов, находящихся в очереди на целевом процессоре, должно превысить определенный порог. Системный поток простоя (idle) также опустошает DPC-очередь того процессора, на котором он запущен. Несмотря на ту гибкость, которую придают системе целевые назначения DPC-вызовов и уровни приоритета, драйверам устройств редко требуется изменять поведение по умолчанию своих DPC-объектов. Ситуации, инициирующие опустошение DPC-очереди, сведены в таблице. Если посмотреть на правила генерации, то, фактически, получается, что приоритеты выше среднего и высокий равны друг другу. Разница проявляется при их вставке в список, когда прерывания высокого уровня находятся впереди, а прерывания уровня выше среднего сзади.

Поскольку потоки пользовательского режима выполняются при низком IRQL, высоки шансы на то, что DPC-вызов прервет выполнение обычного пользовательского потока. DPC-процедуры выполняются независимо от того, какой поток запущен, стало быть, когда запускается DPC-процедура, она не может выстроить предположение насчет того, чье адресное пространство, какого именно процесса в данный момент отображается. DPC-процедуры могут вызывать функции ядра, но они не могут вызывать системные службы, генерировать ошибки отсутствия страницы или же создавать или ожидать объекты диспетчеризации. Тем не менее они могут обращаться к невыгружаемым адресам системной памяти, поскольку системное адресное пространство отображено всегда, независимо от того, что из себя представляет текущий процесс.

Правила генерации DPC-прерывания.

Приоритет DPC DPC-вызов нацеливается на процессор, выполняющий
ISR -процедуру
DPC-вызов нацеливается
на другой процессор
Низкий (Low) Длина DPC-очереди превышает максимальную длину DPC-очереди или уровень DPC-запросов ниже минимального
уровня DPC-запросов
Средний
(Medium)
Всегда Длина DPC-очереди превышает максимальную длину DPC-очереди или система находится в простое
Выше среднего
(Medium-High)
Всегда
Высокий (High) Всегда Целевой процессор простаивает

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

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

Обработчик прерывания от часов ставит DPC-вызов в очередь, чтобы инициировать диспетчеризацию потоков, а затем завершить свою работу и понизить IRQL-уровень процессора. Поскольку у DPC-прерывания приоритет ниже, чем у прерываний от устройств, любые отложенные прерывания от устройств, появляющиеся до завершения прерывания от часов, обрабатываются до выдачи DPC-прерывания.

Так как DPC-вызовы выполняются независимо от того, какой из потоков выполняется в данное время на системе (что во многом похоже на прерывания), они являются основной причиной того, что система, на которой они выполняются, становится невосприимчивой к рабочей нагрузке клиентских систем или рабочей станции, потому что даже потоки с самым высоким уровнем приоритета будут прерваны ожидающим DPC-вызовом.

Некоторые DPC-вызовы выполняются настолько долго, что пользователи могут заметить отставание видео или звука или даже ощутить ненормальное замедление реакции мыши или клавиатуры, поэтому для драйверов с продолжительными DPC-вызовами Windows поддерживает потоковые DPC-вызовы.

Потоковые DPC-вызовы, как следует из их названия, предназначены для выполнения DPC-процедуры на пассивном (passive) уровне в потоке с приоритетом реального времени (priority 31). Это позволяет DPC-вызову воспользоваться приоритетом над большинством потоков пользовательского режима (поскольку большинство потоков приложений не запускается в диапазонах приоритетов реального времени). Но это позволяет другим прерываниям, непотоковым DPC-вызовам, APC-вызовам и потокам с более высоким приоритетом реализовать свой приоритет перед данной процедурой.

Процессор перегружен? Виноваты системные прерывания.

Виной тому, что процессор перегружен практически в течение всего сеанса, могут быть так называемые системные прерывания, а это, в свою очередь, означает, что проблема кроется в области установленного на компьютере оборудования или драйверах для этих устройств. Но предупреждаю сразу: даже объёма всей этой статьи не хватит, чтобы вычленить все причины (и тем более варианты их решений) почему системные прерывания просто убивают Windows. Ибо подход к поиску проблем усложняется использованием куда более сложного инструмента, чем тот, что описывается здесь.

Что такое системные прерывания и как попробовать справиться с перегрузкой процессора?

Системные прерывания появляются в Диспетчере задач в качестве системного процесса, однако по сути они таковым не являются. Эта « » носит лишь репрезентативный характер, отображая загруженность процессора при работе с прерываниями на низком уровне. Она – неотъемлемая часть Windows, убить процесс нельзя. Несмотря на зловещее название, системные прерывания – обязательная и нормальная часть процесса взаимодействия ЦПУ и остального оборудования.

Причиной прерываний (точнее, слишком медленной время от времени работы) могут служить девайсы внутри вашего компьютера, установленные программы, а иногда и сам процессор. Ведь системные прерывания – есть некая форма взаимодействия между программой/«железом» и самим процессором. Всякий раз, когда новому процессу нужно появиться в системе, процессор бросает все дела и выполняет задачу. Неважно, нажал ли пользователь мышку или процесс запущен по расписанию, задача сразу добавляется в очередь на исполнение. По её выполнению процессор возвращается к предыдущему состоянию.

Как понимаете, системные прерывания вполне могут сигнализировать системе и пользователю, что в данный момент некоторые вычисления идут с ошибкой, что и выражается в серьёзных потреблениях ресурсов процессора этим «процессом». В здоровой системе системные прерывания «потребляют» НЕ БОЛЕЕ 2% от общего объёма работы процессора. Хотя мне встречались и процессоры с показателем прерывания от 3 до 10 %% – всё зависит от конфигурации. Но если вы заметили, что процессор тратит на прерывания хотя бы 5 – 10 %% от своей вычислительной мощности от сеанса к сеансу, это сигнал того, что у компьютера проблемы.

Системные прерывания. Как бороться с высокими показаниями?

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

  • ДРАЙВЕРЫ И ЕЩЁ РАЗ ДРАЙВЕРЫ

Самое первое средство, которое поможет определить, виноваты ли битые драйверы в том, что системные прерывания нагружают процессор, это немецкая утилита DPC Latency Checker . Скачайте её по этой ссылке:

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

А вот они начинают себя проявлять:

Утилита в поле комментария на английском языке советует вам перейти в Диспетчер устройств и приступить к поэтапному отключению сетевых устройств, звуковых карт, USB контроллеров, устройств bluetooth . Советую прислушаться. После каждого отключения всматривайтесь в Диспетчер задач и окно утилиты, посмотрите, как система реагирует на временное отключение оборудования. Продолжите отключением всех внешних устройств: модемы, внешние диски, флешки. И если в какой-то момент наметятся изменения к лучшему, примите решение об обновлении драйвера к устройству. Но чтобы не было проблем с запуском Windows, вот эти устройства лучше не отключать (эти драйверы жизненно необходимы, но это тоже драйверы, и вполне возможно придётся переустановить дрова на материнскую всем пакетом как при установке Windows начисто):

На такой же манер действует и программа LatencyMon

http://www.resplendence.com/downloads

Она потребует установки, зато также бесплатна. Её задача – поиск файлов драйверов с высоким показателем вычислений, потраченных на отложенный вызов процедуры (процесса, который вызывается процедурой обработки прерывания в ответ на само прерывание, но необязательно сразу же исполняется). За этим мудрёным названием скрывается процесс поиска драйверов, в файлах которых хранится информация о том, что драйвер слишком много требует от процессора для обслуживания своего, приписанного конкретно ему устройства. Вот страница издателей:

http://www.resplendence.com/latencymon

на которой, впрочем, я своими слепыми глазами ссылки для скачивания не нашёл, а потому представлю вам возможность скачать программу с моего сайта

СКАЧАТЬ БЕСПЛАТНО ПРОГРАММУ

Запустившись, та сразу сообщила мне о возможных проблемах с DVD приводом – драйвер atapi.sys отвечает именно за него (а кстати, привод не работает уже почти 3 месяца…) . Предупреждает, что возможно потребуется перепрошить BIOS:

Переходим во вкладку Drivers и отсортируем их по наиболее уязвимым показаниям, нажав на колонку DPC count :

К первым в строчке присмотритесь: они и могут быть причиной ваших проблем.

  • ВСЁ ПРОИЗОШЛО КАК-ТО ВДРУГ, ПОСЛЕ ПЕРЕЗАГРУЗКИ

Был один момент, когда ну никак не удавалось вычленить причину тормозов. Помог случай: пользователь “хапнул” вирус, который совершенно уничтожил DirectX, причём действовал крайне избирательно, убивая именно системные файлы Windows, оставляя DirectX игровые . Пришлось ремонтировать систему обновлением, и – о чудо! – вместе с дрянью пропали и системные прерывания. Я не пожалел немного времени, но результат оказался неожиданный. Виновниками оказались не вирусы и не драйверы, а пакеты обновлений. Вот их имена:

  • KB3199986
  • KB4013418
  • KB3211320

Я настаиваю, что именно ПОСЛЕ УСТАНОВКИ ИМЕННО ЭТИХ ОБНОВЛЕНИЙ конкретный пользователь начинал мучиться от перегрузки системными прерываниями. Как-то так… вам информация к размышлению.

  • ИСКЛЮЧАЕМ НЕИСПРАВНОЕ ОБОРУДОВАНИЕ

Тоже может послужить причиной того, что системные прерывания нагружают процессор донельзя. Приступайте к проверке, если предыдущий поиск битых драйверов успеха не принёс. А поможет вам в поиске проблем с “железом” сама Windows и встроенные утилиты самодиагностики. О них я писал уже в статье . Пробегите глазами, информация окажется полезной, не сомневайтесь. Знайте – отошедшие от разъёма шлейфа также могут быть виновниками злоключений. Я лично сталкивался с проблемами и перегрева процессора, и “забывчивости” про-апгрейдить BIOS для новенькой Windows 10 (об этом ниже) – везде итогом были заметные системные прерывания.

ПРИМЕЧАНИЕ . Если системные прерывания одолели ваш ноутбук, вам придётся убедиться, что у вас нет проблем с умирающим аккумулятором. Прочтите статью, собственными силами.

  • ПРОВЕРЬТЕ ЗВУКОВУЮ СХЕМУ WINDOWS

Собственно, речь идёт о том, чтобы сбросить звуковые эффекты в Windows до установленных по умолчанию. Щёлкните по иконке звука правой мышкой и нажмите на Устройства воспроизведения :

Во вкладке Воспроизведение щёлкните два раза по пункту дефолтных устройств (у меня Динамики ), пройдите во вкладку Дополнительные возможности и установите галочку напротив Отключить все эффекты . Применить – ОК. Перезагружаемся и проверяем:

  • ВИНОВАТА BIOS ?

Не исключено. BIOS – первая программа, которая запускается после нажатия на кнопку включения компьютера. Так что время проверить обновления для вашей BIOS. А чтобы поиски нужной версии не затягивались во времени, проверьте версию вашей BIOS прямо сейчас. В консоли команд cmd наберите последовательно две команды:

Systeminfo | findstr /I /c:bios wmic bios get manufacturer, smbiosbiosversion

I в первой команде – это большая латинская i .

Причина в жёстком диске?

“Вполне себе и даже очень”. Самый простой способ – проверьте диск на ошибки с помощью встроенных средств типа chkdsk . Если после “прогона” системные прерывания поутихли, причина обнаружена. Однако в случае, когда проблема появляется вновь и вновь, при всём том chkdsk неизменно обнаруживает ошибки, у вас проблемы (с жёстким, БП или материнской платой) – готовьтесь к худшему.

P.S. Ну, судя по отзывам проблема народ теребит. Обещаю тему развить в следующих статьях.

Успехов вам.

Прочитано: 1 238



В продолжение темы:
Windows

Часть вторая : "Важнейшие характеристики каждого семейства процессоров Intel Core i3/i5/i7. Какие из этих чипов представляют особый интерес" Введение Сначала мы приведём...

Новые статьи
/
Популярные