Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Как бороться с пропаданием DPC?  (Прочитано 15707 раз)
0 Пользователей и 1 Гость смотрят эту тему.
ra_
Гость
« : 11-03-2009 08:21 » 

Здравствуйте.

Столкнулся с проблемой, и пока не понял, как решить.

Железка устроена таким образом, что по передаче и по приёму дёргается одно и то же прерывание.

В ISR распознаю, чтение это или запись, после чего планирую DPC:
Код:
IoRequestDpc(FdoData->Self, (PIRP) DPC_READ, FdoData);
, где DPC_READ - это константа.
и сразу после этого - FdoData->RxISRcount++;

Внутри DPC:
Код:
fdoData->DPCcount++;
switch (Mode) {
case DPC_READ:
fdoData->RxDPCcount++;
...

для чтения, и аналогично - для записи.
Таким образом, у меня есть одна ISR, одна DPC, и две разных причины ISR (чтение или запись). Пока события происходят медленно - всё хорошо.
Но при быстром приёме-передаче, как я понял, попадается случай, когда второе прерывание (и вторая ISR) возникает ДО первого вызова DPC. А ведь если планируем DPC, когда она уже есть в очереди - это пустое действие! И, таким образом, на ДВА ISR планируется только ОДИН DPC. Ну, а второе событие, выходит, теряется.
В рассмотренном примере потеря события - это установившееся неравенство RxDPCcount и RxISRcount. Разница на единичку. Для моего применения - фатально, ибо приём от этого останавливается навсегда.

И теперь - вопросы. Насколько я понимаю, в винде одной ISR соответствует одна DPC. Это так?
Если да - то можно ли назначить на одно прерывание две ISR, каждая из которых планирует свою DPC? Тогда что совать в параметры IoInitializeDpcRequest при старте устройства?

Или есть какие-то более стандартные подходы?
Заранее спасибо.
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 11-03-2009 10:07 » 

вообще говоря... не пробовал, но подозреваю что никто не мешает и две DPC очереди сделать.
Цитата
DpcForIsr
To register a DpcForIsr routine for a specific device object, a driver must call IoInitializeDpcRequest, which causes the system to allocate and initialize one DPC object. (If you need multiple DPC routines, use CustomDpc routines.)
так как "Unlike a DpcForIsr routine, a CustomDpc routine is not associated with a device object"
а так же раздел "Which Type of DPC Should You Use?"

а вобще по логике ваших взаимодейсвтий...
вопервых, подумайте, может имеет смысл использовать очереди/списки для диспечеризации ваших прерываний?
посмотрите DDK на структуру SINGLE_LIST_ENTRY в примечании есть отсылка на "Singly- and Doubly-Linked Lists."
при возникновении прерывания обновляется список, и просто ставится DPC.
при выполнении DPC - выполняются действия по списку и подчищаются выполненные элементы.

а так - да... можно наверное и две очереди DPC.
но опять же - остается шанс что при ДЕЙСТВИТЕЛЬНО быстрой передаче, позникнет две пары ISR на 2чтения и 2 записи. прежде, чем выполнится DPC?

если такое гарантированно не произойдет... можно просто обойтись внешней структуркой с двумя флагами:
в ISR R/W флаги взводить путем ExInterlockedXXX. в DPC - сбрасывать так же. а DPC использовать одно.
единственное что не помню... надо посмотреть, - когда DPC извлекается из очреди? в перед выполнением DPC или после вызова DPC? если после - то последний метод подойдет.

насчет "Тогда что совать в параметры IoInitializeDpcRequest при старте устройства?" - а раньше вы что туда совали?))))

PS а зачем вы вообще DPC используете?)
« Последнее редактирование: 11-03-2009 10:12 от Ochkarik » Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
ra_
Гость
« Ответ #2 : 12-03-2009 07:40 » 

вообще говоря... не пробовал, но подозреваю что никто не мешает и две DPC очереди сделать.
Таки вычитал в У.Они. Можно сделать дополнительный DPC, кроме "бесплатного", даваемого сразу. Для создания надо сделать KeInitializeDpc, а для её планирования изнутри ISR - вызвать KeInsertQueueDpc.
Если я правильно понимаю, очередь DPC - она всё равно одна. Просто станет два "типа" DPC, которые можно добавлять в очередь, а доселе был один "тип".

