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

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Использование CmRegisterCallback. Синхронизация с user mode.  (Прочитано 19920 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Erithron
Интересующийся

by
Offline Offline

« : 20-04-2010 20:30 » 

Здравствуйте.
Речь пойдет о передаче данных после перехвата из kernel в user.
Например обернем в мьютексы вида:
*процедура RegisterCallback*
1)Захватываем мьютекс
2)записываем перехваченные данные в буфер
3)Отпираем мьютекс


*процедура приема, user mode*
while(1)
{
1)Захватываем мьютекс
2)обрабатываем данные из буфера и очищаем его.
3)Отпираем мьютекс
}

Так вот, какова по вашему вероятность того, что во время ожидания мьютекса процедурой перехвата(с учетом, что мы перехватываем все обращения) к реестру произойдет несколько обращений?) Насколько я понял только одно из них в итоге сможет оказаться в буфере, а остальные уйдут в небытие.
Стоит ли делать систему без ожиданий  в RegisterCallback?
Записан
resource
Молодой специалист

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

« Ответ #1 : 20-04-2010 22:14 » 

Во-первых описано всё крайне непонятно. Надо поконкретнее относительно кода.
Во-вторых, опять же непонятно, в юзермоде и кернелмоде используется один и тот же мьютекс? Я так полагаю, что да, иначе вообще не было бы синхронизации. Но в итоге это очень странный, если не сказать неправильный способ синхронизации.
Записан
sss
Специалист

ru
Offline Offline

« Ответ #2 : 21-04-2010 00:36 » 

Erithron, следующие обращения к реестру будут происходить  других потоках и блокироваться на захвате мьютекса. А вот какой поток, в конце концов, захватит мьютекс первым - один из потоков "*процедура RegisterCallback*" или  поток "*процедура приема, user mode*" - будет решаться теорией вероятности и телепатическими способностями. Данная проблема называется "состояние гонок"....
« Последнее редактирование: 21-04-2010 00:39 от sss » Записан

while (8==8)
Erithron
Интересующийся

by
Offline Offline

« Ответ #3 : 21-04-2010 07:28 » 

Цитата
Во-первых описано всё крайне непонятно. Надо поконкретнее относительно кода.
Во-вторых, опять же непонятно, в юзермоде и кернелмоде используется один и тот же мьютекс? Я так полагаю, что да, иначе вообще не было бы синхронизации. Но в итоге это очень странный, если не сказать неправильный способ синхронизации.
Да, мьуютекс один. Относительно кода не описываю, т.к. его нету)
Цитата
Erithron, следующие обращения к реестру будут происходить  других потоках и блокироваться на захвате мьютекса. А вот какой поток, в конце концов, захватит мьютекс первым - один из потоков "*процедура RegisterCallback*" или  поток "*процедура приема, user mode*" - будет решаться теорией вероятности и телепатическими способностями. Данная проблема называется "состояние гонок"....
А точно, не заметил)


Не подскажите тогда, как это лучше синхронизировать? Дабы достичь максимальной скорости. "Усложнить" мьютексо-обверточный тип или использовать другие способы(например ивенты, или как писал выше, попробывать обойтись без синхро-операций)?
Записан
resource
Молодой специалист

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

« Ответ #4 : 21-04-2010 07:55 » 

Всё зависит от того, как организован буфер, и как данные передаются в юзермод. Я почему и говорил, что надо обсуждать не абстрактно, а относительно кода.
Как я вижу из всех этих абстракций, мьютексами сблокирован доступ к буферу. Я не пойму зачем это нужно, до тех пор пока не узнаю как организован буфер. Навскидку, похоже на мапинг.
« Последнее редактирование: 21-04-2010 08:02 от resource » Записан
PredatorAlpha
Помогающий

us
Offline Offline

« Ответ #5 : 21-04-2010 14:22 » 

в общем-то алгоритм циклического буфера устойчив к асинхронностям и взаимным перебиваниям. Можно обойтись без мютекса. Если конечно или чтение, или запись не производится одновременно из нескольких мест асинхронно.
Записан
resource
Молодой специалист

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

« Ответ #6 : 21-04-2010 14:25 » 

Ну если не применять никакой синхронизации, то как в данном случае чтение и запись могут производиться не асинхронно?
Записан
Ochkarik
Модератор

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

