Передача данных от драйвера к процессу пользователя

Тема в разделе "WASM.NT.KERNEL", создана пользователем ormoulu, 8 июн 2011.

  1. ormoulu

    ormoulu Well-Known Member

    Публикаций:
    0
    Регистрация:
    24 янв 2011
    Сообщения:
    1.208
    Есть драйвер, которому нужно периодически отправлять управляющей программе небольшие сообщения, к примеру, текстовые строки. Формирование сообщений происходит в контексте других процессов. Управляющая программа при этом не всегда имеет возможность немедленно отреагировать на уведомление драйвера, т.е., сообщения должны где-то накапливаться.
    Как лучше и безопаснее в плане отказоустойчивости реализовать такую передачу?
     
  2. steelfactor

    steelfactor New Member

    Публикаций:
    0
    Регистрация:
    26 апр 2007
    Сообщения:
    501
    Через APC отправлять (NtQueueApcThread)?
     
  3. ormoulu

    ormoulu Well-Known Member

    Публикаций:
    0
    Регистрация:
    24 янв 2011
    Сообщения:
    1.208
    А вот безвременно забаненный товарищ Инди писал в этом топике, что этот метод нестабилен, нет?
     
  4. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Ну про APC уже сказали. Чуть более подробно если, то это выглядит примерно так. Если нужна скорость и данных относительно много, то следует реализовать что-то вроде менеджера памяти (по сути, собственная реализация кучи, но можно использовать и системные функции типа RtlCreateHeap). Драйвер выделяет/освобождает большой (или не очень) кусок виртуальной памяти в процессе управляющего приложения, соответственно, он же решает и все проблемы с фрагментацией и пр. При наступлении события, информацию о котором необходимо передать в приложение, драйвер выделяет блок из этой кучи, блок логически делится на заголовок (длина блока, тип информации в блоке и т.п.) и непосредственно полезные данные блока (информация, которую должно получить приложение). Далее драйвер создаёт APC, в качестве параметров которого указывается NormalRoutine = некая функция в процессе приложения, и NormalContext = адрес выделенного блока, ну и хендл потока приложения, который ждёт этого APC.

    В приложении происходит следующее. При запуске оно создаёт поток, единственная задача которого это крутиться в цикле, пока не получена команда на выход, и постоянно звать SleepEx (..., TRUE) для того, чтобы спать в режиме тревожного ожидания (alertable). Также в приложении должна быть реализована функция, имеющая прототип Normal APC routine (см. ниже). При инициализации драйвера приложение должно передать ему, как минимум, следующую информацию: хендл ждущего потока и виртуальный адрес APC-функции, - эти данные драйвер будет использовать при инициализации структур KAPC специальными функциями вроде KeInitializeApc, KeInsertQueueApc и т.д.

    Код (Text):
    1. VOID
    2. NormalRoutine (
    3.     IN PVOID NormalContext OPTIONAL,
    4.     IN PVOID SystemArgument1 OPTIONAL,
    5.     IN PVOID SystemArgument2 OPTIONAL);
    Эта функция будет вызываться драйвером в контексте того самого потока, который постоянно спит в режиме тревожного ожидания. В качестве NormalContext в неё придёт виртуальный адрес блока памяти, в начале которого заголовок, потом данные. По окончании работы с этим блоком приложение должно сообщить об этом драйверу, например, посредством IOCTL-запроса. В ответ на такой запрос драйвер освободит указанный блок памяти для использования его в дальнейших передачах информации. Ну и напоследок скажем, что если данных не много или они шлются не часто, то не имеет смысла городить свою кучу, вместо этого каждый новый блок памяти можно выделять посредством ZwAllocateVirtualMemory. Если есть более конкретные вопросы по этому методу, - пишите, отвечу.
     
  5. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Моё мнение - стабильность данного метода зависит от прямоты рук.
    Ну можете попробовать доказать обратное, я с удовольствием послушаю.
     
  6. shchetinin

    shchetinin Member

    Публикаций:
    0
    Регистрация:
    27 май 2011
    Сообщения:
    715
    ormoulu
    Товариш руссинович обычно реализовывал shared memory . практически не ограниченная память, производительно, стабильно , и так далее ...
     
  7. ormoulu

    ormoulu Well-Known Member

    Публикаций:
    0
    Регистрация:
    24 янв 2011
    Сообщения:
    1.208
    shchetinin
    В последних его утилитах таки да, наверное, так и следует сделать.

    x64
    Чтобы что-то доказывать, нужно в этом убедиться, а я такой уверенности не имею.

    APC в этом варианте используется только для уведомления приложения, ведь так? Есть ли тогда у него преимущества перед эвентом?
     
  8. 100gold

    100gold New Member

    Публикаций:
    0
    Регистрация:
    26 фев 2010
    Сообщения:
    165
    А какой смысл пользоваться именно APC в этом случае?
    Можно допустим точно так же выделить в драйвере кусок памяти в процессе и организовать там кольцевой буфер событий с данными. В юзермоде приложение будет спать на ивенте, который драйвер будет сигналить когда появляются новые данные. *Кстати тут можно обойтись lock-free доступом к буферу* Если приложение долго не обрабатывает данные (конец буфера указывает на начало) драйвер либо дропает события, либо ждёт, либо ещё чтонить - всё зависит от конкретики.
     
  9. ormoulu

    ormoulu Well-Known Member

    Публикаций:
    0
    Регистрация:
    24 янв 2011
    Сообщения:
    1.208
    О, это ценная идея.
     
  10. klzlk

    klzlk New Member

    Публикаций:
    0
    Регистрация:
    2 июн 2011
    Сообщения:
    449
    x64
    Ого скока текста.. Хотя его смысла нет читать, так как галимый аверсикий изврат. Не удивительно что авер расписал этот вопрос. Надеюсь не будите оправдываться, если знаете как Т-фреймами манипулировать ?

    Забудьте про эту г0вноапи. Она занимает весь нтдлл. Там при совершенно левых условиях возникает фолт, да и нахера оно нужно, если есть фастколы непосредственно.
     
  11. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Мне нравится. Удобно.
    В самой винде оно тоже используется, например, в сокетной подсистеме.

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

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

    asd_asd New Member

    Публикаций:
    0
    Регистрация:
    25 апр 2011
    Сообщения:
    21
    x64, а чем плоха обычная shared memory и синхронизация?
     
  13. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Во-первых, удобно. Дело в том, что, как правило, требуется передавать приложению данные в виде последовательности пакетов. Особенно наглядно это можно увидеть при написании, например, сетевого фильтра. А механизм APC значительно ближе к понятию "очередь", чем shared memory. Это означает, что разработчику не нужно писать весь этот вспомогательный код, связанный с организацией и управлением очередью. Во-вторых, APC быстрее ибо прерывания, в то время, как события и мутексы - чисто программные сущности. Конкретных выкладок я вам не скажу, разумеется, не замерял, но можете проделать эти тесты самостоятельно, думаю, прирост производительности будет очевиден. Ну и, наконец, очереди на базе APC используются повсеместно в самой Windows. Например, в подсистеме сокетов, в случае создания не-IFS сокета, в игру вступает драйвер ws2ifsl.sys, который перенаправляет все I/O-запросы в приложение, создавшее сокет, и делает он это посредством APC. А если ещё вспомнить, что Microsoft придаёт огромное значение производительности сетевой подсистемы в целом, то, думаю, что их выбор на APC пал совсем не просто так. Такие дела.
     
  14. shchetinin

    shchetinin Member

    Публикаций:
    0
    Регистрация:
    27 май 2011
    Сообщения:
    715
    x64
    Все так, только вот заряжать APC в дравере имея линк из приложения это как то ... . Уж лучше пачку MJ_READ запросов, по производительность будет очень быстро, и дизайн будет хороший и не через Ж ( хотя это тоже APC).

    А вообще LPC, PIPE это если приложения без привилегий, то это остается единственный вариант ... (К стати и самый универсальный, и давольно таки быстрый ... )
     
  15. 100gold

    100gold New Member

    Публикаций:
    0
    Регистрация:
    26 фев 2010
    Сообщения:
    165
    Я думаю с производительностью тут вопрос не так однозначно решается. Если события будут возникать "равномерно во времени", то наверное будет быстрее APC, а если события возникают в какие-то определённые моменты "пачкой" так сказать - то ивент может быть быстрее из-за того что обработчик в юзермоде будет обрабатывать события по нескольку за одну свою итерацию.
     
  16. h0t

    h0t Member

    Публикаций:
    0
    Регистрация:
    3 апр 2011
    Сообщения:
    735
    Была такая же проблема решил кольцевым буфером, все очень прилично работало
     
  17. assorted

    assorted New Member

    Публикаций:
    0
    Регистрация:
    7 авг 2006
    Сообщения:
    227
    Тоже занимаюсь подобной задачей. APC и KeUserModeCallback. Вызов первого асинхонный а второго синхронный?