zss
Участник
Offline
|
|
« : 15-07-2004 07:27 » |
|
Доброго всем дня !
Насколько я помню, процесс, создавая какой-либо объект ядра, создает в своем адресном пространстве таблицу описателей, в которую помещает описатель объекта (HANDLE), его адрес в памяти и флаги. По-сути, HANDLE - это индекс в таблице описателей.
В самой структуре объекта счетчик владельцев = 1. Если какой либо процесс (или поток) получает доступ к данному объекту, то счетчик увеличивается на 1. Для того, чтобы система сама удалила объект ядра - необходимо закрыть все описатели (CloseHandle()). Как только счетчик = 0, система удаляет объект из памяти. Причем закрывая HANDLE происходит только удаление записи в таблице описателей и уменьшение счетчика.
Вроде бы все так.
У меня существует один процесс P1 (user-mode приложение), который создает объект (event), и второй P2 (драйвер) - который получает к нему доступ (тоесть число владельцев = 2). Описатель объекта храниться в глобальной переменной как у Р1 так и у Р2. Далее существует некое множество потоков Рn, которые выполняют код процесса Р2. Причем они синхронизируются с помощью KeWaitForSingleObject.
Теперь вопросы:
1. Получат ли потоки Pn доступ к объекту event используя только KeWaitForSingleObject, ведь адрес event хранится в глобальной переменной P2 (а код выполняется в адресном пространстве этого процесса).
2. Увеличивается ли счетчик, если какой либо поток вызывает KeWaitForSingleObject ?
3. Ведет ли объект event вообще подсчет числа владельцев (к примеру mutex точно ведет)
4. Если ведет, то как освободить event, если я не знаю сколько раз был захвачен этот объект ?
Все вопросы к тому, что event сбрасывается в драйвере, но пользовательское приложение не может его взвести.
|
|
|
Записан
|
|
|
|
mad
Гость
|
|
« Ответ #1 : 15-07-2004 11:41 » |
|
1. Получат ли потоки Pn доступ к объекту event используя только KeWaitForSingleObject, ведь адрес event хранится в глобальной переменной P2 (а код выполняется в адресном пространстве этого процесса). Не процесса, а ядра. Да.
2. Увеличивается ли счетчик, если какой либо поток вызывает KeWaitForSingleObject ? нет
3. Ведет ли объект event вообще подсчет числа владельцев (к примеру mutex точно ведет) да,конечно, есть поле рефренс каунт.только оно само ничего не бывает.
4. Если ведет, то как освободить event, если я не знаю сколько раз был захвачен этот объект ? obdereferenceobject
|
|
|
Записан
|
|
|
|
zss
Участник
Offline
|
|
« Ответ #2 : 15-07-2004 12:38 » |
|
Спасибо - по первым трем вопросам я понял 4. Если ведет, то как освободить event, если я не знаю сколько раз был захвачен этот объект ? obdereferenceobject
Тоесть здесь KeClearEvent не поможет ? А если использовать ObDereferenceObject - то эта функция гарантирует освобождение от всех захватов (которые кстати могут происходить в момент освобождения)? и еще вопрос event создается в user-mode приложении. В драйвер я передаю HANDLE, а получаю доступ к объекту ObReferenceObjectByHandle)hReadEvent, GENERIC_ALL, NULL, KernelMode, &pReadEvent, NULL:;
Этого достаточно или надо еще что-то (ну к примеру KeInitializeEvent...) Спасибо
|
|
|
Записан
|
|
|
|
mad
Гость
|
|
« Ответ #3 : 15-07-2004 13:11 » |
|
Тоесть здесь KeClearEvent не поможет ? А если использовать ObDereferenceObject - то эта функция гарантирует освобождение от всех захватов (которые кстати могут происходить в момент освобождения)?
Я под освобождением я имел ввиду дерефренс. Для сброса ивента, нужно keclearevent, Состояние объекта и рефренс каунт - разные поля структуры объекта. Почему они должны быть связаны? Я не понимаю накой тебе рефренс, рефренс с текущим состоянием объекта не связан! Очистишь рефренс и вызовешь keclearevent - получишь BSOD в худшем случае. Этого достаточно или надо еще что-то (ну к примеру KeInitializeEvent...)
достаточно
|
|
|
Записан
|
|
|
|
zss
Участник
Offline
|
|
« Ответ #4 : 15-07-2004 13:20 » |
|
Спасибо за советы Но если все так хорошо как я думая, то почему происходит следующее : когда драйвер сбрасывает event - пользователь начинает читать, а драйвер ждет. Когда пользователь все вычитал из буфера, то он выставляет event, а драйвер все-равно продолжает ждать ?
|
|
|
Записан
|
|
|
|
SlavaI
Главный специалист
Offline
|
|
« Ответ #5 : 15-07-2004 13:34 » |
|
Далее существует некое множество потоков Рn, которые выполняют код процесса Р2.
Сильная фраза. Только драйвер- это не процесс. А отсюда возникает вопрос- какой HANDLE ты хранишь в драйвере и как он получен(в контексте какого процесса).
|
|
|
Записан
|
|
|
|
Anonymous
Гость
|
|
« Ответ #6 : 15-07-2004 16:07 » |
|
когда драйвер <сбрасывает> event - пользователь начинает читать то он <выставляет> event, а драйвер все-равно продолжает ждать
как ты инициализировал ивент в юзер моде? как авторесет?
|
|
|
Записан
|
|
|
|
Anonymous
Гость
|
|
« Ответ #7 : 15-07-2004 16:08 » |
|
попробуй авторесет и не используй ресета ивента вручную
|
|
|
Записан
|
|
|
|
maad
Гость
|
|
« Ответ #8 : 15-07-2004 16:09 » |
|
..
|
|
|
Записан
|
|
|
|
zss
Участник
Offline
|
|
« Ответ #9 : 16-07-2004 05:51 » |
|
Отвечаю 1. как ты инициализировал ивент в юзер моде? как авторесет? Так. Причем функция чтения в отдельном потоке hReadEvent = CreateEvent)NULL, FALSE, FALSE, NULL:; if )hReadEvent:| hWriteEvent = CreateEvent)NULL, TRUE, TRUE, NULL:; if )hWriteEvent:| ... HANDLE hThread = )HANDLE:_beginthreadex )NULL, 0, ReadMemory, NULL, 0, &ThreadID:; .... " "
2. Сильная фраза. Только драйвер- это не процесс. А отсюда возникает вопрос- какой HANDLE ты хранишь в драйвере и как он получен(в контексте какого процесса).
В контексте user-mode (DriverDeviceControl). Я из user-mode приложения передаю HANDLE, а драйвер в контексте user-mode ObReferenceObjectByHandle)hReadEvent, GENERIC_ALL, NULL, KernelMode, &pReadEvent, NULL:;
|
|
|
Записан
|
|
|
|
Anonymous
Гость
|
|
« Ответ #10 : 16-07-2004 07:08 » |
|
попробуй так
hWriteEvent = CreateEvent(NULL, <FALSE>, TRUE, NULL);
|
|
|
Записан
|
|
|
|
mad
Гость
|
|
« Ответ #11 : 16-07-2004 07:10 » |
|
и убери все ResetEvent
|
|
|
Записан
|
|
|
|
zss
Участник
Offline
|
|
« Ответ #12 : 16-07-2004 07:15 » |
|
К сожалению мне так нельзя делать Потому, что происходит не одна запись в разделяемый буфер, а к примеру 500 записей. А когда буфер заполнился - тогда разрешение на его чтение. Если делать оба event с автосбросом, то тогда писать и читать прейдется тольео по одной записи, что увеличивает нагрузку на процессор
|
|
|
Записан
|
|
|
|
mad
Гость
|
|
« Ответ #13 : 16-07-2004 15:20 » |
|
Хм....странная у тебя организация доступа к буферу....очень уж простая. Мне этого не понять
|
|
|
Записан
|
|
|
|
zss
Участник
Offline
|
|
« Ответ #14 : 17-07-2004 10:39 » |
|
Хм....странная у тебя организация доступа к буферу....очень уж простая. Мне этого не понять А ты можешь предложить что-то иное ?
|
|
|
Записан
|
|
|
|
zss
Участник
Offline
|
|
« Ответ #15 : 21-07-2004 12:41 » |
|
Недавно еще раз пролистал Рихтера (прикольные все-таки он дядька - понятно пишет). Так вот появилась идея. А если все организовать таким образом: 1. Функция записи построена не на event, а на mutex - для монопольного доступа к буферу (ну и естественно для инкримента счетчика записей использовать interlock - функции). 2. Тем самым запись будет производится монопольно, а HANDLE mutex-а не надо будет передовать из пользовательского приложения. 3. из user-mode приложения передается только event для чтения и записи - а используются они только для синхронизации чтения (тоесть когда буфер заполнился - сигнализируем пользователю о том, что можно читать и ждем конца чтения) В этом случае вроде не должно быть dedlock-ов Как Вы думаете - это прокатит, или есть в чем-то ошибка ?
|
|
|
Записан
|
|
|
|
npak
|
|
« Ответ #16 : 21-07-2004 13:15 » |
|
zss, дедлок может возникнуть, если есть более одного объекта синхронизации. Пока только один буфер, то всё будет в порядке.
Если буферов два, скажем B1 и B2, процесс P1 залочил мутекс на B1, процесс P2 залочил мутекс на B2. Предположим, что для завершения работы процессу P1 нужен доступ к буферу B2, а процессу P2 доступ к буферу B1. Если процессы будут тупо лочить буферы, то они навечно (до прекращения работы одного из процессов) друг друга будут ждать. Дедлок.
|
|
|
Записан
|
|
|
|
SlavaI
Главный специалист
Offline
|
|
« Ответ #17 : 22-07-2004 13:39 » |
|
1. Функция записи построена не на event, а на mutex - для монопольного доступа к буферу (ну и естественно для инкримента счетчика записей использовать interlock - функции). 2. Тем самым запись будет производится монопольно, а HANDLE mutex-а не надо будет передовать из пользовательского приложения. 3. из user-mode приложения передается только event для чтения и записи - а используются они только для синхронизации чтения (тоесть когда буфер заполнился - сигнализируем пользователю о том, что можно читать и ждем конца чтения)
На первый взгляд это вобще никакая не синхронизация. Вот заполнился буфер и ты через event сказал читать, а в этот момент кто-то хватает мютекс и начинает писать, а ты читаешь то что записали. Фигняс получается.
|
|
|
Записан
|
|
|
|
zss
Участник
Offline
|
|
« Ответ #18 : 23-07-2004 05:21 » |
|
На первый взгляд это вобще никакая не синхронизация. Вот заполнился буфер и ты через event сказал читать, а в этот момент кто-то хватает мютекс и начинает писать, а ты читаешь то что записали. Фигняс получается. Как ни странно, но этот код заработал !!! Если буфер заполнился, то я говорю читать и жду конца чтения. Если же кто-то пытается в этот момент захватить mutex, то он будет ждать. Как пишет Рихтер - mutex используется для монопольного доступа к разделяемым ресурсам. Как только я KeReleaseMutex, то система проверяет какой из потоков ожидает mutex и передает его во владение только одному потоку (причем Microsoft гарантирует что алгоритм выбора честный, тоесть не зависит от привелегий потока)
|
|
|
Записан
|
|
|
|
SlavaI
Главный специалист
Offline
|
|
« Ответ #19 : 06-08-2004 11:19 » |
|
Как ни странно, но этот код заработал !!!
Если код типа <Захватил ресурс> Работа с буфером <Освободил ресурс> Работать он естественно будет если все потоки так делают, но то что ты написал этому не соотвествует, у тебя зачем то два объекта- event и mutex.
|
|
|
Записан
|
|
|
|
|