« Ответ #7 : 21-04-2010 15:37 » 

имеется в виду одновременная запись из двух потоков.
или одновременное чтение из двух потоков.

"один поток чтения - один поток записи", действительно можно без мьютексов синхронизировать.
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Ochkarik
Модератор

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

« Ответ #8 : 21-04-2010 15:52 » 

PS хотя....я бы и многопоточную запись обошел бы, без мьютексов) чисто на атомарных перестановках. (блочную, разумеется!)
для НЕКОТОРЫХ случаев очень красиво может получится)
Записан

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

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

« Ответ #9 : 21-04-2010 16:01 » 

Что-то я уже совсем ничего не понимаю.
Callback срабатывает в контексте того потока, который осуществляет обращение к реестру. Одновременно обращаться к реестру могут много потоков. Вопрос о том, что надо блокировать, а что не надо, упирается в способ передачи данных в юзермод. Судя по всему - это маппинг, иначе вообще не было бы никакого смысла во всех этих мьютексах со стороны юзермода. Но это всё какой-то беспредметный разговор до тех пор, пока ТС не соблаговолит объяснить эти начала.

Но вот поскольку обращаться к реестру могут одновременно много потоков, то как минимум в самом драйвере полюбому надо будет сблокировать запись в буфер.
« Последнее редактирование: 21-04-2010 16:04 от resource » Записан
Erithron
Интересующийся

by
Offline Offline

« Ответ #10 : 21-04-2010 16:22 » 

Вообще вопрос о синхронизации растет из неполного понимая работы коллбаков. Может кто сможет объяснить как это происходит?
Создается отдельный поток в котором вызывается ф-ия перехвата при изменениях в реестре? И что будет если мы поставим wait в перехватчик, что случиться если за время ожидания произойдет 10 изменений в реестре?
Пробовал ставить wait, все сильно начинает виснуть и без перезагрузки не обойтись(как будто, wait останавливает весь драйвер). И допустим если я поставил wait 5 секунд, первый перехват реестра идет через 5 секунд как и надо но последующие начинают идти раньше)
Цитата
"один поток чтения - один поток записи"
Вот такое мне и надо) Однако основная проблема по моему мнению может возникнуть из-за того что user не успеет за kernel и в итоге, если без синхронизации будет переполнение, если с синхронизацией не все данные могут достигнуть user. Насколько я понимаю kernel работает по шустрее user(а как часто происходит этот отлов реестра по сравнению со скоростью работы user я не представляю), поэтому нужен оптимальный вариант. Или я слишком "загоняюсь" и создаю проблемы которых не существует?)
Записан
resource
Молодой специалист

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

« Ответ #11 : 21-04-2010 16:31 » 

Создается отдельный поток в котором вызывается ф-ия перехвата при изменениях в реестре?

Никаких отдельных потоков не создается. Еще раз повторяю, callback вызывается в контексте потока, который обращается к реестру.

И что будет если мы поставим wait в перехватчик

Что за wait? Это функция или что? Если функция, то откуда?
Записан
Erithron
Интересующийся

by
Offline Offline

« Ответ #12 : 21-04-2010 16:38 » 

Ну использовал я KeWaitForSingleObject, где ожидался эвент.
Однако если я вставлял wait в процедуру обработки IRP_MJ_DEVICE_CONTROL, ожидание шло, однако коллбак работал и отлавливал все изменения в реестре. Или это уже IRP_MJ_DEVICE_CONTROL как-то "многопоточно" работает?)
Записан
resource
Молодой специалист

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

« Ответ #13 : 21-04-2010 16:41 » 

Я уже не понимаю. Что за ивент ты ждешь? Может какие куски кода привести и пояснить, а то мы тут долго так будем говорить ни о чём
Записан
Ochkarik
Модератор

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

« Ответ #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 уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Erithron
Интересующийся

by
Offline Offline

« Ответ #15 : 21-04-2010 16:55 » 

Цитата
Я уже не понимаю. Что за ивент ты ждешь? Может какие куски кода привести и пояснить, а то мы тут долго так будем говорить ни о чём
Ну смысл в том, что мне нужно понять как работает коллбак)
То есть если у меня есть простенький драйвер с коллбаком, то мой драйвер вместе с коллбаком будет работать в один поток, и вызывая ф-ии вида KeWaitxxx останавливаться будет весь драйвер?