но опять же - остается шанс что при ДЕЙСТВИТЕЛЬНО быстрой передаче, позникнет две пары ISR на 2чтения и 2 записи. прежде, чем выполнится DPC?
Нет. Именно в DPC я разрешаю снова колбасить прерывания: активизирую приёмник или передатчик железки. Таким образом, пока не закончится DPC, вызванное чтением, не дёрнется ISR чтения. И пока не закончится DPC, вызванное записью - не дёрнется ISR записи. Таким образом, до выполнения DPC может произойти строго или 1, или 2 ISR. Раньше предполагал, что только 1...

если такое гарантированно не произойдет... можно просто обойтись внешней структуркой с двумя флагами:
в ISR R/W флаги взводить путем ExInterlockedXXX. в DPC - сбрасывать так же. а DPC использовать одно.
Это на первый взгляд грозит нестабильностью. Надо подумать...
DPC исчезает из очереди прямо перед моментом её вызова. То есть, похоже, возможны случаи, когда проверка флага ничего не даст.

насчет "Тогда что совать в параметры IoInitializeDpcRequest при старте устройства?" - а раньше вы что туда совали?))))

PS а зачем вы вообще DPC используете?)
Что совать - это я выяснил уже, в начале поста "сам себе" написал Ага IoInitializeDpcRequest - применяет "бесплатный" DPC. Для заведения дополнительного - другие функции.

В общем, буду пробовать заводить два DPC и один ISR. Это кажется самым правильным подходом.
А зачем использую DPC - вроде уже пояснил. На нём я работаю с очередями IRP, копирую DMA в буфер пользователя, включаю приёмник и т.п, то есть делаю действия, которые нельзя или не следует делать на ISR.
Записан
sss
Специалист

ru
Offline Offline

« Ответ #3 : 12-03-2009 11:29 » 

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

while (8==8)
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 12-03-2009 12:27 » 

ra_,
какой еще БЕСПЛАТНЫЙ DPC? бесплатно только сыр и то сами знаете где)

а если DPC извлекается из очереди до того как начнется его выполнение - тогда два флага R/W(spinlock-флага разумеется) как раз сработают в ДАННЫХ условиях - отлично. фактически  в этом случае DPC становится как бы Event-ом для проверки флагов. а поскольку флаги защищены spinlock-ами, становится не важным - сколько было DPC  в очереди (один или два).

sss, фактически это очередь и получается из максимум двух элементов-флагов.
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
PredatorAlpha
Помогающий

us
Offline Offline

« Ответ #5 : 12-03-2009 13:04 » 

///Но при быстром приёме-передаче, как я понял, попадается случай, когда второе прерывание (и вторая ISR) возникает ДО первого вызова DPC. А ведь если планируем DPC, когда она уже есть в очереди - это пустое действие!

Возможно, проблема не в DPC. Возможно, когда Вы сбрасываете бит-индикатор чтения (например), вы заодно сбрасываете и бит-индикатор записи. Например:

#define READ_BIT_MASK   0x01
#define WRITE_BIT_MASK 0x02

if (StatusRegister & READ_BIT_MASK) {
// Читаем с устройства
.........................
.........................

StatusRegister &= ~READ_BIT_MASK; // <- Затык!!!!
}

По шине строка может разбиться на две операции - чтения и записи, а между ними в устройстве может поставиться бит записи, который операция записи подотрёт. Здесь могут не помочь системные функции блокировки, если устройство не поддерживает соответствующие операции на шине (я про PCI).

В примере регистр StatusRegister имеется ввиду внутри железки.
« Последнее редактирование: 12-03-2009 13:30 от PredatorAlpha » Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 12-03-2009 19:58 » 

PredatorAlpha, кстати и такое возможно. но мы из такой ситуации выкручивались иначе.
так как выставление бита идет в одну сторону от железки а сброс только из ПК - сброс производится маской. мы через порты IO делали но суть та же.
то есть, чтобы сбросить флаг - в его позицию записывается ЕДИНИЦА. так и только так)
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
sss
Специалист

ru
Offline Offline

« Ответ #7 : 13-03-2009 02:36 » 

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

 

* avatar1.gif (260.84 Кб - загружено 1509 раз.)
« Последнее редактирование: 13-03-2009 03:41 от sss » Записан

while (8==8)
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #8 : 13-03-2009 10:04 » 

sss, пора раздел чернухи создавать Отлично
Записан

Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #9 : 13-03-2009 12:02 » 

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

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
PredatorAlpha
Помогающий

