WaitForSingleObject(hDevice)

Тема в разделе "WASM.NT.KERNEL", создана пользователем Nouzui, 10 фев 2007.

  1. Nouzui

    Nouzui New Member

    Публикаций:
    0
    Регистрация:
    17 ноя 2006
    Сообщения:
    856
    Некоторые девайсы позволяют дожидаться своей готовности таким способом

    Код (Text):
    1. hDevice= CreateFile("\\\\?\\...
    2. WaitForSingleObject(hDevice, INFINITE);
    Когда у драйвера появляются данные, которые можно прочитать, WaitForSingleObject возвращается
    вопрос: как сделать такое самому?
     
  2. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    DDK\src\general\cancel

    Основные моменты:

    Открыть девайс с флагом FILE_FLAG_OVERLAPPED. Кинуть в него несколько запросов через ReadFile или DeviceIoControl.

    Драйвер возвращает STATUS_PENDING, не завершая IRP, а IRP пихает в очередь. В ДДК описано несколько способов организации такой очереди. В примере используется Cancel Safe Queue.

    ReadFile/DeviceIoControl возвратят FALSE, а GetLastError даст ERROR_IO_PENDING, т.е. можно ждать.

    В примере вместо WaitForSingleObject используется ReadFileEx, но это по сути одно и тоже. Разумеется и WaitForSingleObject можно прикрутить.

    Когда настанет момент такой, драйвер достает IRP из очереди и завершает его. На юзерной стороне ожидание успешно завершается.

    Тут главный гемор - это необходимость отмены IRP, поставленных в очередь. Без возможности отмены никак нельзя, ибо юзер может, например, умереть в любой момент и нужно как-то доставать все его IRP из ядра. Если никогда с отменой не разбирался, то используй Cancel Safe Queue, как в примере. Она сама внутри себя с этим справляется. Все другие очереди требуют явно это делать.
     
  3. Nouzui

    Nouzui New Member

    Публикаций:
    0
    Регистрация:
    17 ноя 2006
    Сообщения:
    856
    А я, кстати, так и пытался
    только вместо очереди запоминал адрес IRP в глобальной переменной )) а завершал пакет в DispatchRoutine, по запросу DeviceIoControl.
    Так вот, все работает замечательно, если дожидаться на event'е, переданном в структуре OVERLAPED. Что же касается ожидания самого устройства, то WaitForSingleObject выходит же сразу, если ReadFile еще не вызывался, и вообще не выходит после того, как чтение было запущено. Она продолжает висеть даже после того, как IRP завершается. Похоже, для перевода устройства в сигнальное состояние (если это понятие тут вообще применимо) используются какие-то другие механизмы.
    Что касается отмены... до завершения IRP юзера убить просто невозможно. Если попытаться замочить его, он останется висеть, и закроется сразу же, как только IRP будет завершен. Canceling нужен именно для того, чтобы не блокировать процесс?
     
  4. Nouzui

    Nouzui New Member

    Публикаций:
    0
    Регистрация:
    17 ноя 2006
    Сообщения:
    856
    Да.. маленькое дополнение
    Ожидание устройства действительно, судя по всему, связанно с наличием незавершенных IRP, только простое их завершение почему-то не помогает. В чем же может быть дело?
     
  5. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Ну для экспериментов можно и так.

    Девайс не является объектом ожидания: http://msdn2.microsoft.com/en-us/library/ms686364(d=printer).aspx

    Да, т.к. поставленный в очередь IRP может находиться там сколь угодно долго. Если не будет отмены, то будут плодиться процессы-зомби. Ну и просто нужно иметь механизм отмены для отзыва IRP.
     
  6. Nouzui

    Nouzui New Member

    Публикаций:
    0
    Регистрация:
    17 ноя 2006
    Сообщения:
    856
    да я то в курсе, вот только одна загвоздочка:
    Код (Text):
    1.     RtlInitUnicodeString(ObjectAttributes.ObjectName, L"\\Device\\KeyboardClass0");
    2.     ntStatus= NtOpenFile(&hKeyboard, GENERIC_READ, &ObjectAttributes, &IoStatusBlock...
    3. ..
    4.     for(;;)
    5.     {
    6.         ntStatus= NtReadFile(hKeyboard, NULL, NULL, NULL, &IoStatusBlock, &stInputData, sizeof(stInputData), &r, NULL);
    7.         if(ntStatus!=0 && ntStatus!=STATUS_PENDING)
    8.         {
    9.             ...
    10.         }
    11.  
    12.         if(ntStatus==STATUS_PENDING)
    13.         {
    14.             ntStatus= NtWaitForSingleObject(hKeyboard, FALSE, NULL);
    15.             if(ntStatus!=0)
    16.             {
    17.                 ...
    18.             }
    19.         }
    20.  
    21.         printf("UnitId=%04X, MakeCode=%04X, Flags=%04X, Res=%04X, Extra=%08X\n", stInputData.UnitId, stInputData.MakeCode, stInputData.Flags, stInputData.Reserved, stInputData.ExtraInformation);
    22.     }
    и вот представь, NtWaitForSingleObject дожидается готовности безо всяких так event'ов и APC! Причем, если поменять их местами, wait выйдет сразу же. Если в конце цикла вставить еще один wait, он тоже сразу завершится. Ожидание выполняется только пока в драйере обрабатывается направленный на этот девайс пакет..
    Ну так вот, самому этого сделать не удается. Есть предположение, что kbdclass все таки добавляет в конце kernel apc, которая вроде сработает независимо от параметра alertable и тоже прервет ожидание (если честно, я слабо в этом разбираюсь)
    Конечно, особой разницы - дожидаться на событии или на устройстве, теперь все равно нет, поскольку в любом случае требуется, чтобы в устройстве был irp. А я было подумал, что можно дождаться на устройстве, и только после этого пытаться его читать, что убавило бы проблем с отменой запросов ))
    Но все равно интересно, к тому же, так можно будет не создавать лишних объектов вроде собыий для ожидания операции.
     
  7. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    То, что оно как-то работает в данном конкретном случае, ничего не означает.


    Нет. Просто достает IRP из очереди, копирует KEYBOARD_INPUT_DATA и IoCompleteRequest.

    И кстати, csrss открывает этот девайс и постоянно читает клавиатурный ввод. Так что ты ему мешаешь.
     
  8. Nouzui

    Nouzui New Member

    Публикаций:
    0
    Регистрация:
    17 ноя 2006
    Сообщения:
    856
    да, но ведь работает как-то..


    Странно, что он вообще дает мне его открыть
    а вот KeyboardClass2, например, не открывается
    Вообще предполагалось все это использовать на стади загрузки(HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\BootExecute)
    Кстати, интересный момент, Sleep проходит через kbdclass, но обрабатыватся где-то ниже. Даже если поставить на него фильтр и залочить всю клавиатуру, реакция на Sleep все равно сохраняется
     
  9. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Конкретно насчет sleep не знаю, но kbdclass - это upper-level class filter. Клавой же рулит драйвер i8042prt. Полные исходники тоже есть в ддк DDK\src\input\pnpi8042.
     
  10. Nouzui

    Nouzui New Member

    Публикаций:
    0
    Регистрация:
    17 ноя 2006
    Сообщения:
    856
    угу.. похоже, что в нем
    даже не отфильтруешь, если только isr перехватывать
     
  11. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    DDK/src/input/kbfiltr/ должен мочь это фильтровать, но сам не пробовал.
     
  12. Nouzui

    Nouzui New Member

    Публикаций:
    0
    Регистрация:
    17 ноя 2006
    Сообщения:
    856
    вот как?
    а ддк, оказывается, рулит )