Но экспериментируя я заметил следующее:
1)Если поставить KeWaitxxx с бесконечным ожиданием в процедуру коллбака, то замирает, видимо, весь драйвер(очень сильно все зависает, драйвер не принимает команды, коллбак не перехватывает изменения в реестре).
2)Если поставить KeWaitxxx с бесконечным ожиданием в процедуру обработки IRP_MJ_DEVICE_CONTROL, то никаких видных на лицо зависаний нету и процедура коллбака нормально работает(не останавливается).
Записан
Ochkarik
Модератор

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

« Ответ #16 : 21-04-2010 17:02 » 

читайте Руссиновича. раздел про переключение потоков.
кажется у вас в этом небольшой пробел...
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Erithron
Интересующийся

by
Offline Offline

« Ответ #17 : 21-04-2010 17:03 » new

Ну вот допустим грубый код:
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
Модератор

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

« Ответ #18 : 21-04-2010 17:06 » 

то есть большой...)
правда почитайте. я не к тому что мне объяснять лень - просто там ооочень хорошо изложено.
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Erithron
Интересующийся

by
Offline Offline

« Ответ #19 : 21-04-2010 20:46 » 

Вроде разобрался)
1)Драйверы в основном однопотоковая штука
2)IRP_MJ_DEVICE_CONTROL есть прерывания и поэтому выполняются не в контексте потока драйвера. Поэтому при KeWaitxxx в обработчике прерываний, драйвер продолжает функционировать.
3)RegisterCallback выполняется в контексте потока драйвера. Представляет собой что-то вроде "подключения к системе", и система  оповещает драйвер о махинациях с реестром. Однако, система запрашивает так же ответ, поэтому если вставить в обработчик KeWaitxxx с бесконечным ожиданием, то все начинает к хреням виснуть, т.к. не могут быть выполнены эти самые перехваченные махинации в реестре.
Так же насколько я понял RegisterCallback все же уязвима и отлавливает не все махинации с реестром. То есть, если во время обработки RegisterCallback-процедурой одного события реестра, произойдет второе, то второе пройдет мимо обработчика.

Все правильно уяснил?). Особенно интересует часть с RegisterCallback.
Записан
resource
Молодой специалист

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

« Ответ #20 : 21-04-2010 20:52 » 

Ужас. Весь мир с ног на голову поставил. Тут слишком много объяснять надо, на целую книгу потянет, а потому следует всётаки внять рекомендациям в постах #16 и #18.
Записан
Erithron
Интересующийся

by
Offline Offline

« Ответ #21 : 22-04-2010 09:47 » 

В общем да, IRP_MJ_DEVICE_CONTROL совершенно не то, что я написал. С этим я уже точно разобрался)

Однако остается вопрос насчет RegisterCallback. Коллбак представляет собой "фильтр". Происходит "событие"-> оно отправляется в фильтр->фильтр обрабатывает его->отправляет дальше.
Но нужен ответ на вопрос: что будет если во время обработки события фильтром, произойдет еще n событий? Они станут в "очередь"(сколько тогда эта очередь может может вместить таких событий)? Или пройдут мимо фильтра?
Записан
resource
Молодой специалист

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

« Ответ #22 : 22-04-2010 10:01 » 

Да это всё пустое. Надо сначала теорию почитать. Тут надо понимать как функционируют потоки. Никакой очереди не будет (я так думаю), потому что пока один вызов не завершен, то другой вызов в этом же потоке просто никак не может произойти.
Записан
Ochkarik
Модератор

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

« Ответ #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 уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Erithron
Интересующийся

by
Offline Offline

« Ответ #24 : 22-04-2010 16:51 » 

Спасибо, разобрался)

Последний вопрос:
Допустим мне необходимо передать полный путь к измененному разделу. Однако судя по всему в XP это путь может быть бесконечно длинным и ограничен только общей памятью машины(или я не прав?).
И вот как такое тогда передавать? Или может можно передать "хэндл ключа" и уже в user приложении вытянуть оттуда путь?

ЗЫ: Передачу планирую делать через маппинг, но наверное разница как передавать небольшая.
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines