Erithron
Интересующийся
Offline
|
|
« : 20-04-2010 20:30 » |
|
Здравствуйте. Речь пойдет о передаче данных после перехвата из kernel в user. Например обернем в мьютексы вида: *процедура RegisterCallback* 1)Захватываем мьютекс 2)записываем перехваченные данные в буфер 3)Отпираем мьютекс
*процедура приема, user mode* while(1) { 1)Захватываем мьютекс 2)обрабатываем данные из буфера и очищаем его. 3)Отпираем мьютекс }
Так вот, какова по вашему вероятность того, что во время ожидания мьютекса процедурой перехвата(с учетом, что мы перехватываем все обращения) к реестру произойдет несколько обращений?) Насколько я понял только одно из них в итоге сможет оказаться в буфере, а остальные уйдут в небытие. Стоит ли делать систему без ожиданий в RegisterCallback?
|
|
|
Записан
|
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #1 : 20-04-2010 22:14 » |
|
Во-первых описано всё крайне непонятно. Надо поконкретнее относительно кода. Во-вторых, опять же непонятно, в юзермоде и кернелмоде используется один и тот же мьютекс? Я так полагаю, что да, иначе вообще не было бы синхронизации. Но в итоге это очень странный, если не сказать неправильный способ синхронизации.
|
|
|
Записан
|
|
|
|
sss
Специалист
Offline
|
|
« Ответ #2 : 21-04-2010 00:36 » |
|
Erithron, следующие обращения к реестру будут происходить других потоках и блокироваться на захвате мьютекса. А вот какой поток, в конце концов, захватит мьютекс первым - один из потоков "*процедура RegisterCallback*" или поток "*процедура приема, user mode*" - будет решаться теорией вероятности и телепатическими способностями. Данная проблема называется "состояние гонок"....
|
|
« Последнее редактирование: 21-04-2010 00:39 от sss »
|
Записан
|
while (8==8)
|
|
|
Erithron
Интересующийся
Offline
|
|
« Ответ #3 : 21-04-2010 07:28 » |
|
Во-первых описано всё крайне непонятно. Надо поконкретнее относительно кода. Во-вторых, опять же непонятно, в юзермоде и кернелмоде используется один и тот же мьютекс? Я так полагаю, что да, иначе вообще не было бы синхронизации. Но в итоге это очень странный, если не сказать неправильный способ синхронизации. Да, мьуютекс один. Относительно кода не описываю, т.к. его нету) Erithron, следующие обращения к реестру будут происходить других потоках и блокироваться на захвате мьютекса. А вот какой поток, в конце концов, захватит мьютекс первым - один из потоков "*процедура RegisterCallback*" или поток "*процедура приема, user mode*" - будет решаться теорией вероятности и телепатическими способностями. Данная проблема называется "состояние гонок".... А точно, не заметил) Не подскажите тогда, как это лучше синхронизировать? Дабы достичь максимальной скорости. "Усложнить" мьютексо-обверточный тип или использовать другие способы(например ивенты, или как писал выше, попробывать обойтись без синхро-операций)?
|
|
|
Записан
|
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #4 : 21-04-2010 07:55 » |
|
Всё зависит от того, как организован буфер, и как данные передаются в юзермод. Я почему и говорил, что надо обсуждать не абстрактно, а относительно кода. Как я вижу из всех этих абстракций, мьютексами сблокирован доступ к буферу. Я не пойму зачем это нужно, до тех пор пока не узнаю как организован буфер. Навскидку, похоже на мапинг.
|
|
« Последнее редактирование: 21-04-2010 08:02 от resource »
|
Записан
|
|
|
|
PredatorAlpha
Помогающий
Offline
|
|
« Ответ #5 : 21-04-2010 14:22 » |
|
в общем-то алгоритм циклического буфера устойчив к асинхронностям и взаимным перебиваниям. Можно обойтись без мютекса. Если конечно или чтение, или запись не производится одновременно из нескольких мест асинхронно.
|
|
|
Записан
|
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #6 : 21-04-2010 14:25 » |
|
Ну если не применять никакой синхронизации, то как в данном случае чтение и запись могут производиться не асинхронно?
|
|
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #7 : 21-04-2010 15:37 » |
|
имеется в виду одновременная запись из двух потоков. или одновременное чтение из двух потоков.
"один поток чтения - один поток записи", действительно можно без мьютексов синхронизировать.
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
Ochkarik
|
|
« Ответ #8 : 21-04-2010 15:52 » |
|
PS хотя....я бы и многопоточную запись обошел бы, без мьютексов) чисто на атомарных перестановках. (блочную, разумеется!) для НЕКОТОРЫХ случаев очень красиво может получится)
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #9 : 21-04-2010 16:01 » |
|
Что-то я уже совсем ничего не понимаю. Callback срабатывает в контексте того потока, который осуществляет обращение к реестру. Одновременно обращаться к реестру могут много потоков. Вопрос о том, что надо блокировать, а что не надо, упирается в способ передачи данных в юзермод. Судя по всему - это маппинг, иначе вообще не было бы никакого смысла во всех этих мьютексах со стороны юзермода. Но это всё какой-то беспредметный разговор до тех пор, пока ТС не соблаговолит объяснить эти начала.
Но вот поскольку обращаться к реестру могут одновременно много потоков, то как минимум в самом драйвере полюбому надо будет сблокировать запись в буфер.
|
|
« Последнее редактирование: 21-04-2010 16:04 от resource »
|
Записан
|
|
|
|
Erithron
Интересующийся
Offline
|
|
« Ответ #10 : 21-04-2010 16:22 » |
|
Вообще вопрос о синхронизации растет из неполного понимая работы коллбаков. Может кто сможет объяснить как это происходит? Создается отдельный поток в котором вызывается ф-ия перехвата при изменениях в реестре? И что будет если мы поставим wait в перехватчик, что случиться если за время ожидания произойдет 10 изменений в реестре? Пробовал ставить wait, все сильно начинает виснуть и без перезагрузки не обойтись(как будто, wait останавливает весь драйвер). И допустим если я поставил wait 5 секунд, первый перехват реестра идет через 5 секунд как и надо но последующие начинают идти раньше) "один поток чтения - один поток записи" Вот такое мне и надо) Однако основная проблема по моему мнению может возникнуть из-за того что user не успеет за kernel и в итоге, если без синхронизации будет переполнение, если с синхронизацией не все данные могут достигнуть user. Насколько я понимаю kernel работает по шустрее user(а как часто происходит этот отлов реестра по сравнению со скоростью работы user я не представляю), поэтому нужен оптимальный вариант. Или я слишком "загоняюсь" и создаю проблемы которых не существует?)
|
|
|
Записан
|
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #11 : 21-04-2010 16:31 » |
|
Создается отдельный поток в котором вызывается ф-ия перехвата при изменениях в реестре? Никаких отдельных потоков не создается. Еще раз повторяю, callback вызывается в контексте потока, который обращается к реестру. И что будет если мы поставим wait в перехватчик Что за wait? Это функция или что? Если функция, то откуда?
|
|
|
Записан
|
|
|
|
Erithron
Интересующийся
Offline
|
|
« Ответ #12 : 21-04-2010 16:38 » |
|
Ну использовал я KeWaitForSingleObject, где ожидался эвент. Однако если я вставлял wait в процедуру обработки IRP_MJ_DEVICE_CONTROL, ожидание шло, однако коллбак работал и отлавливал все изменения в реестре. Или это уже IRP_MJ_DEVICE_CONTROL как-то "многопоточно" работает?)
|
|
|
Записан
|
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #13 : 21-04-2010 16:41 » |
|
Я уже не понимаю. Что за ивент ты ждешь? Может какие куски кода привести и пояснить, а то мы тут долго так будем говорить ни о чём
|
|
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #14 : 21-04-2010 16:42 » |
|
запоздалое сообщение: (в ответ на https://forum.shelek.ru/index.php/topic,24188.msg233318.html#msg233318): 1. Имелось в виду то, что в данном случае (если я правильно понял) можно в качестве FIFO использовать кольцевой буфер для передачи данных. Хотя бы просто потому, что в промежутках между двумя операциями "2)обрабатываем данные из буфера и очищаем его" может произойти довольно большое число "2)записываем перехваченные данные в буфер". 2. Раз речь зашла о кольцевых буферах, то для случаев, когда один-поток-пишет/один-поток-читает, синхронизация операций чтения/записи может быть выполнена на interlocked функциях, БЕЗ МЬЮТЕКСОВ. И использование циклиического буфера- отчасти разрешает проблему "состояния гонок". 3. Я же, на вскидку заметил, что чисто ради эстетического наслаждения и интереса, без использования мьютексов, можно попробовать реализовать систему синхронизации операций многопоточной записи _и_ многопоточного чтения блоков кольцевого буфера) В стиле а-ля SList. PS а то что маппинг - никто и не спорит... вопрос логической организации обмена данными)
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
Erithron
Интересующийся
Offline
|
|
« Ответ #15 : 21-04-2010 16:55 » |
|
Я уже не понимаю. Что за ивент ты ждешь? Может какие куски кода привести и пояснить, а то мы тут долго так будем говорить ни о чём Ну смысл в том, что мне нужно понять как работает коллбак) То есть если у меня есть простенький драйвер с коллбаком, то мой драйвер вместе с коллбаком будет работать в один поток, и вызывая ф-ии вида KeWaitxxx останавливаться будет весь драйвер? Но экспериментируя я заметил следующее: 1)Если поставить KeWaitxxx с бесконечным ожиданием в процедуру коллбака, то замирает, видимо, весь драйвер(очень сильно все зависает, драйвер не принимает команды, коллбак не перехватывает изменения в реестре). 2)Если поставить KeWaitxxx с бесконечным ожиданием в процедуру обработки IRP_MJ_DEVICE_CONTROL, то никаких видных на лицо зависаний нету и процедура коллбака нормально работает(не останавливается).
|
|
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #16 : 21-04-2010 17:02 » |
|
читайте Руссиновича. раздел про переключение потоков. кажется у вас в этом небольшой пробел...
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
Erithron
Интересующийся
Offline
|
|
« Ответ #17 : 21-04-2010 17:03 » |
|
Ну вот допустим грубый код: ntStatus = CmRegisterCallback(RegWatcher,ext,&Cookie); DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DriverDeviceControl; NTSTATUS RegWatcher(IN PVOID Data,IN PVOID CallType,IN PVOID CallData) { KeWaitxxx //Если KeWaitxxx стоит с бесконечным ожиданием, то все повисает) Команды типа TEST_SMTH драйвер уже не принимает и не выводит сообщений + почему-то начинает глючть пуск и сама система почти усмирает. DbgPrint("!!!"); } NTSTATUS DriverDeviceControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp) { case TEST_SMTH: { KeWaitxxx //Если KeWaitxxx стоит с бесконечным ожиданием, то ожидание идет, до вывода "aaa", не доходит но вывод "!!!" из RegWatcher идет. DbgPrint("aaa"); } } читайте Руссиновича. раздел про переключение потоков. кажется у вас с этим небольшой пробел... Спасибо, почитаю. ЗЫ: В прицнипе приведенный выше код не актуален, т.к. иду читать теорию)
|
|
« Последнее редактирование: 21-04-2010 17:05 от Erithron »
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #18 : 21-04-2010 17:06 » |
|
то есть большой...) правда почитайте. я не к тому что мне объяснять лень - просто там ооочень хорошо изложено.
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
Erithron
Интересующийся
Offline
|
|
« Ответ #19 : 21-04-2010 20:46 » |
|
Вроде разобрался) 1)Драйверы в основном однопотоковая штука 2)IRP_MJ_DEVICE_CONTROL есть прерывания и поэтому выполняются не в контексте потока драйвера. Поэтому при KeWaitxxx в обработчике прерываний, драйвер продолжает функционировать. 3)RegisterCallback выполняется в контексте потока драйвера. Представляет собой что-то вроде "подключения к системе", и система оповещает драйвер о махинациях с реестром. Однако, система запрашивает так же ответ, поэтому если вставить в обработчик KeWaitxxx с бесконечным ожиданием, то все начинает к хреням виснуть, т.к. не могут быть выполнены эти самые перехваченные махинации в реестре. Так же насколько я понял RegisterCallback все же уязвима и отлавливает не все махинации с реестром. То есть, если во время обработки RegisterCallback-процедурой одного события реестра, произойдет второе, то второе пройдет мимо обработчика.
Все правильно уяснил?). Особенно интересует часть с RegisterCallback.
|
|
|
Записан
|
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #20 : 21-04-2010 20:52 » |
|
Ужас. Весь мир с ног на голову поставил. Тут слишком много объяснять надо, на целую книгу потянет, а потому следует всётаки внять рекомендациям в постах #16 и #18.
|
|
|
Записан
|
|
|
|
Erithron
Интересующийся
Offline
|
|
« Ответ #21 : 22-04-2010 09:47 » |
|
В общем да, IRP_MJ_DEVICE_CONTROL совершенно не то, что я написал. С этим я уже точно разобрался)
Однако остается вопрос насчет RegisterCallback. Коллбак представляет собой "фильтр". Происходит "событие"-> оно отправляется в фильтр->фильтр обрабатывает его->отправляет дальше. Но нужен ответ на вопрос: что будет если во время обработки события фильтром, произойдет еще n событий? Они станут в "очередь"(сколько тогда эта очередь может может вместить таких событий)? Или пройдут мимо фильтра?
|
|
|
Записан
|
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #22 : 22-04-2010 10:01 » |
|
Да это всё пустое. Надо сначала теорию почитать. Тут надо понимать как функционируют потоки. Никакой очереди не будет (я так думаю), потому что пока один вызов не завершен, то другой вызов в этом же потоке просто никак не может произойти.
|
|
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #23 : 22-04-2010 10:04 » |
|
http://msdn.microsoft.com/en-us/library/ff560903(VS.85).aspxремарка "RegistryCallback executes at IRQL = PASSIVE_LEVEL and in the context of the thread that is performing the registry operation." это исчерпываюащя информация, но чтобы ей воспользоваться.... еще раз, повторяю: ЧИТАЙТЕ КНИГУ. иначе у вас полная каша в голове будет. там нет очереди ТАКИХ событий. там есть процессы и переключение контекстов.
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
Erithron
Интересующийся
Offline
|
|
« Ответ #24 : 22-04-2010 16:51 » |
|
Спасибо, разобрался)
Последний вопрос: Допустим мне необходимо передать полный путь к измененному разделу. Однако судя по всему в XP это путь может быть бесконечно длинным и ограничен только общей памятью машины(или я не прав?). И вот как такое тогда передавать? Или может можно передать "хэндл ключа" и уже в user приложении вытянуть оттуда путь?
ЗЫ: Передачу планирую делать через маппинг, но наверное разница как передавать небольшая.
|
|
|
Записан
|
|
|
|
|