Вызов KeWaitForSingleObject при IRQL = DISPATCH_LEVEL

Тема в разделе "WASM.NT.KERNEL", создана пользователем er1ss, 22 июл 2008.

  1. er1ss

    er1ss New Member

    Публикаций:
    0
    Регистрация:
    22 июл 2008
    Сообщения:
    8
    Народ!!!

    Просветите новичка.

    Кто нибудь может доступно объяснить почему === НЕЛЬЗЯ === вызывать KeWaitForSingleObject при IRQL = DISPATCH_LEVEL при ненулевом значении таймаута?

    Что при этом происходит в ядре и почему это все-таки иногда работает.

    И как все-таки ожидать события при IRQL = DISPATCH_LEVEL так штобы не было переключения контекста причем на двух и более ядерных процессорах?

    ЗЫ:
    Задача:

    Драйвер для УСБ устройства.
    1. Устройство посылает синхронизирующие посылки через конечную точку прерываний (Interupt endpoint).
    2. Устройство начинает слать поток данных по (Bulk endpoint), блок данных фиксированной длины (Фрейм).

    Если между событием 1 и 2 происходит переключение контекста то получаем корявые данные (фрейм не с начала). Проблема в том что вклиница в данные фрейма нельзя и добавить какие нибудь сигнатуры и заголовки тоже нельзя. :dntknw:


    Вопрос: Как засинхронизировать эти два события???
     
  2. 2FED

    2FED New Member

    Публикаций:
    0
    Регистрация:
    20 фев 2008
    Сообщения:
    1.002
    Нельзя использовать потому что планировщик потоков работает на DISPATCH_LEVEL, а когда твой код работает на DISPATCH_LEVEL он вытесняет планировщик. А что происходит при вызове KeWaitForSingleObject? Правильно поток засыпает пока не сработает событие, и планировщик передаёт управление другим потокам, но посколько при DISPATCH_LEVEL планировщик вытесняется он не может произвести эту операцию
     
  3. er1ss

    er1ss New Member

    Публикаций:
    0
    Регистрация:
    22 июл 2008
    Сообщения:
    8
    Хорошо.

    Если у нас однопроцессорная машина, то планировщик вытесняется на текущем процессоре у которого IRQL = DISPATCH_LEVEL.
    Но если машина двухпроцессорная или процессор многоядерный, то у каждого каждого процессора может быть различный текущий IRQL и соответсвенно на одном из процессоров планировщик всетаки сможет стартовать и установить событие. Или в SMP планировщик привязан к конкретному процессору??.
     
  4. er1ss

    er1ss New Member

    Публикаций:
    0
    Регистрация:
    22 июл 2008
    Сообщения:
    8
    Еще вопрос как правильно отменять пакеты IRP.

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

    // KeWaitForSingleObject(&pDx->USBDSemaphore,Executive,KernelMode,FALSE,NULL);

    for (i=0; i<BULKUSB_MAX_IRP; i++)
    {
    if (StreamObject->TransferObjectList &&
    StreamObject->TransferObjectList->Irp)
    {
    USB_DbgMessage( ("USB_StopBulkStream(): IoCancelIrp() %d\n", i) );
    IoCancelIrp(StreamObject->TransferObjectList->Irp);
    }
    }

    // KeReleaseSemaphore(&pDx->USBDSemaphore,LOW_REALTIME_PRIORITY,1,FALSE);

    // Wait for any io request pending for this stream object to
    // complete before returning success.
    // This event is set when streamObject->PendingIrpCount goes to 0
    USB_DbgMessage( ("USB_StopBulkStream(): KeWaitForSingleObject enter\n") );
    KeWaitForSingleObject( &StreamObject->NoPendingIrpEvent, Executive, KernelMode, FALSE, NULL);
    USB_DbgMessage( ("USB_StopBulkStream(): KeWaitForSingleObject exit\n") );

    // Free all the buffers, URBS, and Irps associated with our stream object
    for (i=0; i<BULKUSB_MAX_IRP; i++)
    {
    transferObject = StreamObject->TransferObjectList;

    if (transferObject)
    {
    if ( transferObject->Irp )
    {
    IoFreeIrp( transferObject->Irp );
    transferObject->Irp = NULL;
    }

    ExFreePool( transferObject->Urb );
    ExFreePool( transferObject );
    StreamObject->TransferObjectList = NULL;
    }
    }
     
  5. Zufyxe

    Zufyxe New Member

    Публикаций:
    0
    Регистрация:
    13 авг 2004
    Сообщения:
    137
    Адрес:
    Russia
    что-то как-то мутно написано...
    Во первых, такой сущности как "планировщик" в винде нет. Есть набор функций ядра, логически объеденненых под названием dispatcher. Причем код этих функций работает в контексте соостветствующих нитей. Такого понятия как "поток плнировщика" тоже не существует.
    Во вторых, код dispatcher-a выполняется при IRQL==SYNCH_LEVEL, где SYNCH_LEVEL==DISPATCH_LEVEL это частный случай для UP системы.
    В третьих, термин "вытеснение" (preemption) в данном случае не применим, поскольку когда нить уходит в ожидание её никто не "вытесняет", она сама "передает управление".

    Ну и по существу вопроса:
    Переключение контекста нити происходит при IRQL == PASSIVE_LEVEL. Это закон. Именно для того и были введены уровни IRQL. Чтобы, скажем, IRQL==DISPATCH_LEVEL гарантировал то, что CurrentThread не будет вытеснен.

    Вот блин, неужели ни одной нормальной статьи по Windows Dispatcher в инете нету?
     
  6. er1ss

    er1ss New Member

    Публикаций:
    0
    Регистрация:
    22 июл 2008
    Сообщения:
    8
    Чего то я совсем запутался.
    В MSDN Написано

    When a processor is running at a given IRQL, the interrupts at that IRQL and lower are masked off (blocked) on the processor. For example, a processor that is running at IRQL=DISPATCH_LEVEL can be interrupted only by a request at an IRQL greater than DISPATCH_LEVEL.

    The system schedules all threads to run at IRQLs below DISPATCH_LEVEL, and the system's thread scheduler itself (also called "the dispatcher") runs at IRQL=DISPATCH_LEVEL. Consequently, a thread that is running at or above DISPATCH_LEVEL has, in effect, exclusive use of the current processor. Because DISPATCH_LEVEL interrupts are masked off on the processor, the thread scheduler cannot run on that processor, and thus cannot schedule any other thread.

    On a multiprocessor system, each processor can be running at a different IRQL. Therefore, one processor could run a driver's InterruptService routine at DIRQL, while a second processor runs driver code in a worker thread at PASSIVE_LEVEL. Because more than one thread could thus attempt to access shared data simultaneously, drivers must protect shared data by using an appropriate synchronization method. Drivers should use a lock that raises the IRQL to the highest level at which any code that accesses the data can run. For example, a driver uses a spin lock to protect data that can be accessed at IRQL=DISPATCH_LEVEL. For more information about synchronization mechanisms, see Locks, Deadlocks, and Synchronization.

    On a single-processor system, raising the IRQL to DISPATCH_LEVEL or higher has the same effect as using a spin lock, because raising the IRQL can prevent the pre-emption or interruption of the currently executing code. For example, when a driver's StartIo routine is running at DISPATCH_LEVEL on a single-processor system, other driver code that runs at APC_LEVEL or PASSIVE_LEVEL cannot run until the IRQL drops. Similarly, when a driver's InterruptService routine is running at DIRQL, the DPC queued by that routine cannot run until the InterruptService routine exits. In fact, the operating system's spin lock acquisition and release routines raise the IRQL on single-processor systems; they do not actually manipulate a lock object. On multiprocessor machines, however, spin lock acquisition routines raise the IRQL on the current processor while other processors spin on the lock.

    так при каком уровне IRQL всетаки происходит переключение контектста/потоков при APC_LEVEL или при PASSIVE_LEVEL?
     
  7. Zufyxe

    Zufyxe New Member

    Публикаций:
    0
    Регистрация:
    13 авг 2004
    Сообщения:
    137
    Адрес:
    Russia
    Контекст нити может быть переключен только при PASSIVE_LEVEL.
    Все DPC, APC и прерывания выполняются в контексте той нити которой повезло :)
    Той, в чьем контексте были вызваны KiRetireDpcList, или KiDeliverApc, или произошло прерывание и т.п.
    Функции dispatcher-а "поднимают" IRQL до SYNCH_LEVEL, где и работают.
     
  8. er1ss

    er1ss New Member

    Публикаций:
    0
    Регистрация:
    22 июл 2008
    Сообщения:
    8
    Т.е. если я вызову KeWaitForSingleobject с ненулевым таймаутом при IRQL == APC_LEVEL то система не скажет свое ФЭ и поток не переключит, а будет выполнять все отложенные DPC и APC если они есть, а потом вернет управление в то место откуда была вызвана KeWaitForSingleobject по истечении таймаута или установки события.

    Кстати а будут ли при этом вызваны функции завершения IRP IoCompltionRoutine если они вызываются при IRQL = DISPATCH_LEVEL?
     
  9. er1ss

    er1ss New Member

    Публикаций:
    0
    Регистрация:
    22 июл 2008
    Сообщения:
    8
    Т.е. если я вызову KeWaitForSingleobject с ненулевым таймаутом при IRQL == APC_LEVEL то система не скажет свое ФЭ и поток не переключит, а будет выполнять все отложенные DPC и APC если они есть, а потом вернет управление в то место откуда была вызвана KeWaitForSingleobject по истечении таймаута или установки события.

    Кстати а будут ли при этом вызваны функции завершения IRP IoCompltionRoutine если они вызываются при IRQL = DISPATCH_LEVEL?