us
Offline Offline

« Ответ #10 : 16-03-2009 14:25 » 

PredatorAlpha, кстати и такое возможно. но мы из такой ситуации выкручивались иначе.
так как выставление бита идет в одну сторону от железки а сброс только из ПК - сброс производится маской. мы через порты IO делали но суть та же.
то есть, чтобы сбросить флаг - в его позицию записывается ЕДИНИЦА. так и только так)
Знаю. В DSP от TI (Техасского инструментального завода) почти все регистры событий и прерываний так и реализованы. Причем как статус, так и разрешение/запрещение. Очень умно.
Записан
ra_
Гость
« Ответ #11 : 17-03-2009 03:35 » 

Спасибо всем большое за участие!  Класс! Проблему решил. Завёл второй DPC. Один ISR планирует тот или другой DPC в зависимости от того, чтение или запись вызвало прерывание. Считаю, что это самое лучшее решение в данной ситуации. Готов дискутировать.

ra_,
какой еще БЕСПЛАТНЫЙ DPC? бесплатно только сыр и то сами знаете где)
Улыбаюсь "Бесплатный DPC" - это цитата из У.Они, 2е изд., Питер, с.362. Имеется в виду объект DPC, встроенный в объект устройства.

а если DPC извлекается из очереди до того как начнется его выполнение - тогда два флага R/W(spinlock-флага разумеется) как раз сработают в ДАННЫХ условиях - отлично. фактически  в этом случае DPC становится как бы Event-ом для проверки флагов. а поскольку флаги защищены spinlock-ами, становится не важным - сколько было DPC  в очереди (один или два).
Если есть только один вид DPC - он будет только ОДИН в очереди, два одновременно их не будет в одной очереди. А принятые данные дальше я синхронизирую, да (через cancel-safe queues), но это уже отдельная и другая песня.

Несостыковочка адская - разрешаешь генерацию в DPC (приоткрываешь, как бы расчитывая только на одно прерывание) - а тебе вываливается куча прерываний...
Не про этот случай. Как я и описал: включив приёмник в DPC, получу не более одного прерывания от него: железка сама себе выключает приёмник (и.е. отключает возможность прерывания по Rx) после дёргания ISR.

Возможно, проблема не в DPC. Возможно, когда Вы сбрасываете бит-индикатор чтения (например), вы заодно сбрасываете и бит-индикатор записи.
Не, здесь всё было корректно: железка сделана правильно. Отдельный регистр для сброса битов, как бы Reset_Register; единица в позиции означает сброс нужного бита.
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #12 : 18-03-2009 23:15 » 

1. странно.. перечитаю... не слышал чтоб DPC встраивался в объект устройств... может чего не понимаю, посмотрю при случае...
2. я наверное не совсем корректно выразился. я имел в виду случай, когда первый DPC уже был извлечен из очереди и ТОЛЬКО НАЧАЛ выполнятся, но еще не дошел до проверки флагов, но в этот момент пришло второе ISR и второй DPC был поставлен в очередь и взведен второй флаг. в этом случае оба флага обработаются первым, уже начатым DPC. второй- выполнится в холостую.
3. -
4. ну да) ничего нет нового на земле) все уже давно выдумали)))
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
sss
Специалист

ru
Offline Offline

« Ответ #13 : 19-03-2009 05:07 » 

ra_, ну что тут скажешь - два DPC использующие две разных очереди это логично...
Записан

while (8==8)
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #14 : 08-04-2009 15:56 » 

1. - действительно... спасибо! не знал)
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Рыжий Тигра
Гость
« Ответ #15 : 27-04-2009 09:31 » 

ra_, а нельзя повременить с прерыванием, к примеру, по записи до конца обработки прерывания по чтению? Или хранить флаги готовности чтения и записи не в разных битах, а в разных словах шириной с шину? Или, на худой конец, попробуй вместо флагов кольцевой буфер (на 4 места вполне хватит Улыбаюсь ), а в него устройство пусть укладывает записи с флагами, а DPC их чтобы изымал.
Ещё вариант - подтверждать обработку прерывания от устройства прерыванием к нему от DPC, чтобы устройство снова выставляло прерывание, если какой-то из флагов DPC'ём не сброшен при выходе.
Мы с PredatorAlpha комбинируем последние два способа, за последний год с чем-то ни одного пропадания не было.
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines