Доброе время суток! У меня возникла необходимость пересылать с драйвера в приложение информацию, как лучше всего это реализовать ? Слышал о именованных каналах( Named Pipes, хз почему, но пишут что плохой вариант) и еще inverted calls - но хз что такое. Передавать нужно только в одном направлении Kernel Mode -> User Mode. Заранее спасибо!
AntiB Помимо перечисленных вариантов, которые гуглятся, добавлю. если приложение и драйвер твои, то можно юзать SharedMemory. Драйвер пишет, а приложение читает, это самый простой и банальный вариант - не очень годится. Можно через IOCTL запросы - приложение отсылает запрос, драйвер выдает ответ например используя Buffered IO. Можно DMA использовать, вместо буферизированного ввода\вывода. Если же приложение не твое. А драйверу надо ему все равно, что-то послать - APC как вариант. Все зависит от целей, и постановки задачи.
Приложение мое. Разделяющую секцию не хочу использовать, так нужно будет как-то реализовать запись и чтение с этой секции, то есть у меня драйвер будет писать много данных которые должно обработать приложение и нужно чтобы пока программа не обработала старые данные они не удалялись. А данных будет много. Хочу узнать почему пайпы - плохое решение и что такое inverted calls ?
На OSR-Online была статейка Тут (Даю ссылку из гуглкеша, потому что на сайте надо регаться). Это обычный метод через IOCTL's о котором я писал выше.
Я уже отписал выше, что следует использовать. Эот вариант при грамотной реализации удовлетворяет всем критериям, как то: производительность, надёжность и гибкость. Не самый простой способ, наверное, но за несколько дней, думаю, изучишь. Если ты не знаешь деталей и не уверен в том, что тебе посоветовали, то, как минимум, следует не спорить, а переспросить что непонятно. Между прочим, вопрос уже не раз обсуждался, почитай здесь, например. Да не то чтобы плохое, но в ядре оно полностью недокументировано и кроме того, это банально медленее, чем вариант с APC. Эта такая модель взаимодействия драйвера и приложения, при котором фактически запрос уходит в ядро, но абстрактно, логически, запрос приходит из ядра. Суть в том, чтобы приложение послало Read-запрос драйверу, который вместо того, чтобы завершить, отложит его до того момента, когда у него появятся данные для приложения. И в этот момент драйвер заполняет выходной буфер и завершает запрос, передавая таким образом данные на пользовательский уровень. После обработки данных приложение снова посылает такой запрос драйверу и снова ждёт, когда то завершит запрос уже с данными. Не самая простая модель для реализации, надо сказать, придётся заморачиваться с поддержкой cancellation (ну это по уму если) и так далее.
Кстати, они там почему-то fast mutexes используют. Правильнее было бы на spin locks переписать, оверхед же.
Вот только не учли что очередь апк не ограничена. Ось захлебнётся, если поток не будет успевать обрабатывать апк, просто будет исчерпана вся память ядра, даже в юзермоде простой цикл NtQueueApcThread убивает ось в течении нескольких секунд(XP, 512M). Можно изменять ход исполнения потока, тоесть менять данные которые проверяет постоянно тред, либо менять код который он исполняет, а не ожидать на обьектах.
x64 Видимо автор статьи не знал обо всех подводных камнях fast mutex-ов. Другого объяснения для его ситуации я не вижу. APC там блокировать незачем...
x64 Это не очень быстро, зато очень не стабильно. Чем плоха простая запись в память, тоесть например взводим флажёк в переменной, которую постоянно юзает поток пользовательский ?
x64 Стабильность всегда была превыше всего. Особенно в режиме ядра. Самое лучшее - если ТС скажет какова скорость (предельно допустимая) для его задачи. Сколько раз в секунду надо снимать показания. Если "разумно", то вариант с APC подойдет, поставить пропуск данных (при очень частом их появлении), если это можно, либо сделать кеширование данных если это можно.. зависит от задачи. Рекомендовать же этот метод, либо какой то другой - не берусь. Хотя мысли наталкивают на вариант с DMA.
Стабильность, знаете ли, разная есть тоже. Про падения системы вообще и речи нет, и так понятно, что это недопустимо. А вот если, положим, пропустим несколько сетевых пакетов, - ну да, ну плохо, конечно, но не критично же.
Предложи вариант быстрее. Только, пожалуйста, безо всякой недокументированной грязищи. Чем не стабильно-то? Про память понятно, что ещё? Как предлагаешь пользовательскому потоку мониторить изменение этой переменной? Уж не исключениями ли? Не цикл же крутить без передыху.
x64 А что есчо нужно, когда система зависла значения не имеет что халт в ядре, что шадов не отвечает, результат то один и тотже - юзер ребутит систему. Быстро это если поток получает сообщение от другого потока, до смены кпл(если исполняются на разных процессорах). Тоесть например в случае апк поток должен возвратится из прерывания, а прежде войти в него. Соответственно имеется время простоя. Сюда относятся и манипуляции контекстом. Выше я предложил использовать общую память для синхронизации. Это предельно быстрый способ изменить ход исполнения потока. Без циклов не получится, это понятно ведь.
TermoSINteZ >Можно DMA использовать >Хотя мысли наталкивают на вариант с DMA. Конечно, имелось в виду "DirectIO"? Всё-таки за "DMA" уже закреплено другое значение. x64 >Кстати, они там почему-то fast mutexes используют. Правильнее было бы на spin locks переписать, оверхед же. Т.е. лучше, чтобы на время работы со списками поток бампался с PASSIVE до DISPATCH, а в случае соперничества впустую бы жёг процессорные циклы? Или здесь нечто другое подразумевалось?
Это ты описал ситуацию, при которой fast mutex как раз был бы более уместен (когда синхронизируется какая-то затратная по времени операция). Но у них не такая ситуация, оборачивать макрос InsertTailList в мутексы - это оверхед дикий, при использовании же спинлока тут и оверхед меньше и процессор простаивать практически не будет ибо участок кода слишком мал.
В статье написано все верно, советую почитать соответствующую доку "Locks, Deadlocks, and Synchronization" в часности раздел Choosing a Synchronization Mechanism. Про оверхед тоже неверно, о каком оверхеде идет речь, если спинлок заблочит весь планировщик на текущем потоке при захвате спинблокировки? Собственно можно было бы еще спорить о быстродействии спинлоков и обычных мьютексов, но в статье юзаются fast mutex'ы(незря они были придуманы, ога).
Sol_Ksacap Это реализуется открытием IOPM для пользовательского кода(R3). Зачем оно ? В нелинейный выгружаемый юзерспейс ? Достаточно создать страницу доступную для обоих колец защиты(PTE/PDE.US -> 1). Механизм разделяемой памяти основан на отображении страницы на разные линейные адреса. Тоесть PDBR(i)->PDE->PTE.PhysicalAddress = Const. TSS Нельзя, в условиях планирования(R3) это не имеет смысла.