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

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Использование CmRegisterCallback. Синхронизация с user mode.  (Прочитано 19868 раз)
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 » 

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

Да это всё пустое. Надо сначала теорию почитать. Тут надо понимать как функционируют потоки. Никакой очереди не будет (я так думаю), потому что пока один вызов не завершен, то другой вызов в этом же потоке просто никак не может произойти.
Записан
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